diff --git a/config/alfresco/audit-services-context.xml b/config/alfresco/audit-services-context.xml index b2b94d1f22..2c350a68c8 100644 --- a/config/alfresco/audit-services-context.xml +++ b/config/alfresco/audit-services-context.xml @@ -19,7 +19,7 @@ - + @@ -36,6 +36,8 @@ + + diff --git a/config/alfresco/dao/dao-context.xml b/config/alfresco/dao/dao-context.xml index 3c9caac703..635a8b1676 100644 --- a/config/alfresco/dao/dao-context.xml +++ b/config/alfresco/dao/dao-context.xml @@ -56,6 +56,7 @@ + diff --git a/config/alfresco/hibernate-context.xml b/config/alfresco/hibernate-context.xml index d2ca9e4580..27ab7d5cd5 100644 --- a/config/alfresco/hibernate-context.xml +++ b/config/alfresco/hibernate-context.xml @@ -336,14 +336,14 @@ - - - - + + + + - + @@ -442,7 +442,7 @@ - + diff --git a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java index 9938929ee7..f604b79c47 100644 --- a/source/java/org/alfresco/repo/audit/AuditComponentImpl.java +++ b/source/java/org/alfresco/repo/audit/AuditComponentImpl.java @@ -33,9 +33,13 @@ import java.util.List; import java.util.Map; import org.alfresco.repo.audit.model.AuditEntry; +import org.alfresco.repo.audit.model.AuditModelRegistry; import org.alfresco.repo.audit.model.TrueFalseUnset; +import org.alfresco.repo.audit.model._3.Application; +import org.alfresco.repo.domain.audit.AuditDAO; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.AlfrescoTransactionSupport; +import org.alfresco.repo.transaction.TransactionalResourceHelper; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.Auditable; @@ -74,7 +78,7 @@ public class AuditComponentImpl implements AuditComponent /** * Logging */ - private static Log s_logger = LogFactory.getLog(AuditComponentImpl.class); + private static Log logger = LogFactory.getLog(AuditComponentImpl.class); /** * Suspend resume auditing @@ -119,7 +123,7 @@ public class AuditComponentImpl implements AuditComponent } catch (UnknownHostException e) { - s_logger.error("Failed to get local host address", e); + logger.error("Failed to get local host address", e); } } @@ -129,8 +133,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the DAO for recording auditable information when no exception occurs. - * - * @param auditDAO */ public void setAuditDAO(AuditDAO auditDAO) { @@ -139,8 +141,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the DAO for recording failed actions - this is done in another transaction. - * - * @param auditFailedDAO */ public void setTransactionService(TransactionService transactionService) { @@ -149,8 +149,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the NodeService for path extracting. - * - * @param nodeService */ public void setNodeService(NodeService nodeService) { @@ -159,8 +157,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the audit configuration. - * - * @param auditConfiguration */ public void setAuditConfiguration(AuditConfiguration auditConfiguration) { @@ -169,8 +165,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the helper used to identify public services - * - * @param publicServiceIdentifier */ public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier) { @@ -179,8 +173,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the audit model. - * - * @param auditModel */ public void setAuditModel(AuditModel auditModel) { @@ -190,7 +182,6 @@ public class AuditComponentImpl implements AuditComponent /** * Set the namespacePrefixResolver. - * @param namespacePrefixResolver */ public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) { @@ -216,9 +207,9 @@ public class AuditComponentImpl implements AuditComponent } else { - if (s_logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - s_logger.debug("Auditing internal service use for - " + serviceName + "." + methodName); + logger.debug("Auditing internal service use for - " + serviceName + "." + methodName); } } @@ -227,17 +218,17 @@ public class AuditComponentImpl implements AuditComponent if (serviceName != null) { - if (s_logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - s_logger.debug("Auditing - " + serviceName + "." + methodName); + logger.debug("Auditing - " + serviceName + "." + methodName); } return auditImpl(mi); } else { - if (s_logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - s_logger.debug("UnknownService." + methodName); + logger.debug("UnknownService." + methodName); } return auditImpl(mi); } @@ -245,17 +236,17 @@ public class AuditComponentImpl implements AuditComponent } else if (method.isAnnotationPresent(NotAuditable.class)) { - if (s_logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - s_logger.debug("Not Audited. " + serviceName + "." + methodName); + logger.debug("Not Audited. " + serviceName + "." + methodName); } return mi.proceed(); } else { - if (s_logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { - s_logger.debug("Unannotated service method " + serviceName + "." + methodName); + logger.debug("Unannotated service method " + serviceName + "." + methodName); } if (method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAnnotationPresent(PublicService.class)) { @@ -426,7 +417,7 @@ public class AuditComponentImpl implements AuditComponent } else { - s_logger.warn("Key argument is not a node, store or child assoc ref for return object on " + logger.warn("Key argument is not a node, store or child assoc ref for return object on " + publicServiceIdentifier.getPublicServiceName(mi) + "." + mi.getMethod().getName() + " it is " + returnObject.getClass().getName()); } } @@ -556,7 +547,7 @@ public class AuditComponentImpl implements AuditComponent } else { - s_logger.warn("Key argument is not a node, store or child assoc reference or search parameters on " + logger.warn("Key argument is not a node, store or child assoc reference or search parameters on " + serviceName + "." + methodName + " it is " + key.getClass().getName()); } } @@ -604,7 +595,7 @@ public class AuditComponentImpl implements AuditComponent { if (mi.getArguments().length <= position) { - s_logger.warn("Auditable annotation on " + serviceName + "." + methodName + " references non existant argument"); + logger.warn("Auditable annotation on " + serviceName + "." + methodName + " references non existant argument"); } } @@ -760,14 +751,66 @@ public class AuditComponentImpl implements AuditComponent /* * V3.2 from here on. Put all fixes to the older audit code before this point, please. */ + + private static final Long NO_AUDIT_SESSION = new Long(-1); + private static final String KEY_AUDIT_SESSION = "Audit.Sessions"; + + private AuditModelRegistry auditModelRegistry; - public Long startAuditSession(String application, String rootPath) + /** + * Set the registry holding the audit models + * @since 3.2 + */ + public void setAuditModelRegistry(AuditModelRegistry auditModelRegistry) { - throw new UnsupportedOperationException(); + this.auditModelRegistry = auditModelRegistry; + } + + public Long startAuditSession(String applicationName, String rootPath) + { + // First check that we can store a session on the transaction + Map sessionsById = TransactionalResourceHelper.getMap(KEY_AUDIT_SESSION); + + // Get the application + Application application = auditModelRegistry.getAuditApplication(applicationName); + if (application == null) + { + if (logger.isDebugEnabled()) + { + logger.debug("No audit application named '" + applicationName + "' has been registered."); + } + return NO_AUDIT_SESSION; + } + // Get the model ID for the application + Long modelId = auditModelRegistry.getAuditModelId(applicationName); + if (modelId == null) + { + throw new AuditException("No model exists for audit application: " + applicationName); + } + + // TODO: Validate root path against application + // TODO: Pull out session properties and persist + + // Now create the session + Long sessionId = auditDAO.createAuditSession(modelId, applicationName); + // Create the session info and store it on the transaction + AuditSession session = new AuditSession(application, rootPath, sessionId); + sessionsById.put(sessionId, session); + // Done + if (logger.isDebugEnabled()) + { + logger.debug("New audit session: " + session); + } + return sessionId; } public void audit(Long sessionId, Map values) { + if (sessionId == NO_AUDIT_SESSION) + { + // For some reason, the session was not to be used + return; + } throw new UnsupportedOperationException(); } } diff --git a/source/java/org/alfresco/repo/audit/AuditDAO.java b/source/java/org/alfresco/repo/audit/AuditDAO.java deleted file mode 100644 index 7d6d5a2552..0000000000 --- a/source/java/org/alfresco/repo/audit/AuditDAO.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2005-2007 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.util.List; - -import org.alfresco.service.cmr.audit.AuditInfo; -import org.alfresco.service.cmr.repository.NodeRef; - -/** - * The interface to persist audit information. - * - * @author Andy Hind - */ -public interface AuditDAO -{ - /** - * Create an audit entry. - * - * @param auditInfo - */ - public void audit(AuditState auditInfo); - - /** - * Get the audit trail for a node. - * - * @param nodeRef - * @return - */ - public List getAuditTrail(NodeRef nodeRef); -} diff --git a/source/java/org/alfresco/repo/audit/AuditSession.java b/source/java/org/alfresco/repo/audit/AuditSession.java index 3c75e4256a..690ddb5a9a 100644 --- a/source/java/org/alfresco/repo/audit/AuditSession.java +++ b/source/java/org/alfresco/repo/audit/AuditSession.java @@ -28,7 +28,7 @@ import org.alfresco.repo.audit.model._3.Application; import org.alfresco.util.ParameterCheck; /** - * Entity bean for alf_audit_session table. + * Bean to hold session information for repeated use. * * @author Derek Hulley * @since 3.2 @@ -37,14 +37,22 @@ public class AuditSession { private final Application application; private final String rootPath; + private final Long sessionId; - public AuditSession(Application application, String rootPath) + /** + * @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(Application 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 @@ -79,6 +87,7 @@ public class AuditSession sb.append("AuditSession") .append("[ application=").append(application.getName()) .append(", rootPath=").append(rootPath) + .append(", sessionId=").append(sessionId) .append("]"); return sb.toString(); } @@ -92,4 +101,9 @@ public class AuditSession { return rootPath; } + + public Long getSessionId() + { + return sessionId; + } } diff --git a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java index dff7104af7..07fdc56d75 100644 --- a/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java +++ b/source/java/org/alfresco/repo/audit/hibernate/HibernateAuditDAO.java @@ -28,6 +28,7 @@ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; @@ -41,15 +42,16 @@ import java.util.List; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.audit.AuditComponentImpl; import org.alfresco.repo.audit.AuditConfiguration; -import org.alfresco.repo.audit.AuditDAO; import org.alfresco.repo.audit.AuditState; import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.domain.audit.AuditDAO; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.transaction.TransactionalDao; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.audit.AuditInfo; +import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.NodeRef; @@ -57,6 +59,7 @@ import org.alfresco.service.cmr.repository.datatype.Duration; import org.alfresco.service.transaction.TransactionService; import org.alfresco.util.EqualsHelper; import org.alfresco.util.GUID; +import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; @@ -136,6 +139,28 @@ 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 + * + * @throws UnsupportedOperationException always + * @since 3.2 + */ + public Pair getOrCreateAuditModel(URL url) + { + throw new UnsupportedOperationException(); + } + public void audit(AuditState auditInfo) { if (auditInfo.getUserIdentifier() == null) diff --git a/source/java/org/alfresco/repo/audit/model/AuditModelRegistry.java b/source/java/org/alfresco/repo/audit/model/AuditModelRegistry.java index 65b30252ab..738835aa6e 100644 --- a/source/java/org/alfresco/repo/audit/model/AuditModelRegistry.java +++ b/source/java/org/alfresco/repo/audit/model/AuditModelRegistry.java @@ -191,6 +191,25 @@ public class AuditModelRegistry } } + /** + * Get the application model for the given application name + * + * @param application the name of the audited application + * @return the java model (null if not found) + */ + public Application getAuditApplication(String application) + { + readLock.lock(); + try + { + return auditApplicationsByName.get(application); + } + finally + { + readLock.unlock(); + } + } + /** * Unmarshalls the Audit model from the URL. * diff --git a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java index e4831ce976..7a16d61d02 100644 --- a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java @@ -27,15 +27,20 @@ package org.alfresco.repo.domain.audit; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.util.List; import java.util.zip.CRC32; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.repo.audit.AuditState; +import org.alfresco.repo.audit.hibernate.HibernateAuditDAO; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.domain.propval.PropertyValueDAO; +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.repository.ContentData; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentWriter; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -50,10 +55,16 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO { private static final Log logger = LogFactory.getLog(AbstractAuditDAOImpl.class); + private HibernateAuditDAO oldDAO; private ContentService contentService; private ContentDataDAO contentDataDAO; private PropertyValueDAO propertyValueDAO; + public void setOldDAO(HibernateAuditDAO oldDAO) + { + this.oldDAO = oldDAO; + } + public void setContentService(ContentService contentService) { this.contentService = contentService; @@ -68,8 +79,29 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO { this.propertyValueDAO = propertyValueDAO; } - + /* + * Support for older audit DAO + */ + + /** + * Uses {@link HibernateAuditDAO older DAO} + * @since 3.2 + */ + public void audit(AuditState auditInfo) + { + oldDAO.audit(auditInfo); + } + + /** + * Uses {@link HibernateAuditDAO older DAO} + * @since 3.2 + */ + public List getAuditTrail(NodeRef nodeRef) + { + return oldDAO.getAuditTrail(nodeRef); + } + /* * alf_audit_model */ diff --git a/source/java/org/alfresco/repo/domain/audit/AuditDAO.java b/source/java/org/alfresco/repo/domain/audit/AuditDAO.java index 87bea74e71..f7634e9374 100644 --- a/source/java/org/alfresco/repo/domain/audit/AuditDAO.java +++ b/source/java/org/alfresco/repo/domain/audit/AuditDAO.java @@ -25,18 +25,44 @@ package org.alfresco.repo.domain.audit; import java.net.URL; +import java.util.List; +import org.alfresco.repo.audit.AuditState; +import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.util.Pair; /** * DAO services for alf_audit_XXX tables. + *

+ * The older methods are supported by a different implementation and will eventually + * be deprecated and phased out. * * @author Derek Hulley * @since 3.2 */ public interface AuditDAO { + /** + * Create an audit entry. + * + * @param auditInfo + * @since 2.1 + */ + public void audit(AuditState auditInfo); + + /** + * Get the audit trail for a node. + * + * @since 2.1 + */ + public List getAuditTrail(NodeRef nodeRef); + + /* + * V3.2 methods after here only, please + */ + /** * Creates a new audit model entry or finds an existing one * @@ -46,5 +72,12 @@ public interface AuditDAO */ Pair getOrCreateAuditModel(URL url); + /** + * Creates a new audit session entry - there is no session re-use. + * + * @param modelId a pre-existing model's ID + * @param application the name of the application + * @return Returns the unique session ID + */ Long createAuditSession(Long modelId, String application); }