package com.evolveum.midpoint.model.impl.util;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PostConstruct;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.evolveum.midpoint.audit.api.AuditEventRecord;
import com.evolveum.midpoint.audit.api.AuditResultHandler;
import com.evolveum.midpoint.audit.api.AuditService;
import com.evolveum.midpoint.model.api.ModelPublicConstants;
import com.evolveum.midpoint.schema.result.OperationConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.result.OperationResultStatus;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.task.api.TaskCategory;
import com.evolveum.midpoint.task.api.TaskHandler;
import com.evolveum.midpoint.task.api.TaskManager;
import com.evolveum.midpoint.task.api.TaskRunResult;
import com.evolveum.midpoint.task.api.TaskRunResult.TaskRunResultStatus;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
@Component
public class AuditReindexTaskHandler implements TaskHandler {
static final Trace LOGGER = TraceManager.getTrace(AuditReindexTaskHandler.class);
public static final String HANDLER_URI = ModelPublicConstants.AUDIT_REINDEX_TASK_HANDLER_URI;
private static final String taskName = "AuditReindex";
private int maxResults = 20;
private int firstResult = 0;
@Autowired
protected AuditService auditService;
@Autowired
protected TaskManager taskManager;
@PostConstruct
private void initialize() {
taskManager.registerHandler(HANDLER_URI, this);
}
@Override
public TaskRunResult run(Task coordinatorTask) {
OperationResult opResult = new OperationResult(OperationConstants.AUDIT_REINDEX + ".run");
opResult.setStatus(OperationResultStatus.IN_PROGRESS);
TaskRunResult runResult = new TaskRunResult();
runResult.setOperationResult(opResult);
final Long expectedTotal = auditService.countObjects("select count(*) from RAuditEventRecord as aer where 1=1", null);
AuditResultHandler resultHandler = new AuditResultHandler() {
private AtomicInteger processedObjects = new AtomicInteger();
@Override
public boolean handle(AuditEventRecord auditRecord) {
auditService.reindexEntry(auditRecord);
processedObjects.incrementAndGet();
return true;
}
@Override
public int getProgress() {
return processedObjects.get();
}
};
if (resultHandler == null) {
// the error should already be in the runResult
return runResult;
}
try {
LOGGER.trace("{}: expecting {} objects to be processed", taskName, expectedTotal);
runResult.setProgress(0);
coordinatorTask.setProgress(0);
if (expectedTotal != null) {
coordinatorTask.setExpectedTotal(expectedTotal);
}
try {
coordinatorTask.savePendingModifications(opResult);
} catch (ObjectAlreadyExistsException e) { // other exceptions are
// handled in the outer
// try block
throw new IllegalStateException(
"Unexpected ObjectAlreadyExistsException when updating task progress/expectedTotal",
e);
}
Map<String, Object> params = new HashMap<String, Object>();
while (true) {
params.put("setFirstResult", firstResult);
params.put("setMaxResults", maxResults);
List<AuditEventRecord> records = auditService.listRecords(null, params);
if (CollectionUtils.isNotEmpty(records)){
for (AuditEventRecord record : records) {
resultHandler.handle(record);
runResult.setProgress(resultHandler.getProgress());
}
firstResult += maxResults;
maxResults = ( (expectedTotal.intValue() - firstResult) > maxResults ? maxResults : (expectedTotal.intValue() - firstResult));
} else {
break;
}
}
opResult.recordSuccess();
} catch (ObjectNotFoundException e) {
// This is bad. The resource does not exist. Permanent problem.
logErrorAndSetResult(runResult, resultHandler, "Object not found", e,
OperationResultStatus.FATAL_ERROR, TaskRunResultStatus.PERMANENT_ERROR);
return runResult;
} catch (SchemaException e) {
// Not sure about this. But most likely it is a misconfigured
// resource or connector
// It may be worth to retry. Error is fatal, but may not be
// permanent.
logErrorAndSetResult(runResult, resultHandler, "Error dealing with schema", e,
OperationResultStatus.FATAL_ERROR, TaskRunResultStatus.TEMPORARY_ERROR);
return runResult;
} catch (RuntimeException e) {
// Can be anything ... but we can't recover from that.
// It is most likely a programming error. Does not make much sense
// to retry.
logErrorAndSetResult(runResult, resultHandler, "Internal error", e,
OperationResultStatus.FATAL_ERROR, TaskRunResultStatus.PERMANENT_ERROR);
return runResult;
}
// TODO: check last handler status
runResult.setProgress(resultHandler.getProgress());
runResult.setRunResultStatus(TaskRunResultStatus.FINISHED);
String finishMessage = "Finished " + taskName + " (" + coordinatorTask + "). ";
String statistics = "Processed " + resultHandler.getProgress() + " objects";
opResult.createSubresult(OperationConstants.AUDIT_REINDEX + ".statistics")
.recordStatus(OperationResultStatus.SUCCESS, statistics);
LOGGER.info(finishMessage + statistics);
LOGGER.trace("{} run finished (task {}, run result {})", taskName, coordinatorTask, runResult);
return runResult;
}
@Override
public Long heartbeat(Task task) {
return task.getProgress();
}
@Override
public void refreshStatus(Task task) {
// TODO Auto-generated method stub
}
@Override
public String getCategoryName(Task task) {
return TaskCategory.UTIL;
}
@Override
public List<String> getCategoryNames() {
// TODO Auto-generated method stub
return null;
}
// TODO: copied from abstract search iterative handler
private TaskRunResult logErrorAndSetResult(TaskRunResult runResult, AuditResultHandler resultHandler,
String message, Throwable e, OperationResultStatus opStatus, TaskRunResultStatus status) {
LOGGER.error("{}: {}: {}", taskName, message, e.getMessage(), e);
runResult.getOperationResult().recordStatus(opStatus, message + ": " + e.getMessage(), e);
runResult.setRunResultStatus(status);
runResult.setProgress(resultHandler.getProgress());
return runResult;
}
}