AuditComponent work for new auditing

- Pulled old AuditDAO methods into new AuditDAO interface
 - Combined AuditDAO implementations
 - First cut of high-level AuditSession creation
 - TODO: AuditSession data generation according to path


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15864 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-08-21 18:51:35 +00:00
parent 00dfb8ee66
commit 442e1040d6
10 changed files with 210 additions and 94 deletions

View File

@@ -19,7 +19,7 @@
<ref bean="publicServiceIdentifier"/> <ref bean="publicServiceIdentifier"/>
</property> </property>
<property name="auditDAO"> <property name="auditDAO">
<ref bean="auditDao"/> <ref bean="auditDAO"/>
</property> </property>
<property name="transactionService"> <property name="transactionService">
<ref bean="transactionService"/> <ref bean="transactionService"/>
@@ -36,6 +36,8 @@
<property name="auditModel"> <property name="auditModel">
<ref bean="auditModel"/> <ref bean="auditModel"/>
</property> </property>
<!-- V3.2 specific -->
<property name="auditModelRegistry" ref="auditModel.registry"/>
</bean> </bean>
<!-- Public service idntifier --> <!-- Public service idntifier -->

View File

@@ -56,6 +56,7 @@
</bean> </bean>
<bean id="auditDAO" class="org.alfresco.repo.domain.audit.ibatis.AuditDAOImpl"> <bean id="auditDAO" class="org.alfresco.repo.domain.audit.ibatis.AuditDAOImpl">
<property name="oldDAO" ref="auditDaoHibernate"/>
<property name="sqlMapClientTemplate" ref="auditSqlMapClientTemplate"/> <property name="sqlMapClientTemplate" ref="auditSqlMapClientTemplate"/>
<property name="contentService" ref="contentService"/> <property name="contentService" ref="contentService"/>
<property name="contentDataDAO" ref="contentDataDAO"/> <property name="contentDataDAO" ref="contentDataDAO"/>

View File

@@ -442,7 +442,7 @@
</property> </property>
</bean> </bean>
<bean id="auditDao" class="org.alfresco.repo.audit.hibernate.HibernateAuditDAO"> <bean id="auditDaoHibernate" class="org.alfresco.repo.audit.hibernate.HibernateAuditDAO">
<property name="sessionFactory"> <property name="sessionFactory">
<ref bean="sessionFactory"/> <ref bean="sessionFactory"/>
</property> </property>

View File

@@ -33,9 +33,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.alfresco.repo.audit.model.AuditEntry; import org.alfresco.repo.audit.model.AuditEntry;
import org.alfresco.repo.audit.model.AuditModelRegistry;
import org.alfresco.repo.audit.model.TrueFalseUnset; import org.alfresco.repo.audit.model.TrueFalseUnset;
import org.alfresco.repo.audit.model._3.Application;
import org.alfresco.repo.domain.audit.AuditDAO;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport; import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.TransactionalResourceHelper;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState; import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.Auditable; import org.alfresco.service.Auditable;
@@ -74,7 +78,7 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Logging * Logging
*/ */
private static Log s_logger = LogFactory.getLog(AuditComponentImpl.class); private static Log logger = LogFactory.getLog(AuditComponentImpl.class);
/** /**
* Suspend resume auditing * Suspend resume auditing
@@ -119,7 +123,7 @@ public class AuditComponentImpl implements AuditComponent
} }
catch (UnknownHostException e) 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. * Set the DAO for recording auditable information when no exception occurs.
*
* @param auditDAO
*/ */
public void setAuditDAO(AuditDAO 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. * Set the DAO for recording failed actions - this is done in another transaction.
*
* @param auditFailedDAO
*/ */
public void setTransactionService(TransactionService transactionService) public void setTransactionService(TransactionService transactionService)
{ {
@@ -149,8 +149,6 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Set the NodeService for path extracting. * Set the NodeService for path extracting.
*
* @param nodeService
*/ */
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
@@ -159,8 +157,6 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Set the audit configuration. * Set the audit configuration.
*
* @param auditConfiguration
*/ */
public void setAuditConfiguration(AuditConfiguration auditConfiguration) public void setAuditConfiguration(AuditConfiguration auditConfiguration)
{ {
@@ -169,8 +165,6 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Set the helper used to identify public services * Set the helper used to identify public services
*
* @param publicServiceIdentifier
*/ */
public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier) public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier)
{ {
@@ -179,8 +173,6 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Set the audit model. * Set the audit model.
*
* @param auditModel
*/ */
public void setAuditModel(AuditModel auditModel) public void setAuditModel(AuditModel auditModel)
{ {
@@ -190,7 +182,6 @@ public class AuditComponentImpl implements AuditComponent
/** /**
* Set the namespacePrefixResolver. * Set the namespacePrefixResolver.
* @param namespacePrefixResolver
*/ */
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver) public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
{ {
@@ -216,9 +207,9 @@ public class AuditComponentImpl implements AuditComponent
} }
else 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 (serviceName != null)
{ {
if (s_logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
s_logger.debug("Auditing - " + serviceName + "." + methodName); logger.debug("Auditing - " + serviceName + "." + methodName);
} }
return auditImpl(mi); return auditImpl(mi);
} }
else else
{ {
if (s_logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
s_logger.debug("UnknownService." + methodName); logger.debug("UnknownService." + methodName);
} }
return auditImpl(mi); return auditImpl(mi);
} }
@@ -245,17 +236,17 @@ public class AuditComponentImpl implements AuditComponent
} }
else if (method.isAnnotationPresent(NotAuditable.class)) 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(); return mi.proceed();
} }
else 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)) if (method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAnnotationPresent(PublicService.class))
{ {
@@ -426,7 +417,7 @@ public class AuditComponentImpl implements AuditComponent
} }
else 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()); + publicServiceIdentifier.getPublicServiceName(mi) + "." + mi.getMethod().getName() + " it is " + returnObject.getClass().getName());
} }
} }
@@ -556,7 +547,7 @@ public class AuditComponentImpl implements AuditComponent
} }
else 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()); + serviceName + "." + methodName + " it is " + key.getClass().getName());
} }
} }
@@ -604,7 +595,7 @@ public class AuditComponentImpl implements AuditComponent
{ {
if (mi.getArguments().length <= position) 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");
} }
} }
@@ -761,13 +752,65 @@ public class AuditComponentImpl implements AuditComponent
* V3.2 from here on. Put all fixes to the older audit code before this point, please. * V3.2 from here on. Put all fixes to the older audit code before this point, please.
*/ */
public Long startAuditSession(String application, String rootPath) private static final Long NO_AUDIT_SESSION = new Long(-1);
private static final String KEY_AUDIT_SESSION = "Audit.Sessions";
private AuditModelRegistry auditModelRegistry;
/**
* 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<Long, AuditSession> 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<String, Object> values) public void audit(Long sessionId, Map<String, Object> values)
{ {
if (sessionId == NO_AUDIT_SESSION)
{
// For some reason, the session was not to be used
return;
}
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }

View File

@@ -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<AuditInfo> getAuditTrail(NodeRef nodeRef);
}

View File

@@ -28,7 +28,7 @@ import org.alfresco.repo.audit.model._3.Application;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
/** /**
* Entity bean for <b>alf_audit_session</b> table. * Bean to hold session information for repeated use.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 3.2 * @since 3.2
@@ -37,14 +37,22 @@ public class AuditSession
{ {
private final Application application; private final Application application;
private final String rootPath; 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.mandatory("application", application);
ParameterCheck.mandatoryString("rootPath", rootPath); ParameterCheck.mandatoryString("rootPath", rootPath);
ParameterCheck.mandatory("sessionId", sessionId);
this.application = application; this.application = application;
this.rootPath = rootPath; this.rootPath = rootPath;
this.sessionId = sessionId;
} }
@Override @Override
@@ -79,6 +87,7 @@ public class AuditSession
sb.append("AuditSession") sb.append("AuditSession")
.append("[ application=").append(application.getName()) .append("[ application=").append(application.getName())
.append(", rootPath=").append(rootPath) .append(", rootPath=").append(rootPath)
.append(", sessionId=").append(sessionId)
.append("]"); .append("]");
return sb.toString(); return sb.toString();
} }
@@ -92,4 +101,9 @@ public class AuditSession
{ {
return rootPath; return rootPath;
} }
public Long getSessionId()
{
return sessionId;
}
} }

View File

@@ -28,6 +28,7 @@ import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable; import java.io.Serializable;
import java.net.URL;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
@@ -41,15 +42,16 @@ import java.util.List;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.audit.AuditComponentImpl; import org.alfresco.repo.audit.AuditComponentImpl;
import org.alfresco.repo.audit.AuditConfiguration; import org.alfresco.repo.audit.AuditConfiguration;
import org.alfresco.repo.audit.AuditDAO;
import org.alfresco.repo.audit.AuditState; import org.alfresco.repo.audit.AuditState;
import org.alfresco.repo.content.ContentContext; import org.alfresco.repo.content.ContentContext;
import org.alfresco.repo.content.ContentStore; import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.domain.audit.AuditDAO;
import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.TransactionalDao; import org.alfresco.repo.transaction.TransactionalDao;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.audit.AuditInfo; 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.ContentReader;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef; 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.service.transaction.TransactionService;
import org.alfresco.util.EqualsHelper; import org.alfresco.util.EqualsHelper;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@@ -136,6 +139,28 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
this.localSessionFactory = localSessionFactory; 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<Long, ContentData> getOrCreateAuditModel(URL url)
{
throw new UnsupportedOperationException();
}
public void audit(AuditState auditInfo) public void audit(AuditState auditInfo)
{ {
if (auditInfo.getUserIdentifier() == null) if (auditInfo.getUserIdentifier() == null)

View File

@@ -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 (<tt>null</tt> 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. * Unmarshalls the Audit model from the URL.
* *

View File

@@ -27,15 +27,20 @@ package org.alfresco.repo.domain.audit;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
import java.util.List;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import org.alfresco.error.AlfrescoRuntimeException; 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.content.MimetypeMap;
import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO;
import org.alfresco.repo.domain.propval.PropertyValueDAO; 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.ContentData;
import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; 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 static final Log logger = LogFactory.getLog(AbstractAuditDAOImpl.class);
private HibernateAuditDAO oldDAO;
private ContentService contentService; private ContentService contentService;
private ContentDataDAO contentDataDAO; private ContentDataDAO contentDataDAO;
private PropertyValueDAO propertyValueDAO; private PropertyValueDAO propertyValueDAO;
public void setOldDAO(HibernateAuditDAO oldDAO)
{
this.oldDAO = oldDAO;
}
public void setContentService(ContentService contentService) public void setContentService(ContentService contentService)
{ {
this.contentService = contentService; this.contentService = contentService;
@@ -69,6 +80,27 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
this.propertyValueDAO = propertyValueDAO; 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<AuditInfo> getAuditTrail(NodeRef nodeRef)
{
return oldDAO.getAuditTrail(nodeRef);
}
/* /*
* alf_audit_model * alf_audit_model

View File

@@ -25,18 +25,44 @@
package org.alfresco.repo.domain.audit; package org.alfresco.repo.domain.audit;
import java.net.URL; 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.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
/** /**
* DAO services for <b>alf_audit_XXX</b> tables. * DAO services for <b>alf_audit_XXX</b> tables.
* <p>
* The older methods are supported by a different implementation and will eventually
* be deprecated and phased out.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 3.2 * @since 3.2
*/ */
public interface AuditDAO 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<AuditInfo> getAuditTrail(NodeRef nodeRef);
/*
* V3.2 methods after here only, please
*/
/** /**
* Creates a new audit model entry or finds an existing one * Creates a new audit model entry or finds an existing one
* *
@@ -46,5 +72,12 @@ public interface AuditDAO
*/ */
Pair<Long, ContentData> getOrCreateAuditModel(URL url); Pair<Long, ContentData> 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); Long createAuditSession(Long modelId, String application);
} }