All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cdc.impex.core.ExportRowImpl Maven / Gradle / Ivy

package cdc.impex.core;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

import cdc.impex.ImpExNames;
import cdc.impex.exports.ExportIssueType;
import cdc.impex.exports.ExportIssues;
import cdc.impex.exports.ExportRow;
import cdc.impex.templates.ColumnTemplate;
import cdc.impex.templates.SheetTemplate;
import cdc.impex.templates.SheetTemplateInstance;
import cdc.issues.Issue;
import cdc.issues.IssueSeverity;
import cdc.issues.locations.WorkbookLocation;
import cdc.office.tables.Row;
import cdc.util.lang.Checks;
import cdc.validation.checkers.Checker;

/**
 * Implementation of {@link ExportRow}.
 *
 * @author Damien Carbonne
 */
public class ExportRowImpl implements ExportRow {
    public static final String CONVERSION_FAILURE = "CONVERSION FAILURE";
    public static final String MISSING_DATA = "MISSING DATA";
    private final SheetTemplateInstance templateInstance;
    private final String sheetName;
    private final String systemId;
    private final Map values = new HashMap<>();
    private final Map comments = new HashMap<>();
    private final List issues = new ArrayList<>();
    private int number = 1;

    public ExportRowImpl(SheetTemplateInstance templateInstance,
                         String sheetName,
                         String systemId) {
        this.templateInstance = templateInstance;
        this.sheetName = sheetName;
        this.systemId = systemId;
    }

    private Issue createIssue(ExportIssueType type,
                              IssueSeverity severity,
                              String description,
                              String columnName) {
        return ExportIssues.builder()
                           .name(type)
                           .severity(severity)
                           .description(description)
                           .addLocation(WorkbookLocation.builder()
                                                        .sheetName(sheetName)
                                                        .columnName(columnName)
                                                        .rowNumber(number)
                                                        .systemId(systemId)
                                                        .build())
                           .build();
    }

    private Issue createIssue(ExportIssueType type,
                              String description,
                              String columnName) {
        return createIssue(type,
                           type.getSeverity(),
                           description,
                           columnName);
    }

    private void addIssue(ExportIssueType type,
                          IssueSeverity severity,
                          String description,
                          String columnName) {
        issues.add(createIssue(type,
                               severity,
                               description,
                               columnName));
    }

    private void addIssue(ExportIssueType type,
                          String description,
                          String columnName) {
        addIssue(type,
                 type.getSeverity(),
                 description,
                 columnName);
    }

    @Override
    public SheetTemplateInstance getTemplateInstance() {
        return templateInstance;
    }

    @Override
    public SheetTemplate getTemplate() {
        return templateInstance.getTemplate();
    }

    @Override
    public String getSheetName() {
        return sheetName;
    }

    public void clear() {
        values.clear();
        issues.clear();
        comments.clear();
        setData(getTemplate().getActionColumn(), null);
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public void incrementNumber() {
        this.number++;
    }

    @Override
    public int getNumber() {
        return number;
    }

    private void setDataRaw(ColumnTemplate column,
                            String name,
                            Object data) {
        Checks.isNotNull(column, "column");
        Checks.isNotNull(name, "name");

        final StringBuilder comment = new StringBuilder();

        // Check data compliance (even if data is null)
        final Checker checker = column.getCheckerOrNull();

        if (checker != null) {
            final boolean valid = checker.testRaw(data);
            if (!valid) {
                addIssue(ExportIssueType.NON_COMPLIANT_DATA,
                         column.getCheckFailureSeverity(),
                         "Check [" + checker.explain(true, "?") + "] failed for '?'=" + data + ".",
                         name);
                comment.append("Check [" + checker.explain(true, "?") + "] failed for '?'=" + data + ".");
            }
        }

        try {
            @SuppressWarnings("unchecked")
            final String s = ((Function) column.getExportConverter()).apply(data);
            this.values.put(name, s);
        } catch (final RuntimeException e) {
            addIssue(ExportIssueType.NON_CONVERTIBLE_DATA,
                     "Failed to convert " + column.getDataType().getCanonicalName() + " '" + data + "' to String.",
                     name);
            if (comment.length() > 0) {
                comment.append('\n');
            }
            comment.append("Failed to convert " + column.getDataType().getCanonicalName() + " '" + data + "' to String.");
            if (column.getUsage().isMandatoryForFutureImport()) {
                addIssue(ExportIssueType.MISSING_MANDATORY_DATA,
                         "No data for mandatory column " + column.getHeader() + ".",
                         name);
            }
            this.values.put(name, CONVERSION_FAILURE);
        }
        if (comment.length() > 0) {
            comments.put(name, comment.toString());
        }
    }

    @Override
    public void setData(String name,
                        Object data) {
        Checks.isNotNull(name, ImpExNames.NAME);

        @SuppressWarnings("unchecked")
        final ColumnTemplate column = (ColumnTemplate) getTemplate().getMatchingColumn(name);
        if (column == null) {
            throw new IllegalArgumentException("Invalid column name '" + name + "'");
        }

        setDataRaw(column, name, data);
    }

    @Override
    public  void setData(ColumnTemplate column,
                            T data) {
        Checks.isNotNull(column, ImpExNames.COLUMN);
        column.checkIsName();

        setDataRaw(column, column.getName(), data);
    }

    @Override
    public  void setData(ColumnTemplate column,
                            String name,
                            T data) {
        Checks.isNotNull(column, ImpExNames.COLUMN);
        Checks.isTrue(column.getHeader().matches(name), "Name {} does not match {}", name, column);

        setDataRaw(column, name, data);
    }

    @Override
    public List getIssues() {
        // Copy already detected issues
        final List list = new ArrayList<>(issues);

        // Add other issues
        for (final String name : getTemplateInstance().getHeader().getSortedNames()) {
            final ColumnTemplate column = getTemplate().getMatchingColumn(name);
            if (!values.containsKey(name) && column.getUsage().isMandatoryForFutureImport()) {
                list.add(createIssue(ExportIssueType.MISSING_MANDATORY_DATA,
                                     "No data for mandatory column '" + name + "'.",
                                     name));
            }
        }
        return list;
    }

    @Override
    public boolean containsKey(String name) {
        return values.containsKey(name);
    }

    @Override
    public String getValue(String name) {
        return values.get(name);
    }

    @Override
    public boolean hasValidValue(String name) {
        return !CONVERSION_FAILURE.equals(getValue(name))
                && !MISSING_DATA.equals(getValue(name));
    }

    private static boolean isValue(String s) {
        return s != null;
    }

    @Override
    public Boolean getValueAsBoolean(String name) {
        final String value = getValue(name);
        return isValue(value) ? Boolean.valueOf(value) : null;
    }

    @Override
    public Long getValueAsLong(String name) {
        final String value = getValue(name);
        return isValue(value) ? Long.valueOf(value) : null;
    }

    @Override
    public Double getValueAsDouble(String name) {
        final String value = getValue(name);
        return isValue(value) ? Double.valueOf(value) : null;
    }

    @Override
    public BigInteger getValueAsBigInteger(String name) {
        final String value = getValue(name);
        return isValue(value) ? new BigInteger(value) : null;
    }

    @Override
    public BigDecimal getValueAsBigDecimal(String name) {
        final String value = getValue(name);
        return isValue(value) ? new BigDecimal(value) : null;
    }

    @Override
    public String getComment(String name) {
        return comments.get(name);
    }

    /**
     * @return A Row view of this export row.
     */
    public Row asTableRow() {
        final Row.Builder builder = Row.builder();
        for (final String name : getTemplateInstance().getHeader().getSortedNames()) {
            final ColumnTemplate column = getTemplate().getMatchingColumn(name);
            if (values.containsKey(name)) {
                final String s = values.get(name);
                builder.addValue(s);
            } else if (column.getUsage().isMandatoryForFutureImport()) {
                builder.addValue(MISSING_DATA);
            } else {
                builder.addValue(null);
            }
        }
        return builder.build();
    }

    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder();

        builder.append('[');
        builder.append(getTemplate().getName());
        builder.append(' ');
        builder.append(getSheetName());
        builder.append(' ');
        builder.append(getNumber());
        builder.append(' ');
        int index = 0;
        for (final String name : getTemplateInstance().getHeader().getSortedNames()) {
            if (index > 0) {
                builder.append(';');
            }
            final String value = getValue(name);
            if (value == null) {
                builder.append("null");
            } else {
                builder.append("'")
                       .append(value)
                       .append("'");

            }
            index++;
        }
        builder.append(']');

        return builder.toString();
    }
}