Package reportgen.prototype.queryresults

Source Code of reportgen.prototype.queryresults.ResultsRow

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package reportgen.prototype.queryresults;

import reportgen.prototype.context.ContextMode;
import reportgen.prototype.context.group.ContextGroup;
import reportgen.utils.ReportException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jdom.Element;
import reportgen.prototype.context.NoNeedAtom;
import reportgen.prototype.context.Context;
import reportgen.prototype.context.ContextGeneric;
import reportgen.math.ContextFilter;
import reportgen.math.MathExpression;
import reportgen.math.MathExpressionOperand;
import reportgen.math.MathFactory;
import reportgen.math.constants.bool.MathExpressionConstValueBoolean;
import reportgen.math.constants.dateval.MathExpressionConstValueDate;
import reportgen.math.constants.doubleval.MathExpressionConstValueDouble;
import reportgen.math.constants.longval.MathExpressionConstValueLong;
import reportgen.math.constants.stringval.MathExpressionConstValueString;
import reportgen.math.agregate.agregate.AggregateFunction;
import reportgen.utils.SupportXMLRoot;

/**
* Объект - строка результатов.
* Формируется в парсере, затем передается в конструктор результатов.
* Результаты соответствуют результатам выборки и расположены последовательно,
* в том порядке, как шли в списке результатов выборки.
* Поскольку последовательность результатов выборки и результатов отчета одинаковы,
* благодаря этому результаты из строки их можно запрашивать по индексу
* не рассматривая индекс как положение результата выборки, но и как положение
* результата отчета
* index    ResultRow   CoreColumnResult    ReportColumnResult
*   0      [value]     at index 0           at index 0
*   1      [value]     at index 1           at index 1
*  ...
*   N      [value]     at index N           at index N
*
* @author axe
*/
public class ResultsRow implements Serializable, Cloneable, SupportXMLRoot {
    public static final long serialVersionUID = 1;

    public static final String ROWTAG = "results";

    private Map<Integer, Integer> normalizeScaler;
    private Map<Integer, Set> distinct;
    private Integer groupCode;

    private Object[] values;
   
    private final static Context context = new ContextGeneric(new NoNeedAtom()) {
        @Override
        public List<ContextGroup> getAvailiableGroups() {
            List<ContextGroup> avail = new ArrayList<ContextGroup>();
            avail.add(MathExpressionConstValueBoolean.GROUP);
            avail.add(MathExpressionConstValueDate.GROUP);
            avail.add(MathExpressionConstValueDouble.GROUP);
            avail.add(MathExpressionConstValueLong.GROUP);
            avail.add(MathExpressionConstValueString.GROUP);
            return avail;
        }

        @Override
        public ContextMode getContextMode() {
            return ContextMode.INPUT;
        }
    };

    public ResultsRow(int cols) {
        values = new Object[cols];
    }

    public ResultsRow(Element element) throws ReportException {
        List children = element.getChildren();
        values = new Object[children.size()];
        for(int i = 0; i<children.size(); i++) {
            Element iElement = (Element) children.get(i);
            MathExpressionOperand express = (MathExpressionOperand)
                    MathFactory.fromXml(iElement, context, new ContextFilter() {
                @Override
                public Context getChildContext(ContextGroup group) {
                    return context;
                }
            });
            values[i] = express.getValue(null);
        }
    }

    @Override
    public Element toXML() {
        Element root = new Element(ROWTAG);
        for(Object value: values) {
            MathExpression val = null;
            if(value.getClass().equals(Long.class)) {
                 val = new MathExpressionConstValueLong((Long)value, context);

            } else if(value.getClass().equals(Double.class)) {
                val = new MathExpressionConstValueDouble((Double)value, context);

            } else if(value.getClass().equals(Date.class)) {
                val = new MathExpressionConstValueDate((Date)value, context);

            } else if(value.getClass().equals(String.class)) {
                val = new MathExpressionConstValueString((String)value, context);

            } else if(value.getClass().equals(Boolean.class)) {
                val = new MathExpressionConstValueBoolean((Boolean)value, context);
               
            } else {
                throw new RuntimeException("Сохранение значения '" + value.toString() +
                        "' как результата подзапроса не поддерживается");
            }
            root.addContent(val.toXML());
        }
        return root;
    }



    public int getWidth() {
        return values.length;
    }


    public  void setValue(int index, Object value) {
        values[index] = value;
    }

    public Object getValue(int index) {
        return values[index];
    }

    @Override
    public ResultsRow clone() {
        try {
            ResultsRow row = (ResultsRow) super.clone();
            row.values = values.clone();
            return row;
        } catch (CloneNotSupportedException ex) {
            //do nothing, never happened
        }
        return null;
    }


    /**
     * Проверка, может ли строка группироваться с другой
     * @param other
     * @return
     */
    private boolean canGroupWith(final ResultsRow other, Set<Integer> groupIndicies) {
        for(Integer index : groupIndicies) {
            Object value1 = values[index];
            Object value2 = other.values[index];
            if(value1 != value2) {
                if(value1 == null
                    || value2 == null
                    || !value1.equals(value2) ) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Возвращает хеш-код группы
     * @return
     */
    private int getGroupCode(Set<Integer> groupIndicies) {
        if(groupCode == null) {
            int hash = 0;
            for(Integer index : groupIndicies) {
                Object value = values[index];
                if(value != null) {
                    hash += 100 * value.hashCode();
                }
            }
            groupCode = hash;
        }
        return groupCode;
    }


    public void initGroup(List<AggregateFunction> cols) throws ReportException {
        initGroup(cols, false);
    }

    public void initSummRow(List<AggregateFunction> cols) throws ReportException {
        initGroup(cols, true);
    }
   
    /**
     * Инициализирует первую строку в группе, изменяя для некоторых
     * столбцов тип значения, соответственно функции столбца
     */
    private void initGroup(List<AggregateFunction> cols, boolean clearAsis) throws ReportException {
        //init normalizer
        normalizeScaler = new HashMap<Integer, Integer>();
        //init columns
        for(int i=0; i<cols.size(); i ++) {
            AggregateFunction col = cols.get(i);

            if(col.equals(AggregateFunction.COUNT)) {
                if(values[i] != null) {
                    values[i] = new Long(1);
                } else {
                    values[i] = new Long(0);
                }

            } else if(col.equals(AggregateFunction.COUNT_DISTINCT)) {
                if(distinct == null) {
                    distinct = new HashMap<Integer, Set>();
                }
                Set set = new HashSet();
                if(values[i] != null) {
                    set.add(values[i]);
                    values[i] = new Long(1);
                } else {
                    values[i] = new Long(0);
                }
                distinct.put(i, set);

            } else if(col.equals(AggregateFunction.AVG)) {
                Object value = values[i]; //always be Long or Double
               
                if(value instanceof Long) {
                    values[i] = new Double(((Long)value).doubleValue());
               
                } else if (value instanceof Double) {
                    //fit, do nothing
               
                } else {
                    throw new ReportException("Невозможно инициализировать группу при рассчете среднего значения для класса "
                            + value.getClass().getSimpleName());
                }
                normalizeScaler.put(i, 1);

            } else if(clearAsis
                    && col.equals(AggregateFunction.ASIS)) {
                values[i] = new String("-");
            }
        }
    }

    /**
    * Добавляет строку в слияние (группу)
     * @param newRow строка которую нужно слить
     * @param groupIndicies индексы столбцов по которым осуществляется группировка
     *          null, если априори известно что строки нужно слить
     * @param cols массив функций слияния столбцов
     * @return
     * @throws reportgen.ren.exception.ReportException
     */
    public boolean merge(ResultsRow newRow, Set<Integer> groupIndicies,
            List<AggregateFunction> cols) throws ReportException {
       
        if(groupIndicies != null
                && (getGroupCode(groupIndicies) != newRow.getGroupCode(groupIndicies)
                    || !canGroupWith(newRow, groupIndicies))) {
            return false;
        }

        for(int i=0; i< cols.size(); i++) {
            AggregateFunction col = cols.get(i);
            Object value = newRow.values[i];
            //null values not take apart in group merging
            if(value == null) {
                continue;
            }

            if(col.equals(AggregateFunction.SUM)) {
                values[i] = sum(values[i], value);

            } else if(col.equals(AggregateFunction.AVG)) {
                Double dval = null;
                if(value instanceof Long) {
                    dval = new Double(((Long) value).doubleValue());
                } else if(value instanceof Double) {
                    dval = (Double) value;
                } else {
                    throw new ReportException("Невозможно рассчитать среднее значение для класса "
                            + value.getClass().getSimpleName());
                }
                values[i] = (Double) sum(values[i], dval);

                //update scaler
                Integer scaler = normalizeScaler.get(i);
                normalizeScaler.put(i, scaler+1);

            } else if(col.equals(AggregateFunction.COUNT)) {
                values[i] = (Long) values[i] + 1;

            } else if(col.equals(AggregateFunction.COUNT_DISTINCT)) {
                Set set = distinct.get(i);
                if(!set.contains(value)) {
                    set.add(value);
                    values[i] = (Long) values[i] + 1;
                }

            } else if(col.equals(AggregateFunction.MAX)) {
                if(compare(values[i], value) < 0) {
                    values[i] = value;
                }

            } else if(col.equals(AggregateFunction.MIN)) {
                if(compare(values[i], value) > 0) {
                    values[i] = value;
                }
            }
        }     
        return true;
    }

    private Object sum(Object value1, Object value2) throws ReportException {
        if(value1.getClass() != value2.getClass()) {
            throw new ReportException("Внутренняя ошибка, типы данных в разных строках результатов не совпадают");
        }
        Class cls = value1.getClass();
        if(cls.equals(Double.class)) {
            Double val = (Double)value1 + (Double)value2;
            return val;

        } else if(cls.equals(Long.class)) {
            Long val = (Long)value1 + (Long)value2;
            return val;

        } else {
            throw new ReportException("Внутренняя ошибка, неизвестный тип данных результах отчетов: " + cls.getSimpleName());               
        }          
    }

    /**
     * Сравнивает два объекта
     * @param value1
     * @param value2
     * @return
     * @throws beans.reportgen.ren.ReportException
     */
    private int compare(Object value1, Object value2) throws ReportException {
        if(value1.getClass() != value2.getClass()) {
            throw new ReportException("Внутренняя ошибка, типы данных в разных строках результатов не совпадают");
        }
        Class cls = value1.getClass();
        if(cls.equals(Double.class)) {
            return ((Double)value1).compareTo((Double)value2);

        } else if(cls.equals(Long.class)) {
            return ((Long)value1).compareTo((Long)value2);

        } else {
            throw new ReportException("Внутренняя ошибка, невозможно сравнить данные результов отчета: " + cls.getSimpleName());               
        }          
    }        


    /**
     * Нормализует значение сгруппированных значений строки
     */
    public void normalize(List<AggregateFunction> cols) throws ReportException {
        for(Integer col: normalizeScaler.keySet()) {
            values[col] = normalize(values[col], normalizeScaler.get(col));
        }            
    }

    /**
     * Нормализует значение сгруппировонной колонки
     * @param value
     * @return
     * @throws beans.reportgen.ren.ReportException
     */
    private Object normalize(Object value, int count) throws ReportException {
        Class cls = value.getClass();
        if(cls.equals(Double.class)) {
            Double val = ((Double)value)/count;
            return val;
        } else if(cls.equals(Long.class)) {
            Long val = ((Long)value)/count;
            return val;
        } else {
            throw new ReportException("Внутренняя ошибка, неизвестный тип данных при нормализации результатов отчета: " + cls.getSimpleName());
        }
    }
}
TOP

Related Classes of reportgen.prototype.queryresults.ResultsRow

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.