diff --git a/config/alfresco/audit-services-context.xml b/config/alfresco/audit-services-context.xml index 9400ad4157..ad13cddd1d 100644 --- a/config/alfresco/audit-services-context.xml +++ b/config/alfresco/audit-services-context.xml @@ -117,16 +117,7 @@ - - - - - - - - org.alfresco.repo.audit.model.AuditModelRegistry - - - + + \ No newline at end of file diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml index 4840cef93a..cb2a6e5bbf 100644 --- a/config/alfresco/bootstrap-context.xml +++ b/config/alfresco/bootstrap-context.xml @@ -552,7 +552,19 @@ - + + + + classpath*:alfresco/audit/*.xml + classpath*:alfresco/enterprise/audit/*.xml + classpath*:alfresco/module/*/audit/*.xml + classpath*:alfresco/extension/audit/*.xml + + + + + + true diff --git a/config/alfresco/repository.properties b/config/alfresco/repository.properties index 4007d58e3d..fd46783da8 100644 --- a/config/alfresco/repository.properties +++ b/config/alfresco/repository.properties @@ -251,7 +251,7 @@ db.pool.abandoned.time=300 # Audit configuration audit.enabled=false audit.repository.enabled=true -audit.cmis.enabled=true +audit.cmischangelog.enabled=true audit.useNewConfig=true # Email configuration diff --git a/config/alfresco/subsystems/Audit/default/audit-registry-context.xml b/config/alfresco/subsystems/Audit/default/audit-registry-context.xml deleted file mode 100644 index 3f3d254eba..0000000000 --- a/config/alfresco/subsystems/Audit/default/audit-registry-context.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - ${audit.enabled} - - - - - - - - - - - - - - - - ${audit.repository.enabled} - - - classpath:alfresco/audit/alfresco-audit-repository.xml - - - - - - - ${audit.cmis.enabled} - - - classpath:alfresco/audit/alfresco-audit-cmis.xml - - - - - \ No newline at end of file diff --git a/config/alfresco/subsystems/Audit/default/audit-registry.properties b/config/alfresco/subsystems/Audit/default/audit-registry.properties deleted file mode 100644 index 61b7ac898a..0000000000 --- a/config/alfresco/subsystems/Audit/default/audit-registry.properties +++ /dev/null @@ -1,3 +0,0 @@ -audit.enabled=false -audit.repository.enabled=true -audit.cmis.enabled=true \ No newline at end of file diff --git a/source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java b/source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java index 9c8ae223db..e5b31d52e9 100755 --- a/source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java +++ b/source/java/org/alfresco/cmis/changelog/CMISChangeLogServiceTest.java @@ -39,7 +39,7 @@ import org.alfresco.cmis.CMISChangeType; import org.alfresco.cmis.mapping.BaseCMISTest; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; -import org.alfresco.repo.management.subsystems.ApplicationContextFactory; +import org.alfresco.repo.audit.model.AuditModelRegistryImpl; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.repository.NodeRef; @@ -76,7 +76,7 @@ public class CMISChangeLogServiceTest extends BaseCMISTest EXPECTED_AMOUNTS.put(CMISChangeType.UPDATED, 6); } - private ApplicationContextFactory auditSubsystem; + private AuditModelRegistryImpl auditSubsystem; private CMISChangeLogService changeLogService; private int actualCount = 0; @@ -88,14 +88,14 @@ public class CMISChangeLogServiceTest extends BaseCMISTest { auditSubsystem.stop(); auditSubsystem.setProperty("audit.enabled", "true"); - auditSubsystem.setProperty("audit.cmis.enabled", "false"); + auditSubsystem.setProperty("audit.cmischangelog.enabled", "false"); } private void enableAudit() { auditSubsystem.stop(); auditSubsystem.setProperty("audit.enabled", "true"); - auditSubsystem.setProperty("audit.cmis.enabled", "true"); + auditSubsystem.setProperty("audit.cmischangelog.enabled", "true"); } /** @@ -407,7 +407,7 @@ public class CMISChangeLogServiceTest extends BaseCMISTest nodeService = (NodeService) applicationContext.getBean("NodeService"); permissionService = (PermissionService) applicationContext.getBean("PermissionService"); fileFolderService = (FileFolderService) applicationContext.getBean("FileFolderService"); - auditSubsystem = (ApplicationContextFactory) applicationContext.getBean("Audit"); + auditSubsystem = (AuditModelRegistryImpl) applicationContext.getBean("Audit"); } @Override @@ -415,5 +415,6 @@ public class CMISChangeLogServiceTest extends BaseCMISTest { deleteTestData(); super.tearDown(); + auditSubsystem.destroy(); } } diff --git a/source/java/org/alfresco/repo/audit/AuditBootstrap.java b/source/java/org/alfresco/repo/audit/AuditBootstrap.java deleted file mode 100644 index d9af9c74dd..0000000000 --- a/source/java/org/alfresco/repo/audit/AuditBootstrap.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2005-2010 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 received 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.AuditModelRegistry; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.transaction.TransactionService; -import org.springframework.extensions.surf.util.AbstractLifecycleBean; -import org.springframework.context.ApplicationEvent; - -/** - * Starts all the necessary audit functionality once the repository has started. - * - * @author Derek Hulley - * @since 3.2 - */ -public class AuditBootstrap extends AbstractLifecycleBean -{ - private TransactionService transactionService; - private AuditModelRegistry auditModelRegistry; - private boolean isActive = true; - - public void setTransactionService(TransactionService transactionService) - { - this.transactionService = transactionService; - } - - public void setAuditModelRegistry(AuditModelRegistry registry) - { - this.auditModelRegistry = registry; - } - - public void setActive(boolean isActive) - { - this.isActive = isActive; - } - - /** - * @see AuditModelRegistry#loadAuditModels() - */ - @Override - protected void onBootstrap(ApplicationEvent event) - { - // Don't bootstrap if the system is read-only - if (transactionService.isReadOnly()) - { - return; - } - - // Don't start if we've been configured out - if (!this.isActive) - { - return; - } - - RetryingTransactionCallback callback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - auditModelRegistry.loadAuditModels(); - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(callback, transactionService.isReadOnly()); - } - - /** - * No-op - */ - @Override - protected void onShutdown(ApplicationEvent event) - { - } -} diff --git a/source/java/org/alfresco/repo/audit/AuditBootstrapTest.java b/source/java/org/alfresco/repo/audit/AuditBootstrapTest.java index 28b9531896..3065b1a03b 100644 --- a/source/java/org/alfresco/repo/audit/AuditBootstrapTest.java +++ b/source/java/org/alfresco/repo/audit/AuditBootstrapTest.java @@ -34,7 +34,6 @@ import org.alfresco.repo.audit.generator.DataGenerator; import org.alfresco.repo.audit.model.AuditApplication; import org.alfresco.repo.audit.model.AuditModelException; import org.alfresco.repo.audit.model.AuditModelRegistryImpl; -import org.alfresco.repo.management.subsystems.ApplicationContextFactory; import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.PathMapper; import org.apache.commons.logging.Log; @@ -63,17 +62,21 @@ public class AuditBootstrapTest extends TestCase @Override public void setUp() throws Exception { - // We have to look inside the subsystem for this test - ApplicationContextFactory subsystem = (ApplicationContextFactory) ctx.getBean("Audit"); - ApplicationContext subCtx = subsystem.getApplicationContext(); - auditModelRegistry = (AuditModelRegistryImpl) subCtx.getBean("auditModel.modelRegistry"); + auditModelRegistry = (AuditModelRegistryImpl) ctx.getBean("auditModel.modelRegistry"); // Register a new model - URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml"); + URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/testaudit/alfresco-audit-test.xml"); auditModelRegistry.registerModel(testModelUrl); auditModelRegistry.loadAuditModels(); } - + + @Override + protected void tearDown() throws Exception + { + // Throw away the reconfigured registry state + auditModelRegistry.destroy(); + } + public void testSetUp() { // Just here to fail if the basic startup fails @@ -97,32 +100,32 @@ public class AuditBootstrapTest extends TestCase public void testModelLoading_NoDataExtractor() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-01.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-01.xml"); } public void testModelLoading_NoDataGenerator() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-02.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-02.xml"); } public void testModelLoading_DuplicatePath() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-03.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-03.xml"); } public void testModelLoading_UppercasePath() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-04.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-04.xml"); } public void testModelLoading_InvalidDataGeneratorName() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-05.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-05.xml"); } public void testModelLoading_BadGeneratorRegisteredName() throws Exception { - loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-06.xml"); + loadBadModel("classpath:alfresco/testaudit/alfresco-audit-test-bad-06.xml"); } public void testGetApplicationId() diff --git a/source/java/org/alfresco/repo/audit/AuditComponentTest.java b/source/java/org/alfresco/repo/audit/AuditComponentTest.java index fc76315b8c..58306e6ed4 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponentTest.java +++ b/source/java/org/alfresco/repo/audit/AuditComponentTest.java @@ -39,7 +39,6 @@ import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.audit.model.AuditApplication; import org.alfresco.repo.audit.model.AuditModelException; import org.alfresco.repo.audit.model.AuditModelRegistryImpl; -import org.alfresco.repo.management.subsystems.ApplicationContextFactory; import org.alfresco.repo.security.authentication.AuthenticationException; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; @@ -80,7 +79,6 @@ public class AuditComponentTest extends TestCase private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext(); - private ApplicationContextFactory subsystem; private AuditModelRegistryImpl auditModelRegistry; private AuditComponent auditComponent; private AuditService auditService; @@ -94,10 +92,7 @@ public class AuditComponentTest extends TestCase @Override public void setUp() throws Exception { - // We have to look inside the subsystem for this test - subsystem = (ApplicationContextFactory) ctx.getBean("Audit"); - ApplicationContext subCtx = subsystem.getApplicationContext(); - auditModelRegistry = (AuditModelRegistryImpl) subCtx.getBean("auditModel.modelRegistry"); + auditModelRegistry = (AuditModelRegistryImpl) ctx.getBean("auditModel.modelRegistry"); auditComponent = (AuditComponent) ctx.getBean("auditComponent"); serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); auditService = serviceRegistry.getAuditService(); @@ -105,7 +100,7 @@ public class AuditComponentTest extends TestCase nodeService = serviceRegistry.getNodeService(); // Register the test model - URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml"); + URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/testaudit/alfresco-audit-test.xml"); auditModelRegistry.registerModel(testModelUrl); auditModelRegistry.loadAuditModels(); @@ -138,8 +133,8 @@ public class AuditComponentTest extends TestCase public void tearDown() throws Exception { AuthenticationUtil.clearCurrentSecurityContext(); - // Throw away the reconfigured registry in the subsystem - subsystem.stop(); + // Throw away the reconfigured registry state + auditModelRegistry.destroy(); } public void testSetUp() @@ -479,7 +474,7 @@ public class AuditComponentTest extends TestCase params.setApplicationName(APPLICATION_API_TEST); // Load in the config for this specific test: alfresco-audit-test-authenticationservice.xml - URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test-authenticationservice.xml"); + URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/testaudit/alfresco-audit-test-authenticationservice.xml"); auditModelRegistry.registerModel(testModelUrl); auditModelRegistry.loadAuditModels(); diff --git a/source/java/org/alfresco/repo/audit/model/AuditModelReader.java b/source/java/org/alfresco/repo/audit/model/AuditModelReader.java deleted file mode 100644 index ae769be616..0000000000 --- a/source/java/org/alfresco/repo/audit/model/AuditModelReader.java +++ /dev/null @@ -1,91 +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.model; - -import java.net.URL; - -import org.springframework.extensions.surf.util.PropertyCheck; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.ResourceUtils; - -/** - * A component used to load Audit model XML documents. - * - * @author Derek Hulley - * @since 3.2 - */ -public class AuditModelReader implements InitializingBean -{ - private URL auditModelUrl; - private AuditModelRegistryImpl auditModelRegistry; - private boolean isActive = true; - - /** - * Set the XML location using file:, classpath: or any of the - * {@link ResourceUtils Spring-supported} formats. - * - * @param auditModelUrl the location of the XML file - */ - public void setAuditModelUrl(URL auditModelUrl) - { - this.auditModelUrl = auditModelUrl; - } - - /** - * - * @param auditModelRegistry the registry that combines all loaded models - */ - public void setAuditModelRegistry(AuditModelRegistryImpl auditModelRegistry) - { - this.auditModelRegistry = auditModelRegistry; - } - - /** - * Controls whether or not this bean registers its model with the registry on initialization. - * - * @param isActive - * true if this bean should register its model with the registry on initialization. - */ - public void setActive(boolean isActive) - { - this.isActive = isActive; - } - - /** - * Pulls in the configuration and registers it - */ - public void afterPropertiesSet() throws Exception - { - if (!this.isActive) - { - return; - } - - PropertyCheck.mandatory(this, "configUrl", auditModelUrl); - PropertyCheck.mandatory(this, "auditModelRegistry", auditModelRegistry); - - auditModelRegistry.registerModel(auditModelUrl); - } -} diff --git a/source/java/org/alfresco/repo/audit/model/AuditModelRegistryImpl.java b/source/java/org/alfresco/repo/audit/model/AuditModelRegistryImpl.java index 32c7fa0b36..76fdeeba77 100644 --- a/source/java/org/alfresco/repo/audit/model/AuditModelRegistryImpl.java +++ b/source/java/org/alfresco/repo/audit/model/AuditModelRegistryImpl.java @@ -28,13 +28,11 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; @@ -58,74 +56,588 @@ import org.alfresco.repo.audit.model._3.PathMap; import org.alfresco.repo.audit.model._3.PathMappings; import org.alfresco.repo.domain.audit.AuditDAO; import org.alfresco.repo.domain.audit.AuditDAO.AuditApplicationInfo; +import org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean; +import org.alfresco.repo.management.subsystems.PropertyBackedBeanState; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.PathMapper; +import org.alfresco.util.ResourceFinder; import org.alfresco.util.registry.NamedObjectRegistry; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.core.io.Resource; import org.springframework.extensions.surf.util.PropertyCheck; import org.springframework.util.ResourceUtils; import org.xml.sax.SAXParseException; /** - * Component used to store audit model definitions. It ensures that duplicate application and converter - * definitions are detected and provides a single lookup for code using the Audit model. + * Component used to store audit model definitions. It ensures that duplicate application and converter definitions are + * detected and provides a single lookup for code using the Audit model. It is factored as a subsystem and exposes a + * global enablement property plus enablement properties for each individual audit application. * * @author Derek Hulley + * @author dward * @since 3.2 */ -public class AuditModelRegistryImpl implements AuditModelRegistry +public class AuditModelRegistryImpl extends AbstractPropertyBackedBean implements AuditModelRegistry { + + /** The name of the global enablement property. */ + private static final String PROPERTY_AUDIT_ENABLED = "audit.enabled"; + private static final String AUDIT_SCHEMA_LOCATION = "classpath:alfresco/audit/alfresco-audit-3.2.xsd"; private static final Log logger = LogFactory.getLog(AuditModelRegistryImpl.class); + private String[] searchPath; private TransactionService transactionService; private AuditDAO auditDAO; private NamedObjectRegistry dataExtractors; private NamedObjectRegistry dataGenerators; - - private final ReentrantReadWriteLock.ReadLock readLock; - private final ReentrantReadWriteLock.WriteLock writeLock; private final ObjectFactory objectFactory; - private final Set auditModelUrls; - private final List auditModels; /** - * Used to lookup path translations + * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#afterPropertiesSet() */ - private PathMapper auditPathMapper; - /** - * Used to lookup the audit application java hierarchy - */ - private final Map auditApplicationsByKey; - /** - * Used to lookup the audit application java hierarchy - */ - private final Map auditApplicationsByName; - - /** - * Default constructor - */ - public AuditModelRegistryImpl() - { - ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - readLock = lock.readLock(); - writeLock = lock.writeLock(); - - objectFactory = new ObjectFactory(); - - auditModelUrls = new HashSet(7); - auditModels = new ArrayList(7); - auditPathMapper = new PathMapper(); - auditApplicationsByKey = new HashMap(7); - auditApplicationsByName = new HashMap(7); + @Override + public void afterPropertiesSet() throws Exception + { + PropertyCheck.mandatory(this, "searchPath", searchPath); + PropertyCheck.mandatory(this, "transactionService", transactionService); + PropertyCheck.mandatory(this, "auditDAO", auditDAO); + PropertyCheck.mandatory(this, "dataExtractors", dataExtractors); + PropertyCheck.mandatory(this, "dataGenerators", dataGenerators); + super.afterPropertiesSet(); } /** - * Service to ensure DAO calls are transactionally wrapped + * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#getState(boolean) + */ + @Override + protected synchronized AuditModelRegistryState getState(boolean start) + { + return (AuditModelRegistryState)super.getState(start); + } + + /** + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByKey(java.lang.String) + */ + public AuditApplication getAuditApplicationByKey(String key) + { + return getState(true).getAuditApplicationByKey(key); + } + + /** + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByName(java.lang.String) + */ + public AuditApplication getAuditApplicationByName(String applicationName) + { + return getState(true).getAuditApplicationByName(applicationName); + } + + /** + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditPathMapper() + */ + public PathMapper getAuditPathMapper() + { + return getState(true).getAuditPathMapper(); + } + + /** + * @see org.alfresco.repo.audit.model.AuditModelRegistry#loadAuditModels() + */ + public void loadAuditModels() + { + stop(); + start(); + } + + /** + * Enables audit and registers an audit model at a given URL. Does not register across the cluster and should only + * be used for unit test purposes. + * + * @param auditModelUrl + * the source of the model + */ + public synchronized void registerModel(URL auditModelUrl) + { + stop(); + setProperty(PROPERTY_AUDIT_ENABLED, "true"); + getState(false).registerModel(auditModelUrl); + } + + /** + * A class encapsulating the disposable/resettable state of the audit model registry. + */ + public class AuditModelRegistryState implements PropertyBackedBeanState + { + + /** The audit models. */ + private final Map auditModels; + + /** Used to lookup path translations. */ + private PathMapper auditPathMapper; + + /** Used to lookup the audit application java hierarchy. */ + private Map auditApplicationsByKey; + + /** Used to lookup the audit application java hierarchy. */ + private Map auditApplicationsByName; + + /** The exposed configuration properties. */ + private final Map properties; + + + /** + * Instantiates a new audit model registry state. + */ + public AuditModelRegistryState() + { + auditModels = new LinkedHashMap(7); + properties = new HashMap(7); + + // Default value for global enabled property + properties.put(PROPERTY_AUDIT_ENABLED, false); + + // Let's search for config files in the appropriate places. The individual applications they contain can still + // be enabled/disabled by the bean properties + ResourceFinder resourceFinder = new ResourceFinder(getParent()); + try + { + for (Resource resource : resourceFinder.getResources(searchPath)) + { + registerModel(resource.getURL()); + } + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("Failed to find audit resources", e); + } + } + + /** + * Register an audit model at a given URL. + * + * @param auditModelUrl + * the source of the model + */ + public void registerModel(URL auditModelUrl) + { + try + { + if (auditModels.containsKey(auditModelUrl)) + { + logger.warn("An audit model has already been registered at URL " + auditModelUrl); + } + Audit audit = AuditModelRegistryImpl.unmarshallModel(auditModelUrl); + + // Store the model itself + auditModels.put(auditModelUrl, audit); + + // Cache property enabling each application by default + List applications = audit.getApplication(); + for (Application application : applications) + { + properties.put(getEnabledProperty(application.getKey()), true); + } + } + catch (Throwable e) + { + throw new AuditModelException("Failed to load audit model: " + auditModelUrl, e); + } + } + + /** + * Gets the name of an enablement property. + * + * @param key + * an application key + * @return the property name + */ + private String getEnabledProperty(String key) + { + return "audit." + key.toLowerCase() + ".enabled"; + } + + /** + * Checks if an application enabled. + * + * @param key + * the application key + * @return true, if the application is enabled + */ + private boolean isApplicationEnabled(String key) + { + Boolean enabled = properties.get(getEnabledProperty(key)); + return enabled != null && enabled; + } + + /** + * @see org.alfresco.repo.management.subsystems.PropertyBackedBeanState#getProperty(java.lang.String) + */ + public String getProperty(String name) + { + return String.valueOf(properties.get(name)); + } + + /** + * @see org.alfresco.repo.management.subsystems.PropertyBackedBeanState#getPropertyNames() + */ + public Set getPropertyNames() + { + return properties.keySet(); + } + + /** + * @see org.alfresco.repo.management.subsystems.PropertyBackedBeanState#setProperty(java.lang.String, java.lang.String) + */ + public void setProperty(String name, String value) + { + properties.put(name, Boolean.parseBoolean(value)); + } + + /** + * @see org.alfresco.repo.management.subsystems.PropertyBackedBeanState#start() + */ + public void start() + { + auditApplicationsByKey = new HashMap(7); + auditApplicationsByName = new HashMap(7); + auditPathMapper = new PathMapper(); + + // If we are globally disabled, skip processing the models + Boolean enabled = properties.get(PROPERTY_AUDIT_ENABLED); + if (enabled != null && enabled) + { + + final RetryingTransactionCallback loadModelsCallback = new RetryingTransactionCallback() + { + public Void execute() throws Throwable + { + // Load models from the URLs + for (Map.Entry entry : auditModels.entrySet()) + { + URL auditModelUrl = entry.getKey(); + Audit audit = entry.getValue(); + try + { + // Get an input stream and write the model + Long auditModelId = auditDAO.getOrCreateAuditModel(auditModelUrl).getFirst(); + + // Now cache it (eagerly) + cacheAuditElements(auditModelId, audit); + } + catch (Throwable e) + { + throw new AuditModelException("Failed to load audit model: " + auditModelUrl, e); + } + } + // NOTE: If we support other types of loading, then that will have to go here, too + + // Done + return null; + } + }; + + // Run as system user to avoid cyclical dependency in bootstrap read-only checking (and we are anyway!) + AuthenticationUtil.runAs(new RunAsWork() + { + public Void doWork() throws Exception + { + transactionService.getRetryingTransactionHelper().doInTransaction(loadModelsCallback, + transactionService.isReadOnly(), true); + return null; + } + }, AuthenticationUtil.getSystemUserName()); + } + + auditPathMapper.lock(); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.management.subsystems.PropertyBackedBeanState#stop() + */ + public void stop() + { + auditPathMapper = null; + } + + + /** + * Gets an audit application by key. + * + * @param key + * the application key + * @return the audit application + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByKey(java.lang.String) + */ + public AuditApplication getAuditApplicationByKey(String key) + { + return auditApplicationsByKey.get(key); + } + + /** + * Gets an audit application by name. + * + * @param applicationName + * the application name + * @return the audit application + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByName(java.lang.String) + */ + public AuditApplication getAuditApplicationByName(String applicationName) + { + return auditApplicationsByName.get(applicationName); + } + + /** + * Gets the audit path mapper. + * + * @return the audit path mapper + * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditPathMapper() + */ + public PathMapper getAuditPathMapper() + { + return auditPathMapper; + } + + /** + * Caches audit elements from a model. + * + * @param auditModelId + * the audit model id + * @param audit + * the audit model + */ + private void cacheAuditElements(Long auditModelId, Audit audit) + { + Map dataExtractorsByName = new HashMap(13); + Map dataGeneratorsByName = new HashMap(13); + + // Get the data extractors and check for duplicates + DataExtractors extractorsElement = audit.getDataExtractors(); + if (extractorsElement == null) + { + extractorsElement = objectFactory.createDataExtractors(); + } + List extractorElements = extractorsElement.getDataExtractor(); + for (org.alfresco.repo.audit.model._3.DataExtractor extractorElement : extractorElements) + { + String name = extractorElement.getName(); + // If the name is taken, make sure that they are equal + if (dataExtractorsByName.containsKey(name)) + { + throw new AuditModelException( + "Audit data extractor '" + name + "' has already been defined."); + } + // Construct the converter + final DataExtractor dataExtractor; + if (extractorElement.getClazz() != null) + { + try + { + Class dataExtractorClazz = Class.forName(extractorElement.getClazz()); + dataExtractor = (DataExtractor) dataExtractorClazz.newInstance(); + } + catch (ClassNotFoundException e) + { + throw new AuditModelException( + "Audit data extractor '" + name + "' class not found: " + extractorElement.getClazz()); + } + catch (Exception e) + { + throw new AuditModelException( + "Audit data extractor '" + name + "' could not be constructed: " + extractorElement.getClazz()); + } + } + else if (extractorElement.getRegisteredName() != null) + { + String registeredName = extractorElement.getRegisteredName(); + dataExtractor = dataExtractors.getNamedObject(registeredName); + if (dataExtractor == null) + { + throw new AuditModelException( + "No registered audit data extractor exists for '" + registeredName + "'."); + } + } + else + { + throw new AuditModelException( + "Audit data extractor has no class or registered name: " + name); + } + // Store + dataExtractorsByName.put(name, dataExtractor); + } + // Get the data generators and check for duplicates + DataGenerators generatorsElement = audit.getDataGenerators(); + if (generatorsElement == null) + { + generatorsElement = objectFactory.createDataGenerators(); + } + List generatorElements = generatorsElement.getDataGenerator(); + for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements) + { + String name = generatorElement.getName(); + // If the name is taken, make sure that they are equal + if (dataGeneratorsByName.containsKey(name)) + { + throw new AuditModelException( + "Audit data generator '" + name + "' has already been defined."); + } + // Construct the generator + final DataGenerator dataGenerator; + if (generatorElement.getClazz() != null) + { + try + { + Class dataGeneratorClazz = Class.forName(generatorElement.getClazz()); + dataGenerator = (DataGenerator) dataGeneratorClazz.newInstance(); + } + catch (ClassNotFoundException e) + { + throw new AuditModelException( + "Audit data generator '" + name + "' class not found: " + generatorElement.getClazz()); + } + catch (Exception e) + { + throw new AuditModelException( + "Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz()); + } + } + else if (generatorElement.getRegisteredName() != null) + { + String registeredName = generatorElement.getRegisteredName(); + dataGenerator = dataGenerators.getNamedObject(registeredName); + if (dataGenerator == null) + { + throw new AuditModelException( + "No registered audit data generator exists for '" + registeredName + "'."); + } + } + else + { + throw new AuditModelException( + "Audit data generator has no class or registered name: " + name); + } + // Store + dataGeneratorsByName.put(name, dataGenerator); + } + // Get the application and check for duplicates + List applications = audit.getApplication(); + for (Application application : applications) + { + String key = application.getKey(); + if (!isApplicationEnabled(key)) + { + continue; + } + + if (auditApplicationsByKey.containsKey(key)) + { + throw new AuditModelException( + "Audit application key '" + key + "' is used by: " + auditApplicationsByKey.get(key)); + } + + String name = application.getName(); + if (auditApplicationsByName.containsKey(name)) + { + throw new AuditModelException( + "Audit application '" + name + "' is used by: " + auditApplicationsByName.get(name)); + } + + // Get the ID of the application + AuditApplicationInfo appInfo = auditDAO.getAuditApplication(name); + if (appInfo == null) + { + appInfo = auditDAO.createAuditApplication(name, auditModelId); + } + else + { + // Update it with the new model ID + auditDAO.updateAuditApplicationModel(appInfo.getId(), auditModelId); + } + + AuditApplication wrapperApp = new AuditApplication( + dataExtractorsByName, + dataGeneratorsByName, + application, + appInfo.getId(), + appInfo.getDisabledPathsId()); + auditApplicationsByName.put(name, wrapperApp); + auditApplicationsByKey.put(key, wrapperApp); + } + + // Pull out all the audit path maps + buildAuditPathMap(audit); + } + + /** + * Construct the reverse lookup maps for quick conversion of data to target maps. + * + * @param audit + * the audit model + */ + private void buildAuditPathMap(Audit audit) + { + PathMappings pathMappings = audit.getPathMappings(); + if (pathMappings == null) + { + pathMappings = objectFactory.createPathMappings(); + } + for (PathMap pathMap : pathMappings.getPathMap()) + { + String sourcePath = pathMap.getSource(); + String targetPath = pathMap.getTarget(); + + // Extract the application key from the root of the path + int keyStart = targetPath.charAt(0) == '/' ? 1 : 0; + int keyEnd = targetPath.indexOf('/', keyStart); + String key = keyEnd == -1 ? targetPath.substring(keyStart) : targetPath.substring(keyStart, keyEnd); + + // Only add the path if the application is not disabled + if (isApplicationEnabled(key)) + { + auditPathMapper.addPathMap(sourcePath, targetPath); + } + } + } + } + + /** + * @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#createInitialState() + */ + @Override + protected PropertyBackedBeanState createInitialState() throws IOException + { + return new AuditModelRegistryState(); + } + + /** + * Default constructor. + */ + public AuditModelRegistryImpl() + { + objectFactory = new ObjectFactory(); + } + + + /** + * Sets the search path for config files. + * + * @param searchPath + * the search path + */ + public void setSearchPath(String[] searchPath) + { + this.searchPath = searchPath; + } + + /** + * Service to ensure DAO calls are transactionally wrapped. + * + * @param transactionService + * the transaction service */ public void setTransactionService(TransactionService transactionService) { @@ -133,7 +645,10 @@ public class AuditModelRegistryImpl implements AuditModelRegistry } /** - * Set the DAO used to persisted the registered audit models + * Set the DAO used to persisted the registered audit models. + * + * @param auditDAO + * the audit dao */ public void setAuditDAO(AuditDAO auditDAO) { @@ -141,7 +656,10 @@ public class AuditModelRegistryImpl implements AuditModelRegistry } /** - * Set the registry of {@link DataExtractor data extractors} + * Set the registry of {@link DataExtractor data extractors}. + * + * @param dataExtractors + * the data extractors */ public void setDataExtractors(NamedObjectRegistry dataExtractors) { @@ -149,177 +667,24 @@ public class AuditModelRegistryImpl implements AuditModelRegistry } /** - * Set the registry of {@link DataGenerator data generators} + * Set the registry of {@link DataGenerator data generators}. + * + * @param dataGenerators + * the data generators */ public void setDataGenerators(NamedObjectRegistry dataGenerators) { this.dataGenerators = dataGenerators; } - /** - * Ensures that all properties have been set for use. - */ - private void checkProperties() - { - PropertyCheck.mandatory(this, "transactionService", transactionService); - PropertyCheck.mandatory(this, "auditDAO", auditDAO); - PropertyCheck.mandatory(this, "dataExtractors", dataExtractors); - PropertyCheck.mandatory(this, "dataGenerators", dataGenerators); - } - - /** - * Register an audit model at a given URL. - * - * @param auditModelUrl the source of the model - */ - public void registerModel(URL auditModelUrl) - { - checkProperties(); - writeLock.lock(); - try - { - if (auditModelUrls.contains(auditModelUrl)) - { - logger.warn("An audit model has already been registered at URL " + auditModelUrl); - } - auditModelUrls.add(auditModelUrl); - } - finally - { - writeLock.unlock(); - } - } - - /** - * Register an audit model at a given node reference. - * - * @param auditModelNodeRef the source of the audit model - */ - public void registerModel(NodeRef auditModelNodeRef) - { - checkProperties(); - writeLock.lock(); - try - { - throw new UnsupportedOperationException(); - } - finally - { - writeLock.unlock(); - } - } - - /** - * Cleans out all derived data - */ - private void clearCaches() - { - auditModels.clear(); - auditApplicationsByKey.clear(); - auditApplicationsByName.clear(); - } - - /** - * @see org.alfresco.repo.audit.model.AuditModelRegistry#loadAuditModels() - */ - public void loadAuditModels() - { - checkProperties(); - - RetryingTransactionCallback loadModelsCallback = new RetryingTransactionCallback() - { - public Void execute() throws Throwable - { - // Load models from the URLs - Set auditModelUrlsInner = new HashSet(auditModelUrls); - for (URL auditModelUrl : auditModelUrlsInner) - { - try - { - Audit audit = AuditModelRegistryImpl.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); - } - 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, - e); - } - } - // NOTE: If we support other types of loading, then that will have to go here, too - - // Done - return null; - } - }; - - writeLock.lock(); - // Drop all cached data - clearCaches(); - try - { - auditPathMapper = new PathMapper(); - transactionService.getRetryingTransactionHelper().doInTransaction(loadModelsCallback, - transactionService.isReadOnly(), true); - auditPathMapper.lock(); - } - finally - { - writeLock.unlock(); - } - } - - /** - * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByKey(java.lang.String) - */ - public AuditApplication getAuditApplicationByKey(String key) - { - readLock.lock(); - try - { - return auditApplicationsByKey.get(key); - } - finally - { - readLock.unlock(); - } - } - - /** - * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditApplicationByName(java.lang.String) - */ - public AuditApplication getAuditApplicationByName(String applicationName) - { - readLock.lock(); - try - { - return auditApplicationsByName.get(applicationName); - } - finally - { - readLock.unlock(); - } - } - - /** - * @see org.alfresco.repo.audit.model.AuditModelRegistry#getAuditPathMapper() - */ - public PathMapper getAuditPathMapper() - { - return auditPathMapper; - } - /** * Unmarshalls the Audit model from the URL. * - * @throws AlfrescoRuntimeException if an IOException occurs + * @param configUrl + * the config url + * @return the audit model + * @throws AlfrescoRuntimeException + * if an IOException occurs */ public static Audit unmarshallModel(URL configUrl) { @@ -336,7 +701,13 @@ public class AuditModelRegistryImpl implements AuditModelRegistry } /** - * Unmarshalls the Audit model from a stream + * Unmarshalls the Audit model from a stream. + * + * @param is + * the is + * @param source + * the source + * @return the audit model */ private static Audit unmarshallModel(InputStream is, final String source) { @@ -398,181 +769,5 @@ public class AuditModelRegistryImpl implements AuditModelRegistry { try { is.close(); } catch (IOException e) {} } - } - - private void cacheAuditElements(Long auditModelId, Audit audit) - { - Map dataExtractorsByName = new HashMap(13); - Map dataGeneratorsByName = new HashMap(13); - - // Get the data extractors and check for duplicates - DataExtractors extractorsElement = audit.getDataExtractors(); - if (extractorsElement == null) - { - extractorsElement = objectFactory.createDataExtractors(); - } - List extractorElements = extractorsElement.getDataExtractor(); - for (org.alfresco.repo.audit.model._3.DataExtractor extractorElement : extractorElements) - { - String name = extractorElement.getName(); - // If the name is taken, make sure that they are equal - if (dataExtractorsByName.containsKey(name)) - { - throw new AuditModelException( - "Audit data extractor '" + name + "' has already been defined."); - } - // Construct the converter - final DataExtractor dataExtractor; - if (extractorElement.getClazz() != null) - { - try - { - Class dataExtractorClazz = Class.forName(extractorElement.getClazz()); - dataExtractor = (DataExtractor) dataExtractorClazz.newInstance(); - } - catch (ClassNotFoundException e) - { - throw new AuditModelException( - "Audit data extractor '" + name + "' class not found: " + extractorElement.getClazz()); - } - catch (Exception e) - { - throw new AuditModelException( - "Audit data extractor '" + name + "' could not be constructed: " + extractorElement.getClazz()); - } - } - else if (extractorElement.getRegisteredName() != null) - { - String registeredName = extractorElement.getRegisteredName(); - dataExtractor = dataExtractors.getNamedObject(registeredName); - if (dataExtractor == null) - { - throw new AuditModelException( - "No registered audit data extractor exists for '" + registeredName + "'."); - } - } - else - { - throw new AuditModelException( - "Audit data extractor has no class or registered name: " + name); - } - // Store - dataExtractorsByName.put(name, dataExtractor); - } - // Get the data generators and check for duplicates - DataGenerators generatorsElement = audit.getDataGenerators(); - if (generatorsElement == null) - { - generatorsElement = objectFactory.createDataGenerators(); - } - List generatorElements = generatorsElement.getDataGenerator(); - for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements) - { - String name = generatorElement.getName(); - // If the name is taken, make sure that they are equal - if (dataGeneratorsByName.containsKey(name)) - { - throw new AuditModelException( - "Audit data generator '" + name + "' has already been defined."); - } - // Construct the generator - final DataGenerator dataGenerator; - if (generatorElement.getClazz() != null) - { - try - { - Class dataGeneratorClazz = Class.forName(generatorElement.getClazz()); - dataGenerator = (DataGenerator) dataGeneratorClazz.newInstance(); - } - catch (ClassNotFoundException e) - { - throw new AuditModelException( - "Audit data generator '" + name + "' class not found: " + generatorElement.getClazz()); - } - catch (Exception e) - { - throw new AuditModelException( - "Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz()); - } - } - else if (generatorElement.getRegisteredName() != null) - { - String registeredName = generatorElement.getRegisteredName(); - dataGenerator = dataGenerators.getNamedObject(registeredName); - if (dataGenerator == null) - { - throw new AuditModelException( - "No registered audit data generator exists for '" + registeredName + "'."); - } - } - else - { - throw new AuditModelException( - "Audit data generator has no class or registered name: " + name); - } - // Store - dataGeneratorsByName.put(name, dataGenerator); - } - // Get the application and check for duplicates - List applications = audit.getApplication(); - for (Application application : applications) - { - String key = application.getKey(); - if (auditApplicationsByKey.containsKey(key)) - { - throw new AuditModelException( - "Audit application key '" + key + "' is used by: " + auditApplicationsByKey.get(key)); - } - - String name = application.getName(); - if (auditApplicationsByName.containsKey(name)) - { - throw new AuditModelException( - "Audit application '" + name + "' is used by: " + auditApplicationsByName.get(name)); - } - - // Get the ID of the application - AuditApplicationInfo appInfo = auditDAO.getAuditApplication(name); - if (appInfo == null) - { - appInfo = auditDAO.createAuditApplication(name, auditModelId); - } - else - { - // Update it with the new model ID - auditDAO.updateAuditApplicationModel(appInfo.getId(), auditModelId); - } - - AuditApplication wrapperApp = new AuditApplication( - dataExtractorsByName, - dataGeneratorsByName, - application, - appInfo.getId(), - appInfo.getDisabledPathsId()); - auditApplicationsByName.put(name, wrapperApp); - auditApplicationsByKey.put(key, wrapperApp); - } - // Pull out all the audit path maps - buildAuditPathMap(audit); - // Store the model itself - auditModels.add(audit); - } - - /** - * Construct the reverse lookup maps for quick conversion of data to target maps - */ - private void buildAuditPathMap(Audit audit) - { - PathMappings pathMappings = audit.getPathMappings(); - if (pathMappings == null) - { - pathMappings = objectFactory.createPathMappings(); - } - for (PathMap pathMap : pathMappings.getPathMap()) - { - String sourcePath = pathMap.getSource(); - String targetPath = pathMap.getTarget(); - auditPathMapper.addPathMap(sourcePath, targetPath); - } - } + } } diff --git a/source/java/org/alfresco/util/ResourceFinder.java b/source/java/org/alfresco/util/ResourceFinder.java index 7104684985..c00b3f4aa2 100644 --- a/source/java/org/alfresco/util/ResourceFinder.java +++ b/source/java/org/alfresco/util/ResourceFinder.java @@ -66,7 +66,7 @@ public class ResourceFinder extends ServletContextResourcePatternResolver * @throws IOException * Signals that an I/O exception has occurred. */ - public Resource[] getResources(String[] locationPatterns) throws IOException + public Resource[] getResources(String... locationPatterns) throws IOException { List resources = new LinkedList(); for (String locationPattern : locationPatterns) diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-authenticationservice.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-authenticationservice.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-authenticationservice.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-authenticationservice.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-01.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-01.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-01.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-01.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-02.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-02.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-02.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-02.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-03.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-03.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-03.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-03.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-04.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-04.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-04.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-04.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-05.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-05.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-05.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-05.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test-bad-06.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-06.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test-bad-06.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test-bad-06.xml diff --git a/source/test-resources/alfresco/audit/alfresco-audit-test.xml b/source/test-resources/alfresco/testaudit/alfresco-audit-test.xml similarity index 100% rename from source/test-resources/alfresco/audit/alfresco-audit-test.xml rename to source/test-resources/alfresco/testaudit/alfresco-audit-test.xml