private TableName findTableNameForHistoryTableName(final TableName historyTableName) { for (final TableName tableName : TableName.values()) { if (historyTableName.equals(tableName.getHistoryTableName())) { return tableName; } } return null; } });
@Override public UUID retrieveIdFromObject(final Long recordId, final ObjectType objectType) { final TableName tableName = TableName.fromObjectType(objectType); return nonEntitySqlDao.getIdFromObject(recordId, tableName.getTableName()); }
public static TableName fromObjectType(final ObjectType objectType) { for (final TableName tableName : values()) { if (tableName.getObjectType() != null && tableName.getObjectType().equals(objectType)) { return tableName; } } return null; }
@Override public DefaultAccountAuditLogsForObjectType getAuditLogsForAccountRecordId(final TableName tableName, final AuditLevel auditLevel, final InternalTenantContext context) { final String actualTableName; if (tableName.hasHistoryTable()) { actualTableName = tableName.getHistoryTableName().name(); // upper cased } else { actualTableName = tableName.getTableName(); } // Lazy evaluate records to minimize the memory footprint (these can yield a lot of results) // We usually always want to wrap our queries in an EntitySqlDaoTransactionWrapper... except here. // Since we want to stream the results out, we don't want to auto-commit when this method returns. final EntitySqlDao auditSqlDao = transactionalSqlDao.onDemand(EntitySqlDao.class); final Iterator<AuditLogModelDao> auditLogsForTableNameAndAccountRecordId = auditSqlDao.getAuditLogsForTableNameAndAccountRecordId(actualTableName, context); final Iterator<AuditLog> allAuditLogs = buildAuditLogsFromModelDao(auditLogsForTableNameAndAccountRecordId, context); return new DefaultAccountAuditLogsForObjectType(auditLevel, allAuditLogs); }
@Override public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception { final List<AuditLogModelDao> auditLogsViaHistoryForTargetRecordId = entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsViaHistoryForTargetRecordId(historyTableName.name(), historyTableName.getTableName().toLowerCase(), targetRecordId, context); return buildAuditLogsFromModelDao(auditLogsViaHistoryForTargetRecordId, tableName.getObjectType(), objectId); } });
if (originalTableNameForHistoryTableName != null) { objectType = originalTableNameForHistoryTableName.getObjectType(); if (TableName.ACCOUNT.equals(originalTableNameForHistoryTableName)) { final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappingsForAccountsTable(originalTableNameForHistoryTableName.getTableName(), input.getTableName().getTableName(), tenantContext); historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings)); } else if (TableName.TAG_DEFINITIONS.equals(originalTableNameForHistoryTableName)) { final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappingsForTablesWithoutAccountRecordId(originalTableNameForHistoryTableName.getTableName(), input.getTableName().getTableName(), tenantContext); historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings)); } else { final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getHistoryRecordIdIdMappings(originalTableNameForHistoryTableName.getTableName(), input.getTableName().getTableName(), tenantContext); historyRecordIdIdsCache.put(originalTableNameForHistoryTableName, RecordIdIdMappings.toMap(mappings)); objectType = input.getTableName().getObjectType(); final Iterable<RecordIdIdMappings> mappings = nonEntitySqlDao.getRecordIdIdMappings(input.getTableName().getTableName(), tenantContext); recordIdIdsCache.put(input.getTableName(), RecordIdIdMappings.toMap(mappings));
@Override public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception { final List<AuditLogModelDao> auditLogsForTargetRecordId = entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsForTargetRecordId(tableName.name(), targetRecordId, context); return buildAuditLogsFromModelDao(auditLogsForTargetRecordId, tableName.getObjectType(), auditedEntityId); } });
private List<AuditLog> doGetAuditLogsViaHistoryForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel, final InternalTenantContext context) { final TableName historyTableName = tableName.getHistoryTableName(); if (historyTableName == null) { throw new IllegalStateException("History table shouldn't be null for " + tableName); } final Long targetRecordId = nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName()); final List<AuditLog> allAuditLogs = transactionalSqlDao.execute(new EntitySqlDaoTransactionWrapper<List<AuditLog>>() { @Override public List<AuditLog> inTransaction(final EntitySqlDaoWrapperFactory<EntitySqlDao> entitySqlDaoWrapperFactory) throws Exception { final List<AuditLogModelDao> auditLogsViaHistoryForTargetRecordId = entitySqlDaoWrapperFactory.become(EntitySqlDao.class).getAuditLogsViaHistoryForTargetRecordId(historyTableName.name(), historyTableName.getTableName().toLowerCase(), targetRecordId, context); return buildAuditLogsFromModelDao(auditLogsViaHistoryForTargetRecordId, tableName.getObjectType(), objectId); } }); return filterAuditLogs(auditLevel, allAuditLogs); }
@Override public Long retrieveLastHistoryRecordIdFromTransaction(@Nullable final Long targetRecordId, final TableName tableName, final NonEntitySqlDao transactional) { // There is no caching here because the value returned changes as we add more history records, and so we would need some cache invalidation return transactional.getLastHistoryRecordId(targetRecordId, tableName.getTableName()); }
private void insertAudits(final TableName tableName, final Long entityRecordId, final Long historyRecordId, final ChangeType changeType, final InternalCallContext contextMaybeWithoutAccountRecordId) { final TableName destinationTableName = Objects.firstNonNull(tableName.getHistoryTableName(), tableName); final EntityAudit audit = new EntityAudit(destinationTableName, historyRecordId, changeType, clock.getUTCNow()); final InternalCallContext context; // Populate the account record id when creating the account record if (TableName.ACCOUNT.equals(tableName) && ChangeType.INSERT.equals(changeType)) { context = new InternalCallContext(contextMaybeWithoutAccountRecordId, entityRecordId); } else { context = contextMaybeWithoutAccountRecordId; } sqlDao.insertAuditFromTransaction(audit, context); // We need to invalidate the caches. There is a small window of doom here where caches will be stale. // TODO Knowledge on how the key is constructed is also in AuditSqlDao if (tableName.getHistoryTableName() != null) { final CacheController<Object, Object> cacheController = cacheControllerDispatcher.getCacheController(CacheType.AUDIT_LOG_VIA_HISTORY); if (cacheController != null) { final String key = buildCacheKey(ImmutableMap.<Integer, Object>of(0, tableName.getHistoryTableName(), 1, tableName.getHistoryTableName(), 2, entityRecordId)); cacheController.remove(key); } } else { final CacheController<Object, Object> cacheController = cacheControllerDispatcher.getCacheController(CacheType.AUDIT_LOG); if (cacheController != null) { final String key = buildCacheKey(ImmutableMap.<Integer, Object>of(0, tableName, 1, entityRecordId)); cacheController.remove(key); } } }
@Override @BeforeClass(groups = "fast") public void beforeClass() throws Exception { super.beforeClass(); auditLogs = ImmutableList.<AuditLog>of(createAuditLog(), createAuditLog(), createAuditLog(), createAuditLog()); objectIds = ImmutableList.<UUID>of(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID()); for (final TableName tableName : TableName.values()) { for (final UUID objectId : objectIds) { for (final AuditLog auditLog : auditLogs) { ((MockAuditDao) auditDao).addAuditLogForId(tableName, objectId, auditLog); } } } }
@Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (tableName != null ? tableName.hashCode() : 0); result = 31 * result + (targetRecordId != null ? targetRecordId.hashCode() : 0); result = 31 * result + (changeType != null ? changeType.hashCode() : 0); return result; } }
@Override public List<AuditLog> getAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel, final InternalTenantContext context) { if (tableName.hasHistoryTable()) { return doGetAuditLogsViaHistoryForId(tableName, objectId, auditLevel, context); } else { return doGetAuditLogsForId(tableName, objectId, auditLevel, context); } }
return modelDao.getTableName().getObjectType();
@Override public AuditLogModelDao map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException { final UUID id = getUUID(r, "id"); final String tableName = r.getString("table_name"); final long targetRecordId = r.getLong("target_record_id"); final String changeType = r.getString("change_type"); final DateTime createdDate = getDateTime(r, "created_date"); final String createdBy = r.getString("created_by"); final String reasonCode = r.getString("reason_code"); final String comments = r.getString("comments"); final UUID userToken = getUUID(r, "user_token"); final EntityAudit entityAudit = new EntityAudit(id, TableName.valueOf(tableName), targetRecordId, ChangeType.valueOf(changeType), createdDate); // TODO - we have the tenant_record_id but not the tenant id here final CallContext callContext = new DefaultCallContext(null, createdBy, createdDate, reasonCode, comments, userToken); return new AuditLogModelDao(entityAudit, callContext); } }
private void updateHistoryAndAudit(final String entityId, final Map<String, M> entities, final Map<String, Long> entityRecordIds, final ChangeType changeType, final InternalCallContext context) { // Make sure to re-hydrate the object (especially needed for create calls) final M reHydratedEntity = sqlDao.getById(entityId, context); final Long reHydratedEntityRecordId = sqlDao.getRecordId(entityId, context); final M entity = Objects.firstNonNull(reHydratedEntity, entities.get(entityId)); final Long entityRecordId = Objects.firstNonNull(reHydratedEntityRecordId, entityRecordIds.get(entityId)); final TableName tableName = entity.getTableName(); // Note: audit entries point to the history record id final Long historyRecordId; if (tableName.getHistoryTableName() != null) { historyRecordId = insertHistory(entityRecordId, entity, changeType, context); } else { historyRecordId = entityRecordId; } insertAudits(tableName, entityRecordId, historyRecordId, changeType, context); }
@Override public Long retrieveHistoryTargetRecordId(@Nullable final Long recordId, final TableName tableName) { return nonEntitySqlDao.getHistoryTargetRecordId(recordId, tableName.getTableName()); }
private TableName getTableNameFromObjectType(final ObjectType objectType) { for (final TableName tableName : TableName.values()) { if (objectType.equals(tableName.getObjectType())) { return tableName; } } return null; } }
@Override public Long doRetrieve(final UUID objectId, final ObjectType objectType) { final TableName tableName = TableName.fromObjectType(objectType); return nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName()); } }, objectId, objectType, cache);
private List<AuditLog> doGetAuditLogsForId(final TableName tableName, final UUID objectId, final AuditLevel auditLevel, final InternalTenantContext context) { final Long recordId = nonEntitySqlDao.getRecordIdFromObject(objectId.toString(), tableName.getTableName()); if (recordId == null) { return ImmutableList.<AuditLog>of(); } else { return getAuditLogsForRecordId(tableName, objectId, recordId, auditLevel, context); } }