package com.evolveum.midpoint.web.page.admin.reports.dto;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.wicket.Component;
import org.apache.wicket.model.IModel;
import com.evolveum.midpoint.audit.api.AuditEventRecord;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SecurityViolationException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider;
import com.evolveum.midpoint.web.session.UserProfileStorage;
import com.evolveum.midpoint.xml.ns._public.common.audit_3.AuditEventRecordType;
/**
* Created by honchar.
*/
public class AuditEventRecordProvider extends BaseSortableDataProvider<AuditEventRecordType> {
public static final String VALUE_REF_TARGET_NAMES_KEY = "valueRefTargetNames";
private static final Trace LOGGER = TraceManager.getTrace(BaseSortableDataProvider.class);
private IModel<List<AuditEventRecordType>> model;
private String auditEventQuery;
private Map<String, Object> parameters = new HashMap<>();
private static final String AUDIT_RECORDS_QUERY_CORE = "from RAuditEventRecord as aer left outer join aer.referenceValues as rv where 1=1 and ";
private static final String AUDIT_RECORDS_QUERY_COUNT = "select count(*) ";
private static final String AUDIT_RECORDS_ORDER_BY = " order by aer.timestamp desc";
private static final String SET_FIRST_RESULT_PARAMETER = "setFirstResult";
private static final String SET_MAX_RESULTS_PARAMETER = "setMaxResults";
private static final int MAX_EXPORT_ROWS_COUNT = 1000;
private boolean exportSize = false;
public AuditEventRecordProvider(Component component){
this(component, AUDIT_RECORDS_QUERY_CORE, new HashMap<String, Object>());
}
public AuditEventRecordProvider(Component component, String auditEventQuery, Map<String, Object> parameters ){
super(component);
this.auditEventQuery = auditEventQuery;
this.parameters = parameters;
initModel();
}
private void initModel(){
model = new IModel<List<AuditEventRecordType>>() {
@Override
public List<AuditEventRecordType> getObject() {
return listRecords(auditEventQuery, true);
}
@Override
public void detach() {
}
@Override
public void setObject(List<AuditEventRecordType> object) {
// TODO Auto-generated method stub
}
};
}
@Override
public Iterator<AuditEventRecordType> internalIterator(long first, long count) {
saveCurrentPage(first, count);
List<AuditEventRecordType> recordsList = listRecords(auditEventQuery, true, first, count);
return recordsList.iterator();
}
protected int internalSize() {
String query = generateFullQuery(AUDIT_RECORDS_QUERY_COUNT + auditEventQuery, false, true);
long count;
try {
count = getAuditService().countObjects(query, parameters, new OperationResult("internalSize"));
} catch (SecurityViolationException | SchemaException e) {
// TODO: proper error handling (MID-3536)
throw new SystemException(e.getMessage(), e);
}
int providerSize = ((Long)count).intValue();
return !exportSize ? providerSize : (providerSize < MAX_EXPORT_ROWS_COUNT ? providerSize : MAX_EXPORT_ROWS_COUNT);
}
private List<AuditEventRecordType> listRecords(String query, boolean orderBy){
return listRecords(query, orderBy, 0, getPage().getItemsPerPage(UserProfileStorage.TableId.PAGE_AUDIT_LOG_VIEWER));
}
private List<AuditEventRecordType> listRecords(String query, boolean orderBy, long first, long count){
String parameterQuery = generateFullQuery(query, orderBy, false);
if (parameters.containsKey(SET_FIRST_RESULT_PARAMETER)){
parameters.remove(SET_FIRST_RESULT_PARAMETER);
}
parameters.put(SET_FIRST_RESULT_PARAMETER, ((Long) first).intValue());
if (parameters.containsKey(SET_MAX_RESULTS_PARAMETER)){
parameters.remove(SET_MAX_RESULTS_PARAMETER);
}
parameters.put(SET_MAX_RESULTS_PARAMETER, ((Long) count).intValue());
List<AuditEventRecord> auditRecords;
try {
auditRecords = getAuditService().listRecords(parameterQuery, parameters,
new OperationResult("listRecords"));
} catch (SecurityViolationException | SchemaException e) {
// TODO: proper error handling (MID-3536)
throw new SystemException(e.getMessage(), e);
}
if (auditRecords == null){
auditRecords = new ArrayList<>();
}
List<AuditEventRecordType> auditRecordList = new ArrayList<>();
for (AuditEventRecord record : auditRecords){
auditRecordList.add(record.createAuditEventRecordType());
}
return auditRecordList;
}
public String getAuditEventQuery() {
return auditEventQuery;
}
public void setAuditEventQuery(String auditEventQuery) {
this.auditEventQuery = auditEventQuery;
}
private String generateFullQuery(String query, boolean orderBy, boolean isCount){
parameters = getParameters();
String valueRefFrom = constraintsValueRef(parameters) ? " left outer join aer.referenceValues as rv " : "";
if (parameters.get("changedItem") != null) {
if (isCount) {
query = "select count(*) from RAuditEventRecord as aer right join aer.changedItems as item " + valueRefFrom + " where 1=1 and ";
} else {
query = "from RAuditEventRecord as aer right join aer.changedItems as item " + valueRefFrom + " where 1=1 and ";
}
// query += "INNER JOIN aer.changedItems as item on item.record_id = aer.id WHERE 1=1 and "
// + "(item.changedItemPath = :changedItem) and ";
query += "(item.changedItemPath = :changedItem) and ";
} else {
parameters.remove("changedItem");
// query += "where 1=1 and ";
}
if (parameters.get("from") != null) {
query += "(aer.timestamp >= :from) and ";
} else {
parameters.remove("from");
}
if (parameters.get("to") != null) {
query += "(aer.timestamp <= :to) and ";
} else {
parameters.remove("to");
}
if (parameters.get("eventType") != null) {
query += "(aer.eventType = :eventType) and ";
} else {
parameters.remove("eventType");
}
if (parameters.get("eventStage") != null) {
query += "(aer.eventStage = :eventStage) and ";
} else {
parameters.remove("eventStage");
}
if (parameters.get("outcome") != null) {
query += "(aer.outcome = :outcome) and ";
} else {
parameters.remove("outcome");
}
if (parameters.get("initiatorName") != null) {
query += "(aer.initiatorOid = :initiatorName) and ";
} else {
parameters.remove("initiatorName");
}
if (parameters.get("channel") != null) {
query += "(aer.channel = :channel) and ";
} else {
parameters.remove("channel");
}
if (parameters.get("hostIdentifier") != null) {
query += "(aer.hostIdentifier = :hostIdentifier) and ";
} else {
parameters.remove("hostIdentifier");
}
if (parameters.get("targetOwnerName") != null) {
query += "(aer.targetOwnerOid = :targetOwnerName) and ";
} else {
parameters.remove("targetOwnerName");
}
if (parameters.get("targetNames") != null) {
query += "(aer.targetOid in ( :targetNames )) and ";
} else {
parameters.remove("targetNames");
}
if (parameters.get("taskIdentifier") != null) {
query += "(aer.taskIdentifier = :taskIdentifier) and ";
} else {
parameters.remove("taskIdentifier");
}
if (valueRefTargetIsNotEmpty(parameters.get(VALUE_REF_TARGET_NAMES_KEY))) {
query += "(rv.targetName.orig in ( :valueRefTargetNames )) and ";
} else {
parameters.remove(VALUE_REF_TARGET_NAMES_KEY);
}
query = query.substring(0, query.length()-5); // remove trailing " and "
if (orderBy){
query += AUDIT_RECORDS_ORDER_BY;
}
return query;
}
private boolean constraintsValueRef(Map<String, Object> parameters2) {
return valueRefTargetIsNotEmpty(parameters2.get(VALUE_REF_TARGET_NAMES_KEY));
}
private boolean valueRefTargetIsNotEmpty(Object valueRefTargetNamesParam) {
if(valueRefTargetNamesParam instanceof String) {
return StringUtils.isNotBlank((String)valueRefTargetNamesParam);
} else if(valueRefTargetNamesParam instanceof Collection){
return CollectionUtils.isNotEmpty((Collection)valueRefTargetNamesParam);
} else {
return valueRefTargetNamesParam != null;
}
}
public Map<String, Object> getParameters() {
return parameters;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
protected void saveCurrentPage(long from, long count){
}
public boolean isExportSize() {
return exportSize;
}
public void setExportSize(boolean exportSize) {
this.exportSize = exportSize;
}
}