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

org.dashbuilder.dataset.client.engine.ClientIntervalBuilderDynamicDate Maven / Gradle / Ivy

There is a newer version: 7.74.1.Final
Show newest version
/*
 * Copyright 2014 Red Hat, Inc. and/or its affiliates.
 *
 * 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 org.dashbuilder.dataset.client.engine;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import org.dashbuilder.dataset.DataColumn;
import org.dashbuilder.dataset.DataSet;
import org.dashbuilder.dataset.date.Quarter;
import org.dashbuilder.dataset.engine.DataSetHandler;
import org.dashbuilder.dataset.engine.group.IntervalBuilder;
import org.dashbuilder.dataset.engine.group.IntervalList;
import org.dashbuilder.dataset.group.ColumnGroup;
import org.dashbuilder.dataset.group.DateIntervalType;
import org.dashbuilder.dataset.group.Interval;
import org.dashbuilder.dataset.sort.ColumnSort;
import org.dashbuilder.dataset.sort.DataSetSort;
import org.dashbuilder.dataset.sort.SortOrder;
import org.dashbuilder.dataset.sort.SortedList;

import static org.dashbuilder.dataset.group.DateIntervalType.*;

/**
 * Interval builder for date columns which generates intervals depending on the underlying data available.
 */
@ApplicationScoped
public class ClientIntervalBuilderDynamicDate implements IntervalBuilder {

    private ClientDateFormatter dateFormatter;

    public ClientIntervalBuilderDynamicDate() {
    }

    @Inject
    public ClientIntervalBuilderDynamicDate(ClientDateFormatter dateFormatter) {
        this.dateFormatter = dateFormatter;
    }

    public IntervalList build(DataSetHandler handler, ColumnGroup columnGroup) {
        IntervalDateRangeList results = new IntervalDateRangeList(columnGroup);
        DataSet dataSet = handler.getDataSet();
        List values = dataSet.getColumnById(columnGroup.getSourceId()).getValues();
        if (values.isEmpty()) {
            return results;
        }

        // Sort the column dates.
        DataSetSort sortOp = new DataSetSort();
        sortOp.addSortColumn(new ColumnSort(columnGroup.getSourceId(), SortOrder.ASCENDING));
        DataSetHandler sortResults = handler.sort(sortOp);
        List sortedRows = sortResults.getRows();
        if (sortedRows == null || sortedRows.isEmpty()) {
            return results;
        }

        // Get the lower & upper limits.
        SortedList sortedValues = new SortedList(values, sortedRows);
        Date minDate = null;
        Date maxDate = null;
        for (int i = 0; minDate == null && i < sortedValues.size(); i++) {
            minDate = (Date) sortedValues.get(i);
        }
        for (int i = sortedValues.size()-1; maxDate == null && i >= 0; i--) {
            maxDate = (Date) sortedValues.get(i);
        }

        // If min/max are equals then create a single interval.
        DateIntervalType intervalType = calculateIntervalSize(minDate, maxDate, columnGroup);
        if (minDate == null || minDate.compareTo(maxDate) == 0) {
            IntervalDateRange interval = new IntervalDateRange(0, intervalType, minDate, maxDate);
            for (int row = 0; row < sortedValues.size(); row++) interval.getRows().add(row);
            results.add(interval);

            results.setIntervalType(columnGroup.getIntervalSize());
            results.setMinValue(minDate);
            results.setMaxValue(maxDate);
            return results;
        }

        // Create the intervals according to the min/max dates.
        Date intervalMinDate = firstIntervalDate(intervalType, minDate, columnGroup);
        int index = 0;
        int counter = 0;
        while (intervalMinDate.compareTo(maxDate) <= 0) {

            // Go to the next interval
            Date intervalMaxDate = nextIntervalDate(intervalMinDate, intervalType, 1);

            // Create the interval.
            IntervalDateRange interval = new IntervalDateRange(counter++, intervalType, intervalMinDate, intervalMaxDate);
            results.add(interval);

            // Add the target rows to the interval.
            boolean stop = false;
            while (!stop) {
                if (index >= sortedValues.size()) {
                    stop = true;
                } else {
                    Date dateValue = (Date) sortedValues.get(index);
                    Integer row = sortedRows.get(index);
                    if (dateValue == null) {
                        index++;
                    } else if (dateValue.before(intervalMaxDate)) {
                        interval.getRows().add(row);
                        index++;
                    } else {
                        stop = true;
                    }
                }
            }
            // Move to the next interval.
            intervalMinDate = intervalMaxDate;
        }

        // Reverse intervals if requested
        boolean asc = columnGroup.isAscendingOrder();
        if (!asc) Collections.reverse( results );

        results.setIntervalType(intervalType.toString());
        results.setMinValue(minDate);
        results.setMaxValue(maxDate);
        return results;
    }

    public IntervalList build(DataColumn dataColumn) {
        ColumnGroup columnGroup = dataColumn.getColumnGroup();
        Date minDate = (Date) dataColumn.getMinValue();
        Date maxDate = (Date) dataColumn.getMaxValue();

        IntervalDateRangeList results = new IntervalDateRangeList(columnGroup);
        if (minDate == null || maxDate == null) {
            return results;
        }
        DateIntervalType intervalType = DateIntervalType.getByName(dataColumn.getIntervalType());
        if (intervalType == null) {
            intervalType = DateIntervalType.YEAR;
        }
        Date intervalMinDate = firstIntervalDate(intervalType, minDate, columnGroup);
        int counter = 0;
        while (intervalMinDate.compareTo(maxDate) <= 0) {

            // Go to the next interval
            Date intervalMaxDate = nextIntervalDate(intervalMinDate, intervalType, 1);

            // Create the interval.
            IntervalDateRange interval = new IntervalDateRange(counter++, intervalType, intervalMinDate, intervalMaxDate);
            results.add(interval);

            // Move to the next interval.
            intervalMinDate = intervalMaxDate;
        }

        // Reverse intervals if requested
        boolean asc = columnGroup.isAscendingOrder();
        if (!asc) Collections.reverse( results );

        results.setIntervalType(intervalType.toString());
        results.setMinValue(minDate);
        results.setMaxValue(maxDate);
        return results;
    }

    public DateIntervalType calculateIntervalSize(Date minDate, Date maxDate, ColumnGroup columnGroup) {

        DateIntervalType intervalType = DateIntervalType.getByName(columnGroup.getIntervalSize());
        if (intervalType == null) {
            intervalType = YEAR;
        }

        if (minDate == null || maxDate == null) {
            return intervalType;
        }

        long millis = (maxDate.getTime() - minDate.getTime());
        if (millis <= 0) {
            return intervalType;
        }

        // Calculate the interval type used according to the constraints set.
        int maxIntervals = columnGroup.getMaxIntervals();
        if (maxIntervals < 1) maxIntervals = 15;
        for (DateIntervalType type : values()) {
            long nintervals = millis / getDurationInMillis(type);
            if (nintervals < maxIntervals) {
                intervalType = type;
                break;
            }
        }

        // Ensure the interval mode obtained is always greater or equals than the preferred interval size.
        DateIntervalType intervalSize = null;
        String preferredSize = columnGroup.getIntervalSize();
        if (preferredSize != null && preferredSize.trim().length() > 0) {
            intervalSize = getByName(columnGroup.getIntervalSize());
        }
        if (intervalSize != null && compare(intervalType, intervalSize) == -1) {
            intervalType = intervalSize;
        }
        return intervalType;
    }

    protected Date firstIntervalDate(DateIntervalType intervalType, Date minDate, ColumnGroup columnGroup) {
        Date intervalMinDate = new Date(minDate.getTime());
        if (YEAR.equals(intervalType)) {
            intervalMinDate.setMonth(0);
            intervalMinDate.setDate(1);
            intervalMinDate.setHours(0);
            intervalMinDate.setMinutes(0);
            intervalMinDate.setSeconds(0);
        }
        if (QUARTER.equals(intervalType)) {
            int currentMonth = intervalMinDate.getMonth();
            int firstMonthYear = columnGroup.getFirstMonthOfYear().getIndex();
            int rest = Quarter.getPositionInQuarter(firstMonthYear, currentMonth + 1);
            intervalMinDate.setMonth(currentMonth - rest);
            intervalMinDate.setDate(1);
            intervalMinDate.setHours(0);
            intervalMinDate.setMinutes(0);
            intervalMinDate.setSeconds(0);
        }
        if (MONTH.equals(intervalType)) {
            intervalMinDate.setDate(1);
            intervalMinDate.setHours(0);
            intervalMinDate.setMinutes(0);
            intervalMinDate.setSeconds(0);
        }
        if (DAY.equals(intervalType) || DAY_OF_WEEK.equals(intervalType) || WEEK.equals(intervalType)) {
            intervalMinDate.setHours(0);
            intervalMinDate.setMinutes(0);
            intervalMinDate.setSeconds(0);
        }
        if (HOUR.equals(intervalType)) {
            intervalMinDate.setMinutes(0);
            intervalMinDate.setSeconds(0);
        }
        if (MINUTE.equals(intervalType)) {
            intervalMinDate.setSeconds(0);
        }
        return intervalMinDate;
    }

    protected Date nextIntervalDate(Date intervalMinDate, DateIntervalType intervalType, int intervals) {
        Date intervalMaxDate = new Date(intervalMinDate.getTime());

        if (MILLENIUM.equals(intervalType)) {
            intervalMaxDate.setYear(intervalMinDate.getYear() + 1000 * intervals);
        }
        else if (CENTURY.equals(intervalType)) {
            intervalMaxDate.setYear(intervalMinDate.getYear() + 100 * intervals);
        }
        else if (DECADE.equals(intervalType)) {
            intervalMaxDate.setYear(intervalMinDate.getYear() + 10 * intervals);
        }
        else if (YEAR.equals(intervalType)) {
            intervalMaxDate.setYear(intervalMinDate.getYear() +  intervals);
        }
        else if (QUARTER.equals(intervalType)) {
            intervalMaxDate.setMonth(intervalMinDate.getMonth() + 3 * intervals);
        }
        else if (MONTH.equals(intervalType)) {
            intervalMaxDate.setMonth(intervalMinDate.getMonth() + intervals);
        }
        else if (WEEK.equals(intervalType)) {
            intervalMaxDate.setDate(intervalMinDate.getDate() + 7 * intervals);
        }
        else if (DAY.equals(intervalType) || DAY_OF_WEEK.equals(intervalType)) {
            intervalMaxDate.setDate(intervalMinDate.getDate() + intervals);
        }
        else if (HOUR.equals(intervalType)) {
            intervalMaxDate.setHours(intervalMinDate.getHours() + intervals);
        }
        else if (MINUTE.equals(intervalType)) {
            intervalMaxDate.setMinutes(intervalMinDate.getMinutes() + intervals);
        }
        else if (SECOND.equals(intervalType)) {
            intervalMaxDate.setSeconds(intervalMinDate.getSeconds() + intervals);
        }
        else {
            // Default to year to avoid infinite loops
            intervalMaxDate.setYear(intervalMinDate.getYear() + intervals);
        }
        return intervalMaxDate;
    }

    /**
     * A list containing date range intervals.
     */
    public class IntervalDateRangeList extends IntervalList {

        public IntervalDateRangeList(ColumnGroup columnGroup) {
            super(columnGroup);
        }

        public Interval locateInterval(Object value) {
            Date d = (Date) value;
            for (Interval interval : this) {
                IntervalDateRange dateRange = (IntervalDateRange) interval;
                if (d.equals(dateRange.getMinDate()) || (d.after(dateRange.getMinDate()) && d.before(dateRange.getMaxDate()))) {
                    return interval;
                }
            }
            return null;
        }
    }

    /**
     * A date interval holding dates belonging to a given range.
     */
    public class IntervalDateRange extends Interval {

        public IntervalDateRange(int index, DateIntervalType intervalType, Date minDate, Date maxDate) {
            super(calculateName(intervalType, minDate));
            super.setMinValue(minDate);
            super.setMaxValue(maxDate);
            super.setIndex(index);
            super.setType(intervalType != null ? intervalType.toString() : null);
        }

        public Date getMinDate() {
            return (Date) minValue;
        }

        public Date getMaxDate() {
            return (Date) maxValue;
        }
    }

    public String calculateName(DateIntervalType intervalType, Date d) {
        if (MILLENIUM.equals(intervalType) || CENTURY.equals(intervalType)
                || DECADE.equals(intervalType) || YEAR.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy");
        }
        if (QUARTER.equals(intervalType) || MONTH.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy-MM");
        }
        if (WEEK.equals(intervalType) || DAY.equals(intervalType) || DAY_OF_WEEK.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy-MM-dd");
        }
        if (HOUR.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy-MM-dd HH");
        }
        if (MINUTE.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy-MM-dd HH:mm");
        }
        if (SECOND.equals(intervalType)) {
            return dateFormatter.format(d, "yyyy-MM-dd HH:mm:ss");
        }
        return null;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy