mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
Audit changes and fixes
- Removed notion of audit session - Removed 'scope' attribute for DataGenerator elements - Removed alf_audit_session table and replaced with alf_audit_app (see script) - DataGenerators are working properly git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16053 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -79,7 +79,6 @@
|
||||
<xs:complexContent>
|
||||
<xs:extension base="a:KeyedAuditDefinition">
|
||||
<xs:attribute name="dataGenerator" type="a:NameAttribute" use="required" />
|
||||
<xs:attribute name="scope" type="a:ScopeAttribute" use="required" />
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
@@ -114,12 +113,4 @@
|
||||
</xs:restriction>
|
||||
</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>
|
@@ -22,7 +22,7 @@
|
||||
|
||||
<Application name="Alfresco Repository" key="repository">
|
||||
<AuditPath key="services">
|
||||
<GenerateValue key="txn" dataGenerator="transactionId" scope="AUDIT"/>
|
||||
<GenerateValue key="txn" dataGenerator="transactionId"/>
|
||||
<AuditPath key="nodeservice">
|
||||
<AuditPath key="createstore">
|
||||
<AuditPath key="protocol">
|
||||
|
@@ -17,24 +17,24 @@ CREATE TABLE alf_audit_model
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE alf_audit_session
|
||||
CREATE TABLE alf_audit_app
|
||||
(
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
audit_model_id BIGINT NOT NULL,
|
||||
app_name_id BIGINT NOT NULL,
|
||||
CONSTRAINT fk_alf_audit_sess_model FOREIGN KEY (audit_model_id) REFERENCES alf_audit_model (id),
|
||||
CONSTRAINT fk_alf_audit_sess_app FOREIGN KEY (app_name_id) REFERENCES alf_prop_value (id),
|
||||
CONSTRAINT fk_alf_audit_app_model FOREIGN KEY (audit_model_id) REFERENCES alf_audit_model (id) ON DELETE CASCADE,
|
||||
CONSTRAINT fk_alf_audit_app_app FOREIGN KEY (app_name_id) REFERENCES alf_prop_value (id),
|
||||
PRIMARY KEY (id)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE alf_audit_entry
|
||||
(
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
audit_session_id BIGINT NOT NULL,
|
||||
audit_app_id BIGINT NOT NULL,
|
||||
audit_time BIGINT NOT NULL,
|
||||
audit_user_id BIGINT NULL,
|
||||
audit_values_id BIGINT NULL,
|
||||
CONSTRAINT fk_alf_audit_ent_sess FOREIGN KEY (audit_session_id) REFERENCES alf_audit_session (id),
|
||||
CONSTRAINT fk_alf_audit_ent_app FOREIGN KEY (audit_app_id) REFERENCES alf_audit_app (id) ON DELETE CASCADE,
|
||||
INDEX idx_alf_audit_ent_time (audit_time),
|
||||
CONSTRAINT fk_alf_audit_ent_user FOREIGN KEY (audit_user_id) REFERENCES alf_prop_value (id),
|
||||
CONSTRAINT fk_alf_audit_ent_prop FOREIGN KEY (audit_values_id) REFERENCES alf_prop_value (id),
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<!-- -->
|
||||
|
||||
<typeAlias alias="AuditModel" type="org.alfresco.repo.domain.audit.AuditModelEntity"/>
|
||||
<typeAlias alias="AuditSession" type="org.alfresco.repo.domain.audit.AuditSessionEntity"/>
|
||||
<typeAlias alias="AuditApplication" type="org.alfresco.repo.domain.audit.AuditApplicationEntity"/>
|
||||
<typeAlias alias="AuditEntry" type="org.alfresco.repo.domain.audit.AuditEntryEntity"/>
|
||||
|
||||
<!-- -->
|
||||
@@ -23,14 +23,14 @@
|
||||
<result property="contentDataId" column="content_data_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="contentCrc" column="content_crc" jdbcType="BIGINT" javaType="long"/>
|
||||
</resultMap>
|
||||
<resultMap id="result.AuditSession" class="AuditSession">
|
||||
<resultMap id="result.AuditApplication" class="AuditApplication">
|
||||
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="auditModelId" column="audit_model_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="applicationNameId" column="app_name_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</resultMap>
|
||||
<resultMap id="result.AuditEntry" class="AuditEntry">
|
||||
<result property="id" column="id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="auditSessionId" column="audit_session_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="auditApplicationId" column="audit_app_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="auditUserId" column="audit_user_id" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="auditTime" column="audit_time" jdbcType="BIGINT" javaType="long"/>
|
||||
<result property="auditValuesId" column="audit_values_id" jdbcType="BIGINT" javaType="long"/>
|
||||
@@ -53,14 +53,14 @@
|
||||
values (#contentDataId#, #contentCrc#)
|
||||
</sql>
|
||||
|
||||
<sql id="insert.AuditSession.AutoIncrement">
|
||||
insert into alf_audit_session (audit_model_id, app_name_id)
|
||||
<sql id="insert.AuditApplication.AutoIncrement">
|
||||
insert into alf_audit_app (audit_model_id, app_name_id)
|
||||
values (#auditModelId#, #applicationNameId#)
|
||||
</sql>
|
||||
|
||||
<sql id="insert.AuditEntry.AutoIncrement">
|
||||
insert into alf_audit_entry (audit_session_id, audit_user_id, audit_time, audit_values_id)
|
||||
values (#auditSessionId#, #auditUserId#, #auditTime#, #auditValuesId#)
|
||||
insert into alf_audit_entry (audit_app_id, audit_user_id, audit_time, audit_values_id)
|
||||
values (#auditApplicationId#, #auditUserId#, #auditTime#, #auditValuesId#)
|
||||
</sql>
|
||||
|
||||
<!-- -->
|
||||
@@ -77,4 +77,14 @@
|
||||
content_crc = #contentCrc#
|
||||
</select>
|
||||
|
||||
<!-- Get the audit application by model ID -->
|
||||
<select id="select.AuditApplicationByModelId" parameterMap="parameter.IdMap" resultMap="result.AuditApplication">
|
||||
select
|
||||
*
|
||||
from
|
||||
alf_audit_app
|
||||
where
|
||||
audit_model_id = ?
|
||||
</select>
|
||||
|
||||
</sqlMap>
|
@@ -13,8 +13,8 @@
|
||||
</selectKey>
|
||||
</insert>
|
||||
|
||||
<insert id="insert.AuditSession" parameterClass="AuditSession" >
|
||||
<include refid="insert.AuditSession.AutoIncrement"/>
|
||||
<insert id="insert.AuditApplication" parameterClass="AuditApplication" >
|
||||
<include refid="insert.AuditApplication.AutoIncrement"/>
|
||||
<selectKey resultClass="long" keyProperty="id" type="post">
|
||||
KEY_COLUMN:GENERATED_KEY
|
||||
</selectKey>
|
||||
|
@@ -31,7 +31,6 @@ 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;
|
||||
@@ -110,7 +109,7 @@ public class AuditBootstrapTest extends TestCase
|
||||
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-04.xml");
|
||||
}
|
||||
|
||||
public void testModelLoading_InvalidScope() throws Exception
|
||||
public void testModelLoading_InvalidDataGeneratorName() throws Exception
|
||||
{
|
||||
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-05.xml");
|
||||
}
|
||||
@@ -120,10 +119,10 @@ public class AuditBootstrapTest extends TestCase
|
||||
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-06.xml");
|
||||
}
|
||||
|
||||
public void testGetModelId()
|
||||
public void testGetApplicationId()
|
||||
{
|
||||
Long repoId = auditModelRegistry.getAuditModelId(APPLICATION_TEST);
|
||||
assertNotNull("No audit model ID for " + APPLICATION_TEST, repoId);
|
||||
Long appId = auditModelRegistry.getAuditApplicationId(APPLICATION_TEST);
|
||||
assertNotNull("No audit application ID for " + APPLICATION_TEST, appId);
|
||||
}
|
||||
|
||||
private void testBadPath(AuditApplication app, String path)
|
||||
@@ -162,32 +161,32 @@ public class AuditBootstrapTest extends TestCase
|
||||
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"));
|
||||
assertEquals(1, extractors.size());
|
||||
assertTrue(extractors.containsKey("/test/1.1/2.1/3.1/4.1/value.1"));
|
||||
|
||||
extractors = app.getDataExtractors("/test/1.1/2.1/3.1");
|
||||
assertEquals(1, extractors.size());
|
||||
assertTrue(extractors.containsKey("/test/1.1/2.1/3.1/value.1"));
|
||||
}
|
||||
|
||||
public void testAuditApplication_GetDataGenerators_AnyScope()
|
||||
public void testAuditApplication_GetDataGenerators()
|
||||
{
|
||||
AuditApplication app = auditModelRegistry.getAuditApplication(APPLICATION_TEST);
|
||||
assertNotNull(app);
|
||||
|
||||
Map<String, DataGenerator> generators = app.getDataGenerators("/blah", DataGeneratorScope.ALL);
|
||||
Map<String, DataGenerator> generators = app.getDataGenerators("/blah");
|
||||
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);
|
||||
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1");
|
||||
assertEquals(1, generators.size());
|
||||
assertTrue(generators.containsKey("/test/time"));
|
||||
|
||||
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1", DataGeneratorScope.SESSION);
|
||||
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1");
|
||||
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);
|
||||
generators = app.getDataGenerators("/test/1.1/2.2/3.2/4.1");
|
||||
assertEquals(2, generators.size());
|
||||
assertTrue(generators.containsKey("/test/time"));
|
||||
assertTrue(generators.containsKey("/test/1.1/2.2/3.2/4.1/time"));
|
||||
|
@@ -83,38 +83,6 @@ public interface AuditComponent
|
||||
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Start an audit session for the given root path. All later audit values must start with
|
||||
* the same root path.
|
||||
* <p/>
|
||||
* The name of the application controls part of the audit model will be used. The root path must
|
||||
* start with the path separator '/' ({@link AuditApplication#AUDIT_PATH_SEPARATOR}) and the matching
|
||||
* <b>key</b> attribute that was declared for the <b>Application</b> element in the audit configuration.
|
||||
* <p/>
|
||||
* This is a read-write method. Client code must wrap calls in the appropriate transactional wrappers.
|
||||
*
|
||||
* @param applicationName the name of the application to log against
|
||||
* @param rootPath a base path of {@link AuditPath} key entries concatenated with
|
||||
* {@link AuditApplication#AUDIT_PATH_SEPARATOR}.
|
||||
* @return Returns the unique session or <tt>null</tt> if no session was created
|
||||
* @throws IllegalStateException if there is not a writable transaction present
|
||||
*/
|
||||
AuditSession startAuditSession(String applicationName, String rootPath);
|
||||
|
||||
/**
|
||||
* {@inheritDoc AuditComponent#startAuditSession(String, String)}
|
||||
|
||||
* @param applicationName the name of the application to log against
|
||||
* @param rootPath a base path of {@link AuditPath} key entries concatenated with the path separator
|
||||
* '/' ({@link AuditApplication#AUDIT_PATH_SEPARATOR})
|
||||
* @param values values to associate with the session. These values will override or
|
||||
* complement generated session-specific values
|
||||
* @param rootPath a base path of {@link AuditPath} key entries concatenated with
|
||||
* {@link AuditApplication#AUDIT_PATH_SEPARATOR}.
|
||||
* @throws IllegalStateException if there is not a writable transaction present
|
||||
*/
|
||||
AuditSession startAuditSession(String applicationName, String rootPath, Map<String, Serializable> values);
|
||||
|
||||
/**
|
||||
* Record a set of values against the given session. The map is a path - starting with '/'
|
||||
* ({@link AuditApplication#AUDIT_PATH_SEPARATOR}), relative to the root path given when
|
||||
@@ -126,9 +94,11 @@ public interface AuditComponent
|
||||
* <p/>
|
||||
* This is a read-write method. Client code must wrap calls in the appropriate transactional wrappers.
|
||||
*
|
||||
* @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
|
||||
* root path
|
||||
* @param applicationName the name of the application to log against
|
||||
* @param rootPath a base path of {@link AuditPath} key entries concatenated with the path separator
|
||||
* '/' ({@link AuditApplication#AUDIT_PATH_SEPARATOR})
|
||||
* @param values the values to audit mapped by {@link AuditPath} key relative to root path
|
||||
* (may be <tt>null</tt>)
|
||||
* @return Returns the values that were actually persisted, keyed by their full path.
|
||||
* @throws IllegalStateException if there is not a writable transaction present
|
||||
*
|
||||
@@ -136,5 +106,5 @@ public interface AuditComponent
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
Map<String, Serializable> audit(AuditSession session, Map<String, Serializable> values);
|
||||
Map<String, Serializable> audit(String applicationName, String rootPath, Map<String, Serializable> values);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -35,7 +36,6 @@ import java.util.Map;
|
||||
|
||||
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.AuditEntry;
|
||||
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
||||
@@ -767,27 +767,25 @@ public class AuditComponentImpl implements AuditComponent
|
||||
this.auditModelRegistry = auditModelRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #startAuditSession(String, String, Map)
|
||||
* @since 3.2
|
||||
*/
|
||||
public AuditSession startAuditSession(String applicationName, String rootPath)
|
||||
{
|
||||
return startAuditSession(applicationName, rootPath, new HashMap<String, Serializable>(11));
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 3.2
|
||||
*/
|
||||
public AuditSession startAuditSession(String applicationName, String rootPath, Map<String, Serializable> values)
|
||||
public Map<String, Serializable> audit(String applicationName, String rootPath, Map<String, Serializable> values)
|
||||
{
|
||||
ParameterCheck.mandatory("applicationName", applicationName);
|
||||
ParameterCheck.mandatory("values", values);
|
||||
ParameterCheck.mandatory("rootPath", rootPath);
|
||||
|
||||
if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_READ_WRITE)
|
||||
{
|
||||
throw new IllegalStateException("Auditing requires a read-write transaction.");
|
||||
}
|
||||
|
||||
if (values == null)
|
||||
{
|
||||
values = Collections.emptyMap();
|
||||
}
|
||||
|
||||
// Get the application
|
||||
AuditApplication application = auditModelRegistry.getAuditApplication(applicationName);
|
||||
if (application == null)
|
||||
@@ -796,60 +794,18 @@ public class AuditComponentImpl implements AuditComponent
|
||||
{
|
||||
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
||||
}
|
||||
return null;
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
// Check the path against the application
|
||||
application.checkPath(rootPath);
|
||||
// Get the model ID for the application
|
||||
Long modelId = auditModelRegistry.getAuditModelId(applicationName);
|
||||
if (modelId == null)
|
||||
Long applicationId = auditModelRegistry.getAuditApplicationId(applicationName);
|
||||
if (applicationId == null)
|
||||
{
|
||||
throw new AuditException("No model exists for audit application: " + applicationName);
|
||||
throw new AuditException("No persisted instance exists for audit application: " + applicationName);
|
||||
}
|
||||
|
||||
// Now create the session
|
||||
Long sessionId = auditDAO.createAuditSession(modelId, applicationName);
|
||||
AuditSession session = new AuditSession(application, rootPath, sessionId);
|
||||
|
||||
// Generate session data
|
||||
Map<String, DataGenerator> generators = application.getDataGenerators(rootPath, DataGeneratorScope.SESSION);
|
||||
Map<String, Serializable> sessionData = generateData(generators);
|
||||
|
||||
// Extract data from the values passed in
|
||||
Map<String, Serializable> extractedData = extractData(application, values);
|
||||
|
||||
// Combine the values
|
||||
Map<String, Serializable> allData = new HashMap<String, Serializable>(sessionData);
|
||||
allData.putAll(extractedData);
|
||||
|
||||
// Audit it
|
||||
audit(session, allData);
|
||||
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("New audit session: " + session);
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 3.2
|
||||
*/
|
||||
public Map<String, Serializable> audit(AuditSession session, Map<String, Serializable> values)
|
||||
{
|
||||
ParameterCheck.mandatory("session", session);
|
||||
ParameterCheck.mandatory("values", values);
|
||||
|
||||
if (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_READ_WRITE)
|
||||
{
|
||||
throw new IllegalStateException("Auditing requires a read-write transaction.");
|
||||
}
|
||||
|
||||
AuditApplication app = session.getApplication();
|
||||
String rootPath = session.getRootPath();
|
||||
Long sessionId = session.getSessionId();
|
||||
// TODO: Check if the root path is enabled or not
|
||||
|
||||
// Build the key paths using the session root path
|
||||
Map<String, Serializable> pathedValues = new HashMap<String, Serializable>(values.size() * 2);
|
||||
@@ -860,27 +816,38 @@ public class AuditComponentImpl implements AuditComponent
|
||||
pathedValues.put(path, entry.getValue());
|
||||
}
|
||||
|
||||
// Generate data
|
||||
Map<String, DataGenerator> generators = application.getDataGenerators(pathedValues.keySet());
|
||||
Map<String, Serializable> auditData = generateData(generators);
|
||||
|
||||
// Now extract values
|
||||
Map<String, Serializable> extractedValues = extractData(app, pathedValues);
|
||||
Map<String, Serializable> extractedData = extractData(application, pathedValues);
|
||||
|
||||
// Combine extracted and generated values (extracted data takes precedence)
|
||||
auditData.putAll(extractedData);
|
||||
|
||||
// Time and username are intrinsic
|
||||
long time = System.currentTimeMillis();
|
||||
String username = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
|
||||
Long entryId = null;
|
||||
if (!auditData.isEmpty())
|
||||
{
|
||||
// Persist the values
|
||||
Long entryId = auditDAO.createAuditEntry(sessionId, time, username, pathedValues);
|
||||
entryId = auditDAO.createAuditEntry(applicationId, time, username, auditData);
|
||||
}
|
||||
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(
|
||||
"New audit entry: \n" +
|
||||
" Session ID: " + sessionId + "\n" +
|
||||
" Applicatoin ID: " + applicationId + "\n" +
|
||||
" Entry ID: " + entryId + "\n" +
|
||||
" Path Values: " + pathedValues + "\n" +
|
||||
" Extracted Values: " + extractedValues);
|
||||
" Audit Data: " + auditData);
|
||||
}
|
||||
return extractedValues;
|
||||
return auditData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -110,11 +110,11 @@ public class AuditComponentTest extends TestCase
|
||||
// Just here to fail if the basic startup fails
|
||||
}
|
||||
|
||||
public void testStartSessionWithBadPath() throws Exception
|
||||
public void testAuditWithBadPath() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
auditComponent.startAuditSession(APPLICATION_TEST, "test");
|
||||
auditComponent.audit(APPLICATION_TEST, "/test", null);
|
||||
fail("Should fail due to lack of a transaction.");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
@@ -127,7 +127,7 @@ public class AuditComponentTest extends TestCase
|
||||
{
|
||||
try
|
||||
{
|
||||
auditComponent.startAuditSession(APPLICATION_TEST, "test");
|
||||
auditComponent.audit(APPLICATION_TEST, "test", null);
|
||||
fail("Failed to detect illegal path");
|
||||
}
|
||||
catch (AuditModelException e)
|
||||
@@ -136,18 +136,16 @@ public class AuditComponentTest extends TestCase
|
||||
}
|
||||
try
|
||||
{
|
||||
auditComponent.startAuditSession(APPLICATION_TEST, "/test/");
|
||||
auditComponent.audit(APPLICATION_TEST, "/test/", null);
|
||||
fail("Failed to detect illegal path");
|
||||
}
|
||||
catch (AuditModelException e)
|
||||
{
|
||||
// Expected
|
||||
}
|
||||
AuditSession session;
|
||||
session = auditComponent.startAuditSession("Bogus App", "/test");
|
||||
assertNull("Invalid app should return null session.", session);
|
||||
session = auditComponent.startAuditSession(APPLICATION_TEST, "/test");
|
||||
assertNotNull("Valid app and root path failed to create session.", session);
|
||||
Map<String, Serializable> auditedValues = auditComponent.audit("Bogus App", "/test", null);
|
||||
assertNotNull(auditedValues);
|
||||
assertTrue("Invalid application should not audit anything", auditedValues.isEmpty());
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -158,20 +156,18 @@ public class AuditComponentTest extends TestCase
|
||||
/**
|
||||
* Start a session and use it within a single txn
|
||||
*/
|
||||
public void testSession_Basic() throws Exception
|
||||
public void testAudit_Basic() 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);
|
||||
auditComponent.audit(APPLICATION_TEST, "/test/1.1", values);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -198,7 +194,7 @@ public class AuditComponentTest extends TestCase
|
||||
for (Map.Entry<String, Serializable> entry : parameters.entrySet())
|
||||
{
|
||||
String paramName = entry.getKey();
|
||||
String path = AuditApplication.buildPath("params", paramName);
|
||||
String path = AuditApplication.buildPath(action, "params", paramName);
|
||||
adjustedValues.put(path, entry.getValue());
|
||||
}
|
||||
|
||||
@@ -207,10 +203,9 @@ public class AuditComponentTest extends TestCase
|
||||
{
|
||||
public Map<String, Serializable> execute() throws Throwable
|
||||
{
|
||||
String actionPath = AuditApplication.buildPath("actions-test/actions", action);
|
||||
AuditSession session = auditComponent.startAuditSession(APPLICATION_ACTIONS_TEST, actionPath);
|
||||
String actionPath = AuditApplication.buildPath("actions-test/actions");
|
||||
|
||||
return auditComponent.audit(session, adjustedValues);
|
||||
return auditComponent.audit(APPLICATION_ACTIONS_TEST, actionPath, adjustedValues);
|
||||
}
|
||||
};
|
||||
return transactionService.getRetryingTransactionHelper().doInTransaction(auditCallback);
|
||||
@@ -279,7 +274,8 @@ public class AuditComponentTest extends TestCase
|
||||
Map<String, Serializable> result = auditTestAction("action-01", nodeRef, parameters);
|
||||
|
||||
Map<String, Serializable> expected = new HashMap<String, Serializable>();
|
||||
expected.put("/actions-test/actions/action-01/context-node/noderef", nodeRef);
|
||||
expected.put("/actions-test/actions/user", AuthenticationUtil.getFullyAuthenticatedUser());
|
||||
expected.put("/actions-test/actions/context-node/noderef", nodeRef);
|
||||
expected.put("/actions-test/actions/action-01/params/A/value", valueA);
|
||||
expected.put("/actions-test/actions/action-01/params/B/value", valueB);
|
||||
expected.put("/actions-test/actions/action-01/params/C/value", valueC);
|
||||
|
93
source/java/org/alfresco/repo/audit/AuditEntry.java
Normal file
93
source/java/org/alfresco/repo/audit/AuditEntry.java
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* Bean to hold audit entry data. An audit entry represents a single audit call, but the
|
||||
* data stored may be a large map.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuditEntry
|
||||
{
|
||||
private final String user;
|
||||
private final long time;
|
||||
private final Long valuesId;
|
||||
private final Map<String, Serializable> values;
|
||||
|
||||
/**
|
||||
* TODO: Comment
|
||||
*/
|
||||
public AuditEntry(String user, long time, Long valuesId, Map<String, Serializable> values)
|
||||
{
|
||||
ParameterCheck.mandatoryString("user", user);
|
||||
ParameterCheck.mandatory("time", time);
|
||||
|
||||
this.user = user;
|
||||
this.time = time;
|
||||
this.valuesId = valuesId;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("AuditEntry")
|
||||
.append("[ user=").append(user)
|
||||
.append(", time=").append(new Date(time))
|
||||
.append(", valuesId=").append(valuesId)
|
||||
.append(", values=").append(values)
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getUser()
|
||||
{
|
||||
return user;
|
||||
}
|
||||
|
||||
public long getTime()
|
||||
{
|
||||
return time;
|
||||
}
|
||||
|
||||
public Long getValuesId()
|
||||
{
|
||||
return valuesId;
|
||||
}
|
||||
|
||||
public Map<String, Serializable> getValues()
|
||||
{
|
||||
return values;
|
||||
}
|
||||
}
|
@@ -122,4 +122,16 @@ public class AuditServiceImpl implements AuditService
|
||||
tx.commit();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void auditQuery(AuditQueryCallback callback, String auditPath, String user, long from, long to, int limit)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.alfresco.repo.audit.model.AuditApplication;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
|
||||
/**
|
||||
* Bean to hold session information for repeated use.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuditSession
|
||||
{
|
||||
private final AuditApplication application;
|
||||
private final String rootPath;
|
||||
private final Long sessionId;
|
||||
|
||||
/**
|
||||
* @param application the audit application config being used
|
||||
* @param rootPath the root path being used for the session
|
||||
* @param sessionId the ID produced for the persisted session
|
||||
*/
|
||||
public AuditSession(AuditApplication application, String rootPath, Long sessionId)
|
||||
{
|
||||
ParameterCheck.mandatory("application", application);
|
||||
ParameterCheck.mandatoryString("rootPath", rootPath);
|
||||
ParameterCheck.mandatory("sessionId", sessionId);
|
||||
|
||||
this.application = application;
|
||||
this.rootPath = rootPath;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return (application.hashCode() + rootPath.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (obj instanceof AuditSession)
|
||||
{
|
||||
AuditSession that = (AuditSession) obj;
|
||||
return this.application.equals(that.application) &&
|
||||
this.rootPath.equals(that.rootPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("AuditSession")
|
||||
.append("[ application=").append(application)
|
||||
.append(", rootPath=").append(rootPath)
|
||||
.append(", sessionId=").append(sessionId)
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public AuditApplication getApplication()
|
||||
{
|
||||
return application;
|
||||
}
|
||||
|
||||
public String getRootPath()
|
||||
{
|
||||
return rootPath;
|
||||
}
|
||||
|
||||
public Long getSessionId()
|
||||
{
|
||||
return sessionId;
|
||||
}
|
||||
}
|
@@ -38,16 +38,6 @@ import java.io.Serializable;
|
||||
*/
|
||||
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.
|
||||
*
|
||||
|
@@ -140,17 +140,6 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
|
||||
this.localSessionFactory = localSessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallout implementation from new audit DAO
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @since 3.2
|
||||
*/
|
||||
public Long createAuditSession(Long modelId, String application)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallout implementation from new audit DAO
|
||||
*
|
||||
@@ -168,7 +157,18 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
|
||||
* @throws UnsupportedOperationException always
|
||||
* @since 3.2
|
||||
*/
|
||||
public Long createAuditEntry(Long sessionId, long time, String username, Map<String, Serializable> values)
|
||||
public Long getOrCreateAuditApplication(Long modelId, String applicationName)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallout implementation from new audit DAO
|
||||
*
|
||||
* @throws UnsupportedOperationException always
|
||||
* @since 3.2
|
||||
*/
|
||||
public Long createAuditEntry(Long applicationId, long time, String username, Map<String, Serializable> values)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
@@ -27,18 +27,15 @@ 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;
|
||||
|
||||
@@ -70,8 +67,6 @@ public class AuditApplication
|
||||
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
|
||||
@@ -251,43 +246,29 @@ public class AuditApplication
|
||||
* 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)
|
||||
public Map<String, DataGenerator> getDataGenerators(String path)
|
||||
{
|
||||
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);
|
||||
return getDataGenerators(Collections.singleton(path));
|
||||
}
|
||||
|
||||
if (scope != DataGeneratorScope.ALL)
|
||||
/**
|
||||
* Get all data generators applicable to a given path and scope.
|
||||
*
|
||||
* @param paths the audit paths
|
||||
* @return Returns all data generators mapped to their key-path
|
||||
*/
|
||||
public Map<String, DataGenerator> getDataGenerators(Set<String> paths)
|
||||
{
|
||||
// Go through them and eliminate the ones in the wrong scope
|
||||
Iterator<Map.Entry<String, DataGenerator>> iterator = generators.entrySet().iterator();
|
||||
while (iterator.hasNext())
|
||||
Map<String, DataGenerator> amalgamatedGenerators = new HashMap<String, DataGenerator>(13);
|
||||
for (String path : paths)
|
||||
{
|
||||
Map.Entry<String, DataGenerator> entry = iterator.next();
|
||||
String generatorPath = entry.getKey();
|
||||
DataGeneratorScope generatorScope = dataGeneratorScopes.get(generatorPath);
|
||||
if (generatorScope == DataGeneratorScope.ALL)
|
||||
Map<String, DataGenerator> generators = dataGenerators.get(path);
|
||||
if (generators != null)
|
||||
{
|
||||
// This one always applies
|
||||
continue;
|
||||
}
|
||||
else if (generatorScope != scope)
|
||||
{
|
||||
// Wrong scope
|
||||
iterator.remove();
|
||||
}
|
||||
// Copy values to combined map
|
||||
amalgamatedGenerators.putAll(generators);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,11 +277,10 @@ public class AuditApplication
|
||||
{
|
||||
logger.debug(
|
||||
"Looked up data generators: \n" +
|
||||
" Path: " + path + "\n" +
|
||||
" Scope: " + scope + "\n" +
|
||||
" Found: " + generators);
|
||||
" Paths: " + paths + "\n" +
|
||||
" Found: " + amalgamatedGenerators);
|
||||
}
|
||||
return generators;
|
||||
return amalgamatedGenerators;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,11 +345,11 @@ public class AuditApplication
|
||||
}
|
||||
// All the extractors apply to the current path
|
||||
dataExtractors.put(currentPath, upperExtractorsByPath);
|
||||
// // Data extractors only apply directly to data in which they appear.
|
||||
// // TODO: Examine this assumption. If it is not true, i.e. data extractors apply to
|
||||
// // data anywhere down the hierarchy, then the followin line of code should be
|
||||
// // removed and the use-cases tested appropriately.
|
||||
// upperExtractorsByPath.clear();
|
||||
// Data extractors only apply directly to data in which they appear.
|
||||
// TODO: Examine this assumption. If it is not true, i.e. data extractors apply to
|
||||
// data anywhere down the hierarchy, then the followin line of code should be
|
||||
// removed and the use-cases tested appropriately.
|
||||
upperExtractorsByPath = new HashMap<String, DataExtractor>();
|
||||
|
||||
// Get the data generators declared for this key
|
||||
for (GenerateValue element : auditPath.getGenerateValue())
|
||||
@@ -387,26 +367,6 @@ public class AuditApplication
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
@@ -96,9 +96,9 @@ public class AuditModelRegistry
|
||||
*/
|
||||
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 application
|
||||
*/
|
||||
private final Map<String, Long> auditModelIdsByApplicationsName;
|
||||
private final Map<String, Long> auditApplicationIdsByApplicationsName;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
@@ -114,7 +114,7 @@ public class AuditModelRegistry
|
||||
auditModelUrls = new HashSet<URL>(7);
|
||||
auditModels = new ArrayList<Audit>(7);
|
||||
auditApplicationsByName = new HashMap<String, AuditApplication>(7);
|
||||
auditModelIdsByApplicationsName = new HashMap<String, Long>(7);
|
||||
auditApplicationIdsByApplicationsName = new HashMap<String, Long>(7);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,7 +209,7 @@ public class AuditModelRegistry
|
||||
{
|
||||
auditModels.clear();
|
||||
auditApplicationsByName.clear();
|
||||
auditModelIdsByApplicationsName.clear();
|
||||
auditApplicationIdsByApplicationsName.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,17 +271,17 @@ public class AuditModelRegistry
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of the persisted audit model for the given application name
|
||||
* Get the ID of the persisted audit application for the given application name
|
||||
*
|
||||
* @param applicationName the name of the audited application
|
||||
* @return the unique ID of the persisted model (<tt>null</tt> if not found)
|
||||
* @return the unique ID of the persisted application (<tt>null</tt> if not found)
|
||||
*/
|
||||
public Long getAuditModelId(String applicationName)
|
||||
public Long getAuditApplicationId(String applicationName)
|
||||
{
|
||||
readLock.lock();
|
||||
try
|
||||
{
|
||||
return auditModelIdsByApplicationsName.get(applicationName);
|
||||
return auditApplicationIdsByApplicationsName.get(applicationName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -514,9 +514,13 @@ public class AuditModelRegistry
|
||||
{
|
||||
throw new AuditModelException("Audit application '" + name + "' has already been defined.");
|
||||
}
|
||||
|
||||
// Get the ID of the application
|
||||
Long appId = auditDAO.getOrCreateAuditApplication(auditModelId, name);
|
||||
|
||||
AuditApplication wrapperApp = new AuditApplication(dataExtractorsByName, dataGeneratorsByName, application);
|
||||
auditApplicationsByName.put(name, wrapperApp);
|
||||
auditModelIdsByApplicationsName.put(name, auditModelId);
|
||||
auditApplicationIdsByApplicationsName.put(name, appId);
|
||||
}
|
||||
// Store the model itself
|
||||
auditModels.add(audit);
|
||||
|
@@ -17,7 +17,6 @@ import javax.xml.bind.annotation.XmlType;
|
||||
* <complexContent>
|
||||
* <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="scope" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}ScopeAttribute" />
|
||||
* </extension>
|
||||
* </complexContent>
|
||||
* </complexType>
|
||||
@@ -33,8 +32,6 @@ public class GenerateValue
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
protected String dataGenerator;
|
||||
@XmlAttribute(required = true)
|
||||
protected ScopeAttribute scope;
|
||||
|
||||
/**
|
||||
* Gets the value of the dataGenerator property.
|
||||
@@ -60,28 +57,4 @@ public class GenerateValue
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -34,11 +34,11 @@ public class ObjectFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link KeyedAuditDefinition }
|
||||
* Create an instance of {@link RecordValue }
|
||||
*
|
||||
*/
|
||||
public KeyedAuditDefinition createKeyedAuditDefinition() {
|
||||
return new KeyedAuditDefinition();
|
||||
public RecordValue createRecordValue() {
|
||||
return new RecordValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,14 +57,6 @@ public class ObjectFactory {
|
||||
return new Audit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link DataExtractors }
|
||||
*
|
||||
*/
|
||||
public DataExtractors createDataExtractors() {
|
||||
return new DataExtractors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link AuditPath }
|
||||
*
|
||||
@@ -90,11 +82,11 @@ public class ObjectFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link RecordValue }
|
||||
* Create an instance of {@link KeyedAuditDefinition }
|
||||
*
|
||||
*/
|
||||
public RecordValue createRecordValue() {
|
||||
return new RecordValue();
|
||||
public KeyedAuditDefinition createKeyedAuditDefinition() {
|
||||
return new KeyedAuditDefinition();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,6 +105,14 @@ public class ObjectFactory {
|
||||
return new GenerateValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link DataExtractors }
|
||||
*
|
||||
*/
|
||||
public DataExtractors createDataExtractors() {
|
||||
return new DataExtractors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an instance of {@link JAXBElement }{@code <}{@link Audit }{@code >}}
|
||||
*
|
||||
|
@@ -1,40 +0,0 @@
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
@@ -56,7 +56,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
*/
|
||||
public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(AbstractAuditDAOImpl.class);
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private HibernateAuditDAO oldDAO;
|
||||
private ContentService contentService;
|
||||
@@ -83,6 +83,11 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
this.propertyValueDAO = propertyValueDAO;
|
||||
}
|
||||
|
||||
protected PropertyValueDAO getPropertyValueDAO()
|
||||
{
|
||||
return this.propertyValueDAO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Support for older audit DAO
|
||||
*/
|
||||
@@ -196,34 +201,42 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
protected abstract AuditModelEntity createAuditModel(Long contentDataId, long crc);
|
||||
|
||||
/*
|
||||
* alf_audit_session
|
||||
* alf_audit_application
|
||||
*/
|
||||
|
||||
public Long createAuditSession(Long modelId, String application)
|
||||
public Long getOrCreateAuditApplication(Long modelId, String application)
|
||||
{
|
||||
// Search for it
|
||||
AuditApplicationEntity entity = getAuditApplicationByModelIdAndName(modelId, application);
|
||||
if (entity == null)
|
||||
{
|
||||
// Create it
|
||||
// Persist the string
|
||||
Long appNameId = propertyValueDAO.getOrCreatePropertyValue(application).getFirst();
|
||||
// Create the audit session
|
||||
AuditSessionEntity entity = createAuditSession(appNameId, modelId);
|
||||
entity = createAuditApplication(modelId, appNameId);
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(
|
||||
"Created new audit session: \n" +
|
||||
"Created new audit application: \n" +
|
||||
" Model: " + modelId + "\n" +
|
||||
" App: " + application + "\n" +
|
||||
" Result: " + entity);
|
||||
}
|
||||
}
|
||||
// Done
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
protected abstract AuditSessionEntity createAuditSession(Long appNameId, Long modelId);
|
||||
protected abstract AuditApplicationEntity getAuditApplicationByModelIdAndName(Long modelId, String appName);
|
||||
protected abstract AuditApplicationEntity createAuditApplication(Long modelId, Long appNameId);
|
||||
|
||||
/*
|
||||
* alf_audit_entry
|
||||
*/
|
||||
|
||||
public Long createAuditEntry(Long sessionId, long time, String username, Map<String, Serializable> values)
|
||||
public Long createAuditEntry(Long applicationId, long time, String username, Map<String, Serializable> values)
|
||||
{
|
||||
final Long usernameId;
|
||||
if (username != null)
|
||||
@@ -242,14 +255,14 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
}
|
||||
|
||||
// Create the audit entry
|
||||
AuditEntryEntity entity = createAuditEntry(sessionId, time, usernameId, valuesId);
|
||||
AuditEntryEntity entity = createAuditEntry(applicationId, time, usernameId, valuesId);
|
||||
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug(
|
||||
"Created new audit entry: \n" +
|
||||
" Session: " + sessionId + "\n" +
|
||||
" Application: " + applicationId + "\n" +
|
||||
" Time: " + (new Date(time)) + "\n" +
|
||||
" User: " + username + "\n" +
|
||||
" Result: " + entity);
|
||||
@@ -257,5 +270,5 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
protected abstract AuditEntryEntity createAuditEntry(Long sessionId, long time, Long usernameId, Long valuesId);
|
||||
protected abstract AuditEntryEntity createAuditEntry(Long applicationId, long time, Long usernameId, Long valuesId);
|
||||
}
|
||||
|
@@ -25,18 +25,18 @@
|
||||
package org.alfresco.repo.domain.audit;
|
||||
|
||||
/**
|
||||
* Entity bean for <b>alf_audit_session</b> table.
|
||||
* Entity bean for <b>alf_audit_application</b> table.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.2
|
||||
*/
|
||||
public class AuditSessionEntity
|
||||
public class AuditApplicationEntity
|
||||
{
|
||||
private Long id;
|
||||
private Long applicationNameId;
|
||||
private Long auditModelId;
|
||||
private Long applicationNameId;
|
||||
|
||||
public AuditSessionEntity()
|
||||
public AuditApplicationEntity()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ public class AuditSessionEntity
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("AuditSessionEntity")
|
||||
sb.append("AuditApplicationEntity")
|
||||
.append("[ ID=").append(id)
|
||||
.append(", applicationNameId=").append(applicationNameId)
|
||||
.append(", auditModelId=").append(auditModelId)
|
||||
.append(", applicationNameId=").append(applicationNameId)
|
||||
.append("]");
|
||||
return sb.toString();
|
||||
}
|
@@ -75,22 +75,22 @@ public interface AuditDAO
|
||||
Pair<Long, ContentData> getOrCreateAuditModel(URL url);
|
||||
|
||||
/**
|
||||
* Creates a new audit session entry - there is no session re-use.
|
||||
* Creates a new audit application or finds an existing one
|
||||
*
|
||||
* @param modelId an existing audit model ID
|
||||
* @param application the name of the application
|
||||
* @return Returns the unique session ID
|
||||
* @param modelId the ID of the model configuration
|
||||
* @param applicationName the name of the application
|
||||
* @return Returns the ID of the application entry
|
||||
*/
|
||||
Long createAuditSession(Long modelId, String application);
|
||||
Long getOrCreateAuditApplication(Long modelId, String applicationName);
|
||||
|
||||
/**
|
||||
* Create a new audit entry with the given map of values.
|
||||
*
|
||||
* @param sessionId an existing audit session ID
|
||||
* @param applicationId an existing audit application ID
|
||||
* @param time the time (ms since epoch) to log the entry against
|
||||
* @param username the authenticated user (<tt>null</tt> if not present)
|
||||
* @param values the values to record
|
||||
* @return Returns the unique entry ID
|
||||
*/
|
||||
Long createAuditEntry(Long sessionId, long time, String username, Map<String, Serializable> values);
|
||||
Long createAuditEntry(Long applicationId, long time, String username, Map<String, Serializable> values);
|
||||
}
|
@@ -88,7 +88,7 @@ public class AuditDAOTest extends TestCase
|
||||
assertEquals(configPair, configPairCheck);
|
||||
}
|
||||
|
||||
public void testAuditSession() throws Exception
|
||||
public void testAuditApplicatoin() throws Exception
|
||||
{
|
||||
final File file = AbstractContentTransformerTest.loadQuickTestFile("pdf");
|
||||
assertNotNull(file);
|
||||
@@ -104,22 +104,22 @@ public class AuditDAOTest extends TestCase
|
||||
|
||||
final String appName = getName() + "." + System.currentTimeMillis();
|
||||
final int count = 1000;
|
||||
RetryingTransactionCallback<Void> createSessionCallback = new RetryingTransactionCallback<Void>()
|
||||
RetryingTransactionCallback<Void> createAppCallback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
auditDAO.createAuditSession(modelId, appName);
|
||||
auditDAO.getOrCreateAuditApplication(modelId, appName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
long before = System.nanoTime();
|
||||
txnHelper.doInTransaction(createSessionCallback);
|
||||
txnHelper.doInTransaction(createAppCallback);
|
||||
long after = System.nanoTime();
|
||||
System.out.println(
|
||||
"Time for " + count + " session creations was " +
|
||||
"Time for " + count + " application creations was " +
|
||||
((double)(after - before)/(10E6)) + "ms");
|
||||
}
|
||||
|
||||
@@ -130,15 +130,15 @@ public class AuditDAOTest extends TestCase
|
||||
final URL url = new URL("file:" + file.getAbsolutePath());
|
||||
final String appName = getName() + "." + System.currentTimeMillis();
|
||||
|
||||
RetryingTransactionCallback<Long> createSessionCallback = new RetryingTransactionCallback<Long>()
|
||||
RetryingTransactionCallback<Long> createAppCallback = new RetryingTransactionCallback<Long>()
|
||||
{
|
||||
public Long execute() throws Throwable
|
||||
{
|
||||
Long modelId = auditDAO.getOrCreateAuditModel(url).getFirst();
|
||||
return auditDAO.createAuditSession(modelId, appName);
|
||||
return auditDAO.getOrCreateAuditApplication(modelId, appName);
|
||||
}
|
||||
};
|
||||
final Long sessionId = txnHelper.doInTransaction(createSessionCallback);
|
||||
final Long sessionId = txnHelper.doInTransaction(createAppCallback);
|
||||
|
||||
final int count = 1000;
|
||||
final String username = "alexi";
|
||||
|
@@ -35,7 +35,7 @@ import java.util.Date;
|
||||
public class AuditEntryEntity
|
||||
{
|
||||
private Long id;
|
||||
private Long auditSessionId;
|
||||
private Long auditApplicationId;
|
||||
private Long auditUserId;
|
||||
private long auditTime;
|
||||
private Long auditValuesId;
|
||||
@@ -50,7 +50,7 @@ public class AuditEntryEntity
|
||||
StringBuilder sb = new StringBuilder(512);
|
||||
sb.append("AuditEntryEntity")
|
||||
.append("[ ID=").append(id)
|
||||
.append(", auditSessionId=").append(auditSessionId)
|
||||
.append(", auditApplicationId=").append(auditApplicationId)
|
||||
.append(", auditTime").append(new Date(auditTime))
|
||||
.append(", auditValuesId=").append(auditValuesId)
|
||||
.append("]");
|
||||
@@ -67,14 +67,14 @@ public class AuditEntryEntity
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getAuditSessionId()
|
||||
public Long getAuditApplicationId()
|
||||
{
|
||||
return auditSessionId;
|
||||
return auditApplicationId;
|
||||
}
|
||||
|
||||
public void setAuditSessionId(Long auditSessionId)
|
||||
public void setAuditApplicationId(Long auditSessionId)
|
||||
{
|
||||
this.auditSessionId = auditSessionId;
|
||||
this.auditApplicationId = auditSessionId;
|
||||
}
|
||||
|
||||
public Long getAuditUserId()
|
||||
|
@@ -24,10 +24,16 @@
|
||||
*/
|
||||
package org.alfresco.repo.domain.audit.ibatis;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.domain.audit.AbstractAuditDAOImpl;
|
||||
import org.alfresco.repo.domain.audit.AuditApplicationEntity;
|
||||
import org.alfresco.repo.domain.audit.AuditEntryEntity;
|
||||
import org.alfresco.repo.domain.audit.AuditModelEntity;
|
||||
import org.alfresco.repo.domain.audit.AuditSessionEntity;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.springframework.orm.ibatis.SqlMapClientTemplate;
|
||||
|
||||
/**
|
||||
@@ -41,7 +47,8 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
|
||||
private static final String SELECT_MODEL_BY_CRC = "select.AuditModelByCrc";
|
||||
private static final String INSERT_MODEL = "insert.AuditModel";
|
||||
|
||||
private static final String INSERT_SESSION = "insert.AuditSession";
|
||||
private static final String SELECT_APPLICATION_BY_MODEL_ID = "select.AuditApplicationByModelId";
|
||||
private static final String INSERT_APPLICATION = "insert.AuditApplication";
|
||||
|
||||
private static final String INSERT_ENTRY = "insert.AuditEntry";
|
||||
|
||||
@@ -75,22 +82,59 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
|
||||
return entity;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected AuditSessionEntity createAuditSession(Long appNameId, Long modelId)
|
||||
protected AuditApplicationEntity getAuditApplicationByModelIdAndName(Long modelId, String appName)
|
||||
{
|
||||
AuditSessionEntity entity = new AuditSessionEntity();
|
||||
entity.setApplicationNameId(appNameId);
|
||||
Map<String, Object> params = new HashMap<String, Object>(11);
|
||||
params.put("id", modelId);
|
||||
List<AuditApplicationEntity> results = (List<AuditApplicationEntity>) template.queryForList(
|
||||
SELECT_APPLICATION_BY_MODEL_ID,
|
||||
params);
|
||||
// There could be multiple hits for the model ID. Go through them and find the correct app name.
|
||||
AuditApplicationEntity result = null;
|
||||
for (AuditApplicationEntity row : results)
|
||||
{
|
||||
Long appNameId = row.getApplicationNameId();
|
||||
Pair<Long, Serializable> propPair = getPropertyValueDAO().getPropertyValueById(appNameId);
|
||||
if (propPair == null)
|
||||
{
|
||||
// There is a FK to protect against this, but we'll just log it
|
||||
logger.warn("An audit application references a non-existent app_name_id: " + appNameId);
|
||||
}
|
||||
// Check for exact match
|
||||
Serializable propValue = propPair.getSecond();
|
||||
if (propValue instanceof String && propValue.equals(appName))
|
||||
{
|
||||
// Got it
|
||||
result = row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Done
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Searched for audit application with model id " + modelId + " and found: " + result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuditApplicationEntity createAuditApplication(Long modelId, Long appNameId)
|
||||
{
|
||||
AuditApplicationEntity entity = new AuditApplicationEntity();
|
||||
entity.setAuditModelId(modelId);
|
||||
Long id = (Long) template.insert(INSERT_SESSION, entity);
|
||||
entity.setApplicationNameId(appNameId);
|
||||
Long id = (Long) template.insert(INSERT_APPLICATION, entity);
|
||||
entity.setId(id);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AuditEntryEntity createAuditEntry(Long sessionId, long time, Long usernameId, Long valuesId)
|
||||
protected AuditEntryEntity createAuditEntry(Long applicationId, long time, Long usernameId, Long valuesId)
|
||||
{
|
||||
AuditEntryEntity entity = new AuditEntryEntity();
|
||||
entity.setAuditSessionId(sessionId);
|
||||
entity.setAuditApplicationId(applicationId);
|
||||
entity.setAuditTime(time);
|
||||
entity.setAuditUserId(usernameId);
|
||||
entity.setAuditValuesId(valuesId);
|
||||
|
@@ -24,7 +24,9 @@
|
||||
*/
|
||||
package org.alfresco.service.cmr.audit;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.service.NotAuditable;
|
||||
import org.alfresco.service.PublicService;
|
||||
@@ -100,4 +102,62 @@ public interface AuditService
|
||||
*/
|
||||
@NotAuditable
|
||||
public List<AuditInfo> getAuditTrail(NodeRef nodeRef);
|
||||
|
||||
/*
|
||||
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The interface that will be used to give query results to the calling code.
|
||||
* @since 3.2
|
||||
*/
|
||||
public static interface AuditQueryCallback
|
||||
{
|
||||
/**
|
||||
* Check if summary or full data fetching is required. Depending on the return value,
|
||||
* the underlying query may be completely different; it is not possible to change the
|
||||
* return value and expect the callback to be used differently during row handling.
|
||||
*
|
||||
* @return Return <tt>true</tt> if summary data is required only i.e
|
||||
* the full map of audit values for the entries will not be
|
||||
* retrieved.
|
||||
*/
|
||||
boolean isSummaryOnly();
|
||||
|
||||
/**
|
||||
* Handle a summary row of audit entry data. The ID of the full values map is provided.
|
||||
*
|
||||
* @param applicationName the name of the application
|
||||
* @param user the user that logged the entry
|
||||
* @param time the time of the entry
|
||||
* @param valuesId the ID of the values map as created
|
||||
* @return Return <tt>true</tt> to continue processing rows or <tt>false</tt> to stop
|
||||
*/
|
||||
boolean handleAuditEntrySummary(String applicationName, String user, long time, Long valuesId);
|
||||
|
||||
/**
|
||||
* Handle a full row of audit entry data.
|
||||
*
|
||||
* @param applicationName the name of the application
|
||||
* @param user the user that logged the entry
|
||||
* @param time the time of the entry
|
||||
* @param values the values map as created
|
||||
* @return Return <tt>true</tt> to continue processing rows or <tt>false</tt> to stop
|
||||
*/
|
||||
boolean handleAuditEntryFull(String applicationName, String user, long time, Map<String, Serializable> values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the audit entries that match the given criteria.
|
||||
*
|
||||
* @param callback the callback that will handle results
|
||||
* @param auditPath if not <tt>null</tt>, at least one value in the entry must start with this path
|
||||
* @param user if not <tt>null</tt>, the entry must be logged against this user
|
||||
* @param from the start search time (use 0L) to cover all times
|
||||
* @param to the end search time (use Long.MAX_VALUE) to cover all times
|
||||
* @param limit the maximum number of results to retrieve
|
||||
*/
|
||||
void auditQuery(
|
||||
AuditQueryCallback callback,
|
||||
String auditPath, String user, long from, long to, int limit);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<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"/>
|
||||
<GenerateValue key="value.1" dataGenerator="blah"/>
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
</Application>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<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"/>
|
||||
<GenerateValue key="time" dataGenerator="systemTimeAAA"/>
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
</Application>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<Application name="Alfresco Test Bad 06" key="test-bad-06">
|
||||
<AuditPath key="1.1">
|
||||
<AuditPath key="2.1">
|
||||
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSION"/>
|
||||
<GenerateValue key="time" dataGenerator="systemTime"/>
|
||||
</AuditPath>
|
||||
</AuditPath>
|
||||
</Application>
|
||||
|
@@ -20,7 +20,7 @@
|
||||
</DataGenerators>
|
||||
|
||||
<Application name="Alfresco Test" key="test">
|
||||
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSION"/>
|
||||
<GenerateValue key="time" dataGenerator="systemTime"/>
|
||||
<AuditPath key="1.1">
|
||||
<AuditPath key="2.1">
|
||||
<AuditPath key="3.1">
|
||||
@@ -56,7 +56,7 @@
|
||||
<AuditPath key="3.2">
|
||||
<AuditPath key="4.1">
|
||||
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||
<GenerateValue key="time" dataGenerator="systemTime" scope="ALL"/>
|
||||
<GenerateValue key="time" dataGenerator="systemTime"/>
|
||||
</AuditPath>
|
||||
<AuditPath key="4.2">
|
||||
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||
@@ -67,12 +67,12 @@
|
||||
</Application>
|
||||
|
||||
<Application name="Actions Test" key="actions-test">
|
||||
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSION"/>
|
||||
<AuditPath key="actions">
|
||||
<AuditPath key="action-01">
|
||||
<GenerateValue key="user" dataGenerator="user"/>
|
||||
<AuditPath key="context-node">
|
||||
<RecordValue key="noderef" dataExtractor="simpleValue"/>
|
||||
</AuditPath>
|
||||
<AuditPath key="action-01">
|
||||
<AuditPath key="params">
|
||||
<AuditPath key="A">
|
||||
<RecordValue key="value" dataExtractor="simpleValue"/>
|
||||
|
Reference in New Issue
Block a user