/*
* codjo.net
*
* Common Apache License 2.0
*/
package net.codjo.segmentation.server.participant;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.Connection;
import java.sql.SQLException;
import net.codjo.expression.ExpressionException;
import net.codjo.segmentation.common.MidAuditKey;
import net.codjo.segmentation.server.blackboard.message.Level;
import net.codjo.segmentation.server.blackboard.message.Todo;
import net.codjo.segmentation.server.participant.common.ComputeException;
import net.codjo.segmentation.server.participant.common.ExpressionsEvaluator;
import net.codjo.segmentation.server.participant.common.Page;
import net.codjo.segmentation.server.participant.common.SegmentationResult;
import net.codjo.segmentation.server.participant.context.ContextManager;
import net.codjo.segmentation.server.participant.context.SegmentationContext;
import net.codjo.segmentation.server.participant.context.SegmentationReport;
import net.codjo.segmentation.server.participant.context.TaskTemplate;
import net.codjo.segmentation.server.participant.context.TodoContent;
import net.codjo.segmentation.server.preference.family.Row;
import net.codjo.segmentation.server.preference.family.RowFilter;
import net.codjo.segmentation.server.preference.family.XmlFamilyPreference;
import net.codjo.workflow.common.message.Arguments;
/**
*
*/
public class CalculatorParticipant extends BackOfficeSegmentationParticipant {
public CalculatorParticipant(ContextManager contextManager) {
super(contextManager, TransactionType.TRANSACTIONAL, SegmentationLevels.TO_COMPUTE);
}
@Override
protected void handleTodo(final Todo<TodoContent> todo, final Level fromLevel, final Connection connection) {
final SegmentationReport report = getReport(todo);
new TaskTemplate(report, getName()) {
@Override
protected void doRun() throws Exception {
final SegmentationContext context = contextManager.getSegmentationContext(todo);
final XmlFamilyPreference familyPreference = context.getFamilyPreference();
final ExpressionsEvaluator expressionsEvaluator = context.createExpressionsEvaluator();
final SegmentationResult segmentationResult = context.createSegmentationResult(connection);
try {
final int pageId = todo.getContent().getPageId();
final Page page = context.removePage(pageId);
final int nbRows = page.getRowCount();
final int[] filterIndex = {-1};
for (int i = 0; i < nbRows; i++) {
final Row row = page.getRow(i);
new TaskTemplate(report, "row") {
@Override
protected void doRun() throws Exception {
filterIndex[0] = determineFilterIndex(filterIndex[0], familyPreference, row);
if (!isFiltered(familyPreference, context, row, filterIndex[0])) {
Row resultRow = expressionsEvaluator.compute(row);
segmentationResult.add(resultRow);
}
}
@Override
protected void handleComputeException(ComputeException exception) throws SQLException {
if (logger.isDebugEnabled()) {
logComputeError(todo, exception, row);
}
segmentationResult.addError(exception);
}
}.runComputation();
}
}
finally {
segmentationResult.close();
}
send(write(createTodoAudit(fromLevel, familyPreference),
SegmentationLevels.INFORMATION)
.then()
.erase(todo, fromLevel));
}
@Override
protected void handleException(Exception e) {
logger.fatal("Calcul en erreur de " + todo.getContent(), e);
send(informOfFailure(todo, fromLevel).dueTo(e));
}
}.run();
}
private void logComputeError(Todo<TodoContent> todo, ComputeException computeError, Row row) {
StringBuilder result = new StringBuilder();
result.append("Erreur de calcul ").append(todo.getContent()).append('\n')
.append("\t * Ligne en erreur : ").append(row).append('\n')
.append("\t * Ligne resultat : ").append(computeError.getResultRow()).append('\n');
if (computeError.getExpressionException() != null) {
ExpressionException root = computeError.getExpressionException();
for (int i = 0; i < root.getNbError(); i++) {
Exception exception = root.getException(i);
StringWriter stackTrace = new StringWriter();
exception.printStackTrace(new PrintWriter(stackTrace));
result.append("\t *").append(root.getMessage(i)).append('\n')
.append(stackTrace).append('\n');
}
}
logger.debug(result.toString());
}
private int determineFilterIndex(int filterIndex, XmlFamilyPreference familyPreference, Row row) {
if (!familyPreference.hasFilter()) {
return -1;
}
if (filterIndex != -1) {
return filterIndex;
}
RowFilter filter = familyPreference.getFilter();
return row.findColumnIndex(filter.getTableName(), filter.getColumnName());
}
private boolean isFiltered(XmlFamilyPreference familyPreference,
SegmentationContext context,
Row row,
int filterIndex) {
if (filterIndex == -1) {
return false;
}
RowFilter filter = familyPreference.getFilter();
Object value = row.getColumnValue(filterIndex);
//noinspection unchecked
return filter.isRowExcluded(context.getSegmentationId(), row, value);
}
private Todo<Arguments> createTodoAudit(Level level, XmlFamilyPreference familyPreference) {
Arguments arguments = createAudit(new String[][]{
{MidAuditKey.LEVEL_KEY, level.getName()},
{MidAuditKey.FAMILY_KEY, familyPreference.getFamilyId()}
});
return new Todo<Arguments>(arguments);
}
}