com.baidu.rigel.biplatform.tesseract.util.DataModelBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.baidu.rigel.biplatform.tesseract.util.DataModelBuilder.java

Source

/**
 * Copyright (c) 2014 Baidu, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baidu.rigel.biplatform.tesseract.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baidu.rigel.biplatform.ac.exception.MiniCubeQueryException;
import com.baidu.rigel.biplatform.ac.minicube.MiniCubeMeasure;
import com.baidu.rigel.biplatform.ac.query.data.DataModel;
import com.baidu.rigel.biplatform.ac.query.data.HeadField;
import com.baidu.rigel.biplatform.ac.util.DeepcopyUtils;
import com.baidu.rigel.biplatform.ac.util.MetaNameUtil;
import com.baidu.rigel.biplatform.tesseract.model.MemberNodeTree;
import com.baidu.rigel.biplatform.tesseract.qsservice.query.vo.QueryContext;
import com.baidu.rigel.biplatform.tesseract.resultset.TesseractResultSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * ?TesseractResultSetDataModel
 * 
 * @author xiaoming.chen
 *
 */
public class DataModelBuilder {

    private static final String BLANK_ROW = "blankRow";

    /**
     * log
     */
    private Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * HEAD_KEY_SPLIT
     */
    private static final String HEAD_KEY_SPLIT = "_+_";

    /** 
     * PROP_KEY_SPLIT
     */
    private static final String PROP_KEY_SPLIT = "^_^";

    /**
     * tesseractResultSet 
     */
    private TesseractResultSet tesseractResultSet;

    /**
     * queryContext ?
     */
    private QueryContext queryContext;

    /**
     * columnBaseDatas
     */
    private List<List<BigDecimal>> columnBaseDatas;

    /**
     * constructor
     * 
     * @param tesseractResultSet
     */
    public DataModelBuilder(TesseractResultSet tesseractResultSet, QueryContext queryContext) {
        if (tesseractResultSet == null) {
            log.warn("tesseractResultSet is null,return table head");
            //            throw new IllegalArgumentException("tesseractResultSet is null");
        }
        if (queryContext == null) {
            throw new IllegalArgumentException("queryContext is null");
        }
        this.tesseractResultSet = tesseractResultSet;
        this.queryContext = queryContext;
    }

    public DataModel build(boolean isContainsCallbackMeasure) throws MiniCubeQueryException {
        DataModel dataModel = new DataModel();
        /**
         * get the order of row head
         */
        List<List<String>> rowNodeName = new ArrayList<List<String>>();
        List<MemberTreePropResult> rowHeadNames = getHeadNameByOrder(queryContext.getRowMemberTrees(), rowNodeName,
                isContainsCallbackMeasure);

        /**
         * get the order of col head
         */
        List<List<String>> columnNodeName = new ArrayList<List<String>>();
        List<MemberTreePropResult> colHeadNames = getHeadNameByOrder(queryContext.getColumnMemberTrees(),
                columnNodeName, false);
        // ???KEY
        List<String> rowAxisKeys = generateAxisKeys(rowNodeName, null);
        List<String> columnAxisKeys = generateAxisKeys(columnNodeName, queryContext.getQueryMeasures());

        if (this.tesseractResultSet != null) {
            Map<String, Map<String, BigDecimal>> parseData = null;
            try {
                parseData = parseResultSet(rowHeadNames, colHeadNames);
            } catch (Exception e) {
                throw new MiniCubeQueryException("get data from resultset error.", e);
            }

            if (CollectionUtils.isNotEmpty(rowAxisKeys) && CollectionUtils.isNotEmpty(columnAxisKeys)) {
                columnBaseDatas = new ArrayList<List<BigDecimal>>(columnAxisKeys.size());
                for (int i = 0; i < columnAxisKeys.size(); i++) {
                    String columnName = columnAxisKeys.get(i);
                    if (columnBaseDatas.size() < i + 1) {
                        columnBaseDatas.add(new ArrayList<BigDecimal>(rowAxisKeys.size()));
                    }
                    if (CollectionUtils.isEmpty(rowAxisKeys)) {
                        rowAxisKeys.add(BLANK_ROW);
                    }

                    for (String rowName : rowAxisKeys) {
                        if (parseData.containsKey(rowName) && parseData.get(rowName).containsKey(columnName)) {
                            columnBaseDatas.get(i).add(parseData.get(rowName).get(columnName));
                        } else {
                            // null
                            columnBaseDatas.get(i).add(null);
                            //                            columnBaseDatas.get(i).add(BigDecimal.ZERO);
                        }
                    }
                }
            }

        }

        dataModel.setColumnBaseData(columnBaseDatas);
        dataModel.setColumnHeadFields(
                buildAxisHeadFields(queryContext.getColumnMemberTrees(), queryContext.getQueryMeasures()));
        dataModel.setRowHeadFields(buildAxisHeadFields(queryContext.getRowMemberTrees(), null));

        return dataModel;
    }

    /**
     * ?ResultSet????
     * 
     * @return ResultSet????
     * @throws Exception ?
     */
    private Map<String, Map<String, BigDecimal>> parseResultSet(List<MemberTreePropResult> rowHeadNames,
            List<MemberTreePropResult> colHeadNames) throws Exception {

        //    
        Map<String, Map<String, BigDecimal>> data = Maps.newHashMap();
        while (this.tesseractResultSet.next()) {
            StringBuilder oneLine = new StringBuilder();
            for (MemberTreePropResult rowHeadName : rowHeadNames) {

                for (String prop : rowHeadName.queryPropers.keySet()) {
                    String value = tesseractResultSet.getString(prop);
                    if (rowHeadName.queryPropers.get(prop).isEmpty()
                            || rowHeadName.queryPropers.get(prop).contains(value)) {
                        oneLine.append(prop);
                        oneLine.append(PROP_KEY_SPLIT);
                        oneLine.append(value);
                        oneLine.append(HEAD_KEY_SPLIT);
                        break;
                    }
                }
            }
            if (oneLine.length() > 1) {
                oneLine.delete(oneLine.length() - HEAD_KEY_SPLIT.length(), oneLine.length());
            } else {
                oneLine.append(BLANK_ROW);
            }
            Map<String, BigDecimal> colValues = Maps.newHashMap();
            StringBuilder oneColumn = new StringBuilder();
            for (MemberTreePropResult colHeadName : colHeadNames) {
                for (String prop : colHeadName.queryPropers.keySet()) {
                    String value = tesseractResultSet.getString(prop);
                    if (colHeadName.queryPropers.get(prop).isEmpty()
                            || colHeadName.queryPropers.get(prop).contains(value)) {
                        oneColumn.append(prop);
                        oneColumn.append(PROP_KEY_SPLIT);
                        oneColumn.append(value);
                        oneColumn.append(HEAD_KEY_SPLIT);
                        break;
                    }
                }

            }
            for (MiniCubeMeasure measure : queryContext.getQueryMeasures()) {
                StringBuilder columnKey = new StringBuilder();
                columnKey.append(oneColumn);
                columnKey.append(measure.getName());
                colValues.put(columnKey.toString(), tesseractResultSet.getBigDecimal(measure.getDefine()));
            }
            data.put(oneLine.toString(), colValues);
        }

        return data;
    }

    private List<String> generateAxisKeys(List<List<String>> nodeNames, List<MiniCubeMeasure> measures) {
        List<String> axisKeys = new ArrayList<String>();
        if (CollectionUtils.isNotEmpty(nodeNames)) {
            for (int i = 0; i < nodeNames.size(); i++) {
                axisKeys = getCrossjoinNode(axisKeys, nodeNames.get(i));
            }
        }
        if (CollectionUtils.isNotEmpty(measures)) {
            List<String> measureName = new ArrayList<String>();
            measures.forEach((measure) -> {
                measureName.add(measure.getName());
            });
            axisKeys = getCrossjoinNode(axisKeys, measureName);
        }
        return axisKeys;
    }

    private List<String> getCrossjoinNode(List<String> parentNode, List<String> nextNode) {
        if (CollectionUtils.isEmpty(parentNode)) {
            return nextNode;
        } else if (CollectionUtils.isEmpty(nextNode)) {
            return parentNode;
        }
        int size = parentNode.size() * nextNode.size();
        List<String> result = new ArrayList<String>(size);
        for (int i = 0; i < parentNode.size(); i++) {
            for (String name : nextNode) {
                result.add(parentNode.get(i) + HEAD_KEY_SPLIT + name);
            }
        }
        return result;
    }

    /**
     * ??key?
     * 
     * @param memberNodes ?
     * @param rowNodeName
     * @return KEY
     */
    private List<MemberTreePropResult> getHeadNameByOrder(List<MemberNodeTree> memberNodes,
            List<List<String>> rowNodeName, boolean isContainsCallbackMeasure) {
        List<MemberTreePropResult> headNames = Lists.newArrayList();
        for (int i = 0; i < memberNodes.size(); i++) {
            MemberNodeTree nodeTree = memberNodes.get(i);
            if (MetaNameUtil.isAllMemberName(nodeTree.getName()) && nodeTree.getChildren().isEmpty()) {
                return headNames;
            }
            MemberTreePropResult treeProp = new MemberTreePropResult();
            rowNodeName.add(getNodeName(nodeTree, null, treeProp, isContainsCallbackMeasure));
            if (MapUtils.isEmpty(treeProp.getQueryPropers())) {
                log.warn("query proper:{} is null,skip", nodeTree);
                continue;
            }
            headNames.add(treeProp);

        }
        return headNames;
    }

    /** 
     *  ?,?
     * @author xiaoming.chen
     * @version  2015116 
     * @since jdk 1.8 or after
     */
    class MemberTreePropResult {

        /** 
         * queryPropers ???VALUE
         */
        private Map<String, Set<String>> queryPropers = new LinkedHashMap<String, Set<String>>(3);

        /** 
         * ? queryPropers 
         * @return the queryPropers 
         */
        public Map<String, Set<String>> getQueryPropers() {

            return queryPropers;
        }

    }

    /**
     * ??
     * 
     * @param nodeTree 
     * @param nodeNames 
     * @return ??
     */
    private List<String> getNodeName(MemberNodeTree nodeTree, List<String> nodeNames,
            MemberTreePropResult treePropResult, boolean isContainsCallbackMeasure) {
        if (nodeNames == null) {
            nodeNames = new ArrayList<String>();
        }
        String prop = nodeTree.getQuerySource();
        if (StringUtils.isNotBlank(nodeTree.getName())) {
            final boolean allMemberName = MetaNameUtil.isAllMemberName(nodeTree.getName());
            if (allMemberName && nodeTree.getChildren().isEmpty()) {
                return nodeNames;
            }
            if (StringUtils.isNotBlank(prop)) {
                if (allMemberName && isContainsCallbackMeasure) {
                    nodeNames.add(prop + PROP_KEY_SPLIT + TesseractConstant.SUMMARY_KEY);
                } else {
                    nodeNames.add(prop + PROP_KEY_SPLIT + nodeTree.getName());
                }
                treePropResult.getQueryPropers().put(prop, new HashSet<String>());
            }
        }
        if (CollectionUtils.isNotEmpty(nodeTree.getChildren())) {
            String childProp = null;
            for (MemberNodeTree child : nodeTree.getChildren()) {
                getNodeName(child, nodeNames, treePropResult, isContainsCallbackMeasure);
                if (childProp == null) {
                    childProp = child.getQuerySource();
                }
            }
            if (StringUtils.isNotBlank(prop) && !prop.equals(childProp)) {
                treePropResult.getQueryPropers().get(prop).add(nodeTree.getName());
            }

        }
        return nodeNames;
    }

    /**
     * ????
     * 
     * @param treeNodes ??
     * @return
     */
    public static List<HeadField> buildAxisHeadFields(List<MemberNodeTree> treeNodes,
            List<MiniCubeMeasure> measures) {
        List<HeadField> result = Lists.newArrayList();
        for (MemberNodeTree nodeTree : treeNodes) {
            List<HeadField> curHeadFields = buildFieldsByMemberNodeTree(nodeTree, result.isEmpty(), null);
            if (result.isEmpty()) {
                result.addAll(curHeadFields);
            } else {
                addTailFields(result, curHeadFields);
            }
        }
        // ??????
        if (CollectionUtils.isNotEmpty(measures)) {
            List<HeadField> measureFields = new ArrayList<HeadField>(measures.size());
            measures.forEach((measure) -> {
                HeadField measureField = new HeadField(null);
                measureField.setCaption(measure.getCaption());
                measureField.setValue(measure.getUniqueName());
                measureFields.add(measureField);
            });
            // 
            addTailFields(result, measureFields);
        }

        return result;
    }

    /**
     * tailHeadFields?headFields???headField???
     * 
     * @param headFields ?
     * @param tailFields ???
     */
    private static void addTailFields(List<HeadField> headFields, List<HeadField> tailFields) {
        if (CollectionUtils.isNotEmpty(headFields)) {
            if (CollectionUtils.isNotEmpty(tailFields)) {
                headFields.forEach((node) -> {
                    List<HeadField> leafNodes = node.getLeafFileds(true);
                    for (HeadField leaf : leafNodes) {
                        // ?????
                        leaf.getNodeList()
                                .addAll(packageParentLevelField(DeepcopyUtils.deepCopy(tailFields), leaf));
                    }
                });
            }
        } else {
            headFields.addAll(tailFields);
        }
    }

    /**
     * ?parentLevelField
     * 
     * @param nodes ?
     * @param parentLevelField 
     * @return
     */
    private static List<HeadField> packageParentLevelField(List<HeadField> nodes, HeadField parentLevelField) {
        if (CollectionUtils.isNotEmpty(nodes)) {
            for (HeadField field : nodes) {
                field.setParentLevelField(parentLevelField);
                // ?UniqueName
                parentLevelField.getNodeUniqueName();
                field.getNodeUniqueName();
                packageParentLevelField(field.getChildren(), parentLevelField);
            }
        }
        return nodes;
    }

    public static List<HeadField> buildFieldsByMemberNodeTree(MemberNodeTree nodeTree, boolean isFirstNode,
            HeadField parent) {
        List<HeadField> result = Lists.newArrayList();
        HeadField node = null;
        if (StringUtils.isNotBlank(nodeTree.getName())) {
            node = buildField(nodeTree, isFirstNode, parent);
        }
        List<HeadField> children = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(nodeTree.getChildren())) {
            final HeadField parentField = node;
            nodeTree.getChildren().forEach((field) -> {
                children.addAll(buildFieldsByMemberNodeTree(field, isFirstNode, parentField));
            });
        }

        if (node != null) {
            node.setChildren(children);
            result.add(node);
            return result;
        } else {
            return children;
        }
    }

    /**
     * ?HeadField
     * 
     * @param node 
     * @return DataModel
     */
    private static HeadField buildField(MemberNodeTree node, boolean isParent, HeadField parent) {
        HeadField headField = new HeadField(null);
        headField.setCaption(node.getCaption());
        headField.setValue(node.getUniqueName());
        if (isParent) {
            headField.getNodeUniqueName();
        }
        headField.setHasChildren(node.isHasChildren());
        headField.setParent(parent);
        return headField;
    }

}