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

com.gooddata.md.visualization.VisualizationConverter Maven / Gradle / Ivy

/*
 * Copyright (C) 2018, GoodData(R) Corporation. All rights reserved.
 * This source code is licensed under the BSD-style license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */
package com.gooddata.md.visualization;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gooddata.executeafm.Execution;
import com.gooddata.executeafm.afm.Afm;
import com.gooddata.executeafm.afm.AttributeItem;
import com.gooddata.executeafm.afm.CompatibilityFilter;
import com.gooddata.executeafm.afm.DateFilter;
import com.gooddata.executeafm.afm.FilterItem;
import com.gooddata.executeafm.afm.MeasureItem;
import com.gooddata.executeafm.afm.NegativeAttributeFilter;
import com.gooddata.executeafm.afm.PositiveAttributeFilter;
import com.gooddata.executeafm.afm.SimpleMeasureDefinition;
import com.gooddata.executeafm.resultspec.Dimension;
import com.gooddata.executeafm.resultspec.ResultSpec;
import com.gooddata.executeafm.resultspec.SortItem;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.gooddata.executeafm.resultspec.Dimension.MEASURE_GROUP;
import static com.gooddata.md.visualization.CollectionType.SEGMENT;
import static com.gooddata.md.visualization.CollectionType.STACK;
import static com.gooddata.md.visualization.CollectionType.TREND;
import static com.gooddata.md.visualization.CollectionType.VIEW;
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.Validate.notNull;

/**
 * Helper class for converting {@link VisualizationObject} into {@link Execution}
 */
public abstract class VisualizationConverter {
    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * Generate Execution from Visualization object.
     *
     * @param visualizationObject which will be converted to {@link Execution}
     * @param visualizationClassGetter {@link Function} for fetching VisualizationClass, which is necessary for correct generation of {@link ResultSpec}
     * @return {@link Execution} object
     *
     * @see #convertToAfm(VisualizationObject)
     * @see #convertToResultSpec(VisualizationObject, Function)
     */
    public static Execution convertToExecution(final VisualizationObject visualizationObject, final Function visualizationClassGetter) {
        ResultSpec resultSpec = convertToResultSpec(visualizationObject, visualizationClassGetter);
        Afm afm = convertToAfm(visualizationObject);
        return new Execution(afm, resultSpec);
    }

    /**
     * Generate Afm from Visualization object.
     *
     * @param visualizationObject which will be converted to {@link Execution}
     * @return {@link Afm} object
     */
    public static Afm convertToAfm(final VisualizationObject visualizationObject) {
        final List attributes = convertAttributes(visualizationObject.getAttributes());
        final List filters = convertFilters(visualizationObject.getFilters());
        final List measures = convertMeasures(visualizationObject.getMeasures());

        return new Afm(attributes, filters, measures, null);
    }

    /**
     * Generate ResultSpec from Visualization object. Currently {@link ResultSpec}'s {@link Dimension}s can be generated
     * for table and four types of chart: bar, column, line and pie.
     *
     * @param visualizationObject which will be converted to {@link Execution}
     * @param visualizationClassGetter {@link Function} for fetching VisualizationClass, which is necessary for correct generation of {@link ResultSpec}
     * @return {@link Execution} object
     */
    public static ResultSpec convertToResultSpec(final VisualizationObject visualizationObject,
                                          final Function visualizationClassGetter) {
        VisualizationClass visualizationClass = notNull(visualizationClassGetter).apply(notNull(visualizationObject).getVisualizationClassUri());

        List sorts = getSorting(visualizationObject);
        List dimensions = getDimensions(visualizationObject, visualizationClass.getVisualizationType());
        return new ResultSpec(dimensions, sorts);
    }

    static List getSorting(final VisualizationObject visualizationObject) {
        try {
             List sorts = parseSorting(visualizationObject.getProperties());
             if (sorts != null) {
                 return sorts;
             }
        } catch (Exception ignored) {}

        return null;
    }

    static List parseSorting(final String properties) throws Exception {
        JsonNode jsonProperties = parseProperties(properties);
        JsonNode nodeSortItems = jsonProperties.get("sortItems");
        TypeReference> mapType = new TypeReference>() {};
        return MAPPER.convertValue(nodeSortItems, mapType);
    }

    private static List getDimensions(final VisualizationObject visualizationObject,
                                                 final VisualizationType visualizationType) {
        switch (visualizationType) {
            case COLUMN:
            case BAR:
                return getDimensionsForStacked(visualizationObject, STACK, VIEW);
            case LINE:
                return getDimensionsForStacked(visualizationObject, SEGMENT, TREND);
            case PIE:
                return getDimensionsForPie(visualizationObject);
            default:
                return getDimensionsForTable(visualizationObject);
        }
    }

    private static List getDimensionsForPie(final VisualizationObject visualizationObject) {
        VisualizationAttribute attribute = visualizationObject.getView();

        List dimensions = new ArrayList<>();

        if (visualizationObject.hasMeasures()) {
            dimensions.add(new Dimension(MEASURE_GROUP));
        }

        if (attribute != null) {
            dimensions.add(new Dimension(attribute.getLocalIdentifier()));
        }

        return dimensions;
    }

    private static List getDimensionsForStacked(final VisualizationObject visualizationObject,
                                                           final CollectionType stackBy,
                                                           final CollectionType viewBy) {
        VisualizationAttribute stack = visualizationObject.getAttributeFromCollection(stackBy);
        VisualizationAttribute view = visualizationObject.getAttributeFromCollection(viewBy);

        List dimensions = new ArrayList<>();

        if (stack != null) {
            dimensions.add(new Dimension(stack.getLocalIdentifier()));

            List dimensionItems = new ArrayList<>();

            if (view != null) {
                dimensionItems.add(view.getLocalIdentifier());
            }

            if (visualizationObject.hasMeasures()) {
                dimensionItems.add(MEASURE_GROUP);
            }

            if (!dimensionItems.isEmpty()) {
                dimensions.add(new Dimension(dimensionItems));
            }
        } else {
            if (visualizationObject.hasMeasures()) {
                dimensions.add(new Dimension(MEASURE_GROUP));
            }

            if (view != null) {
                dimensions.add(new Dimension(view.getLocalIdentifier()));
            }
        }

        return dimensions;
    }

    private static List getDimensionsForTable(final VisualizationObject visualizationObject) {
        List dimensions = new ArrayList<>();

        List attributes = visualizationObject.getAttributes();

        if (!attributes.isEmpty()) {
            dimensions.add(new Dimension(attributes.stream()
                    .map(VisualizationAttribute::getLocalIdentifier)
                    .collect(toList())
            ));
        } else {
            dimensions.add(new Dimension(new ArrayList<>()));
        }

        if (visualizationObject.hasMeasures()) {
            dimensions.add(new Dimension(MEASURE_GROUP));
        }

        return dimensions;
    }

    private static JsonNode parseProperties(final String properties) throws Exception {
        return MAPPER.readValue(properties, JsonNode.class);
    }

    private static List convertAttributes(final List attributes) {
        return attributes.stream()
                .map(AttributeItem.class::cast)
                .collect(toList());
    }

    private static List convertFilters(final List filters) {
        if (filters == null) {
            return new ArrayList<>();
        }

        List validFilters = removeIrrelevantFilters(filters);
        return getCompatibilityFilters(validFilters);
    }

    private static List convertMeasures(final List measures) {
        return measures.stream()
                .map(VisualizationConverter::removeFormat)
                .map(VisualizationConverter::getAfmMeasure)
                .map(VisualizationConverter::convertMeasureFilters)
                .collect(toList());
    }

    private static Measure removeFormat(final Measure measure) {
        if (measure.hasComputeRatio()) {
            measure.setFormat("");
        }

        return measure;
    }

    private static MeasureItem getAfmMeasure(final Measure measure) {
        String alias = measure.getAlias();
        String usedTitle = alias;
        if(alias == null || alias.isEmpty()) {
            if (measure.getTitle() != null) {
                usedTitle = measure.getTitle();
            }
        }
        return new MeasureItem(measure.getDefinition(), measure.getLocalIdentifier(), usedTitle, measure.getFormat());
    }

    private static MeasureItem convertMeasureFilters(final MeasureItem measure) {
        if (measure.getDefinition() instanceof SimpleMeasureDefinition) {
            List filters = ((SimpleMeasureDefinition) measure.getDefinition()).getFilters();

            List validFilters;
            if (filters == null) {
                validFilters = new ArrayList<>();
            } else {
                validFilters = removeIrrelevantFilters(filters);
            }

            ((SimpleMeasureDefinition) measure.getDefinition()).setFilters(validFilters);
        }

        return measure;
    }


    private static List getCompatibilityFilters(final List filters) {
        return (List)(List) filters;
    }

    private static List removeIrrelevantFilters(final List filters) {
        return filters.stream()
                .filter((f) -> {
                    if (f instanceof DateFilter) {
                        return !((DateFilter) f).isAllTimeSelected();
                    } else if (f instanceof NegativeAttributeFilter) {
                        return !((NegativeAttributeFilter) f).isAllSelected();
                    } else if (f instanceof PositiveAttributeFilter) {
                        return true;
                    }

                    return false;
                })
                .collect(Collectors.toList());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy