Added key-value audit query

- Currently supports lookups on string values (RM use-case)


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16133 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-09-07 17:38:27 +00:00
parent fadc101ce4
commit bae58d6ee7
7 changed files with 163 additions and 55 deletions

View File

@@ -125,53 +125,6 @@
join alf_audit_entry entry on (entry.audit_app_id = app.id)
join alf_prop_value user_pv on (user_pv.id = entry.audit_user_id)
join alf_prop_string_value user_sv on (user_sv.id = user_pv.long_value and user_pv.persisted_type = 3)
<dynamic prepend="where">
<isNotNull prepend="and" property="auditAppNameShort">
app_sv.string_end_lower = #auditAppNameShort# and
app_sv.string_crc = #auditAppNameCrc#
</isNotNull>
<isNotNull prepend="and" property="auditUserShort">
user_sv.string_end_lower = #auditUserShort# and
user_sv.string_crc = #auditUserCrc#
</isNotNull>
<isNotNull prepend="and" property="auditFromTime">
<![CDATA[entry.audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToTime">
<![CDATA[entry.audit_time < #auditToTime#]]>
</isNotNull>
</dynamic>
order by
entry.id
</select>
<!-- Get audit entries -->
<!-- TODO: Use compound parameters for string searching, possibly namespaced from propval -->
<!-- TODO: Use compound result map for audit values -->
<select id="select_AuditEntriesWithValues" parameterClass="AuditQueryParameters" resultMap="result_AuditQueryAllValues">
select
entry.id as audit_entry_id,
user_sv.string_value as audit_user,
app_sv.string_value as audit_app_name,
entry.audit_time as audit_time,
entry.audit_values_id as audit_values_id,
cl.root_prop_id, cl.current_prop_id, cl.value_prop_id, cl.key_prop_id,
v.actual_type_id, v.persisted_type,
v.long_value, dv.double_value, sv.string_value, serv.serializable_value
from
alf_audit_app app
join alf_prop_value app_pv on (app_pv.id = app.app_name_id)
join alf_prop_string_value app_sv on (app_sv.id = app_pv.long_value and app_pv.persisted_type = 3)
join alf_audit_entry entry on (entry.audit_app_id = app.id)
join alf_prop_value user_pv on (user_pv.id = entry.audit_user_id)
join alf_prop_string_value user_sv on (user_sv.id = user_pv.long_value and user_pv.persisted_type = 3)
join alf_prop_link cl on (cl.root_prop_id = entry.audit_values_id)
join alf_prop_value v on (cl.value_prop_id = v.id)
left join alf_prop_double_value dv on (dv.id = v.long_value and v.persisted_type = 2)
left join alf_prop_string_value sv on (sv.id = v.long_value and (v.persisted_type = 3 || v.persisted_type = 5))
left join alf_prop_serializable_value serv on (serv.id = v.long_value and v.persisted_type = 4)
<dynamic prepend="where">
<isNotNull prepend="and" property="auditAppNameShort">
app_sv.string_end_lower = #auditAppNameShort# and
@@ -192,4 +145,67 @@
entry.id
</select>
<!-- Get audit entries -->
<!-- TODO: Use compound parameters for string searching, possibly namespaced from propval -->
<select id="select_AuditEntriesWithValues" parameterClass="AuditQueryParameters" resultMap="result_AuditQueryAllValues">
select
entry.id as audit_entry_id,
user_sv.string_value as audit_user,
app_sv.string_value as audit_app_name,
entry.audit_time as audit_time,
entry.audit_values_id as audit_values_id,
pl.root_prop_id, pl.current_prop_id, pl.value_prop_id, pl.key_prop_id,
v.actual_type_id, v.persisted_type,
v.long_value, dv.double_value, sv.string_value, serv.serializable_value
from
alf_audit_app app
join alf_prop_value app_pv on (app_pv.id = app.app_name_id)
join alf_prop_string_value app_sv on (app_sv.id = app_pv.long_value and app_pv.persisted_type = 3)
join alf_audit_entry entry on (entry.audit_app_id = app.id)
join alf_prop_value user_pv on (user_pv.id = entry.audit_user_id)
join alf_prop_string_value user_sv on (user_sv.id = user_pv.long_value and user_pv.persisted_type = 3)
<isNotNull property="searchKey">
join alf_prop_link sp_kpl on (sp_kpl.root_prop_id = entry.audit_values_id)
join alf_prop_value sp_kv on (sp_kpl.key_prop_id = sp_kv.id)
join alf_prop_string_value sp_ksv on (sp_ksv.id = sp_kv.long_value and sp_kv.persisted_type = 3)
</isNotNull>
<isNotNull property="searchValueString">
join alf_prop_link sp_mpl on (sp_mpl.root_prop_id = entry.audit_values_id)
join alf_prop_value sp_mv on (sp_mpl.value_prop_id = sp_mv.id)
join alf_prop_string_value sp_msv on (sp_msv.id = sp_mv.long_value and sp_mv.persisted_type = 3)
</isNotNull>
join alf_prop_link pl on (pl.root_prop_id = entry.audit_values_id)
join alf_prop_value v on (pl.value_prop_id = v.id)
left join alf_prop_double_value dv on (dv.id = v.long_value and v.persisted_type = 2)
left join alf_prop_string_value sv on (sv.id = v.long_value and (v.persisted_type = 3 || v.persisted_type = 5))
left join alf_prop_serializable_value serv on (serv.id = v.long_value and v.persisted_type = 4)
<dynamic prepend="where">
<isNotNull prepend="and" property="auditAppNameShort">
app_sv.string_end_lower = #auditAppNameShort# and
app_sv.string_crc = #auditAppNameCrc#
</isNotNull>
<isNotNull prepend="and" property="auditUserShort">
user_sv.string_end_lower = #auditUserShort# and
user_sv.string_crc = #auditUserCrc#
</isNotNull>
<isNotNull prepend="and" property="auditFromTime">
<![CDATA[entry.audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull prepend="and" property="auditToTime">
<![CDATA[entry.audit_time < #auditToTime#]]>
</isNotNull>
<isNotNull prepend="and" property="searchKey">
sp_ksv.string_value = #searchKey#
</isNotNull>
<isNotNull prepend="and" property="searchValueString">
sp_msv.string_value = #searchValueString#
</isNotNull>
</dynamic>
order by
entry.id
</select>
</sqlMap>

View File

@@ -698,4 +698,18 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
{
throw new UnsupportedOperationException();
}
/**
* Fallout implementation from new audit DAO
*
* @throws UnsupportedOperationException always
* @since 3.2
*/
public void findAuditEntries(
AuditQueryCallback callback,
String applicationName, String user, Long from, Long to, int maxResults,
String searchKey, String searchString)
{
throw new UnsupportedOperationException();
}
}

View File

@@ -346,10 +346,20 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
String applicationName, String user, Long from, Long to, int maxResults)
{
AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback);
findAuditEntries(rowHandler, applicationName, user, from, to, maxResults);
findAuditEntries(rowHandler, applicationName, user, from, to, maxResults, null, null);
}
public void findAuditEntries(
AuditQueryCallback callback,
String applicationName, String user, Long from, Long to, int maxResults,
String searchKey, String searchString)
{
AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback);
findAuditEntries(rowHandler, applicationName, user, from, to, maxResults, searchKey, searchString);
}
protected abstract void findAuditEntries(
AuditQueryRowHandler rowHandler,
String applicationName, String user, Long from, Long to, int maxResults);
String applicationName, String user, Long from, Long to, int maxResults,
String searchKey, String searchString);
}

View File

@@ -98,4 +98,9 @@ public interface AuditDAO
void findAuditEntries(
AuditQueryCallback callback,
String applicationName, String user, Long from, Long to, int maxResults);
void findAuditEntries(
AuditQueryCallback callback,
String applicationName, String user, Long from, Long to, int maxResults,
String searchKey, String searchString);
}

View File

@@ -37,6 +37,7 @@ import org.alfresco.repo.domain.contentdata.ContentDataDAO;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
@@ -124,6 +125,13 @@ public class AuditDAOTest extends TestCase
}
public void testAuditEntry() throws Exception
{
doAuditEntryImpl(1000);
}
/**
* @return Returns the name of the application
*/
private String doAuditEntryImpl(final int count) throws Exception
{
final File file = AbstractContentTransformerTest.loadQuickTestFile("pdf");
assertNotNull(file);
@@ -140,7 +148,6 @@ public class AuditDAOTest extends TestCase
};
final Long sessionId = txnHelper.doInTransaction(createAppCallback);
final int count = 1000;
final String username = "alexi";
RetryingTransactionCallback<Void> createEntryCallback = new RetryingTransactionCallback<Void>()
{
@@ -161,5 +168,38 @@ public class AuditDAOTest extends TestCase
System.out.println(
"Time for " + count + " entry creations was " +
((double)(after - before)/(10E6)) + "ms");
// Done
return appName;
}
public void testAuditQuery() throws Exception
{
// Some entries
doAuditEntryImpl(1);
// Find everything, bug look for a specific key
final AuditQueryCallback callback = new AuditQueryCallback()
{
public boolean handleAuditEntry(
Long entryId,
String applicationName,
String user,
long time,
Map<String, Serializable> values)
{
System.out.println(values);
return true;
}
};
RetryingTransactionCallback<Void> findCallback = new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
auditDAO.findAuditEntries(callback, null, null, null, null, -1, "/a/b/c", null);
return null;
}
};
txnHelper.doInTransaction(findCallback);
}
}

View File

@@ -41,6 +41,8 @@ public class AuditQueryParameters
private Pair<String, Long> auditUserCrcPair;
private Long auditFromTime;
private Long auditToTime;
private String searchKey;
private String searchValueString;
public AuditQueryParameters()
{
@@ -56,6 +58,8 @@ public class AuditQueryParameters
.append(", auditUserCrcPair=").append(auditUserCrcPair)
.append(", auditFromTime").append(new Date(auditFromTime))
.append(", auditToTime").append(new Date(auditToTime))
.append(", searchKey").append(searchKey)
.append(", searchValueString").append(searchValueString)
.append("]");
return sb.toString();
}
@@ -119,4 +123,24 @@ public class AuditQueryParameters
{
this.auditToTime = to;
}
public String getSearchKey()
{
return searchKey;
}
public void setSearchKey(String searchKey)
{
this.searchKey = searchKey;
}
public String getSearchValueString()
{
return searchValueString;
}
public void setSearchValueString(String searchValueString)
{
this.searchValueString = searchValueString;
}
}

View File

@@ -155,11 +155,8 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
@Override
protected void findAuditEntries(
final AuditQueryRowHandler rowHandler,
String appName,
String user,
Long from,
Long to,
int maxResults)
String appName, String user, Long from, Long to, int maxResults,
String searchKey, String searchString)
{
AuditQueryParameters params = new AuditQueryParameters();
if (appName != null)
@@ -175,6 +172,8 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
}
params.setAuditFromTime(from);
params.setAuditToTime(to);
params.setSearchKey(searchKey);
params.setSearchValueString(searchString);
// RowHandlers in RowHandlers: See 'groupBy' issue https://issues.apache.org/jira/browse/IBATIS-503
RowHandler shreddedRowHandler = new RowHandler()