org.apache.lens.cube.metadata.UpdatePeriod.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.lens.cube.metadata.UpdatePeriod.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.lens.cube.metadata;

import static java.util.Calendar.*;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.apache.lens.cube.error.LensCubeErrorCode;
import org.apache.lens.server.api.error.LensException;

import org.apache.commons.lang3.time.DateUtils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.Getter;

public enum UpdatePeriod implements Named {
    SECONDLY("second", SECOND, 1000, 1.4f, "yyyy-MM-dd-HH-mm-ss"), MINUTELY("minute", MINUTE,
            60 * SECONDLY.weight(), 1.35f,
            "yyyy-MM-dd-HH-mm"), HOURLY("hour", HOUR_OF_DAY, 60 * MINUTELY.weight(), 1.3f, "yyyy-MM-dd-HH"), DAILY(
                    "day", DAY_OF_MONTH, 24 * HOURLY.weight(), 1f,
                    "yyyy-MM-dd"), WEEKLY("week", WEEK_OF_YEAR, 7 * DAILY.weight(), 0.7f, "YYYY-'W'ww"), MONTHLY(
                            "month", MONTH, 30 * DAILY.weight(), 0.6f,
                            "yyyy-MM"), QUARTERLY("quarter", MONTH, 3 * MONTHLY.weight(), 0.55f, "yyyy-MM"), YEARLY(
                                    "year", YEAR, 12 * MONTHLY.weight(), 0.52f, "yyyy"), CONTINUOUS("continuous",
                                            Calendar.SECOND, 1, 1.5f, "yyyy-MM-dd-HH-mm-ss");

    public static final long MIN_INTERVAL = values()[0].weight();
    @Getter
    private String unitName;
    private final int calendarField;
    private final long weight;
    /**
     * Normalization factor is calculated in comparison with daily update period. What it means is that
     * for a fixed time range, reading partitions of this update period is expensive/cheap as compared to
     * reading partitions of daily update period by this factor. Values are tentatively picked based on
     * similar logic in an existing system at InMobi.
     */
    private final float normalizationFactor;
    private final String format;

    private static DateFormat getSecondlyFormat() {
        if (secondlyFormat == null) {
            secondlyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(SECONDLY.formatStr());
                }
            };
        }
        return secondlyFormat.get();
    }

    private static DateFormat getMinutelyFormat() {
        if (minutelyFormat == null) {
            minutelyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(MINUTELY.formatStr());
                }
            };
        }
        return minutelyFormat.get();
    }

    private static DateFormat getHourlyFormat() {
        if (hourlyFormat == null) {
            hourlyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(HOURLY.formatStr());
                }
            };
        }
        return hourlyFormat.get();
    }

    private static DateFormat getDailyFormat() {
        if (dailyFormat == null) {
            dailyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(DAILY.formatStr());
                }
            };
        }
        return dailyFormat.get();
    }

    private static DateFormat getWeeklyFormat() {
        if (weeklyFormat == null) {
            weeklyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(WEEKLY.formatStr());
                }
            };
        }
        return weeklyFormat.get();
    }

    private static DateFormat getMonthlyFormat() {
        if (monthlyFormat == null) {
            monthlyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(MONTHLY.formatStr());
                }
            };
        }
        return monthlyFormat.get();
    }

    private static DateFormat getQuarterlyFormat() {
        if (quarterlyFormat == null) {
            quarterlyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(QUARTERLY.formatStr());
                }
            };
        }
        return quarterlyFormat.get();
    }

    private static DateFormat getYearlyFormat() {
        if (yearlyFormat == null) {
            yearlyFormat = new ThreadLocal<DateFormat>() {
                @Override
                protected SimpleDateFormat initialValue() {
                    return new SimpleDateFormat(YEARLY.formatStr());
                }
            };
        }
        return yearlyFormat.get();
    }

    private static ThreadLocal<DateFormat> secondlyFormat;
    private static ThreadLocal<DateFormat> minutelyFormat;
    private static ThreadLocal<DateFormat> hourlyFormat;
    private static ThreadLocal<DateFormat> dailyFormat;
    private static ThreadLocal<DateFormat> weeklyFormat;
    private static ThreadLocal<DateFormat> monthlyFormat;
    private static ThreadLocal<DateFormat> quarterlyFormat;
    private static ThreadLocal<DateFormat> yearlyFormat;

    UpdatePeriod(String unitName, int calendarField, long diff, float normalizationFactor, String format) {
        this.unitName = unitName;
        this.calendarField = calendarField;
        this.weight = diff;
        this.normalizationFactor = normalizationFactor;
        this.format = format;
    }

    public int calendarField() {
        return this.calendarField;
    }

    public long weight() {
        return this.weight;
    }

    public static UpdatePeriod fromUnitName(String unitName) throws LensException {
        for (UpdatePeriod up : values()) {
            if (up.getUnitName().equals(unitName)) {
                return up;
            }
        }
        throw new LensException(LensCubeErrorCode.INVALID_TIME_UNIT.getLensErrorInfo(), unitName);
    }

    public DateFormat format() {
        switch (this) {
        case CONTINUOUS:
            return getSecondlyFormat();
        case SECONDLY:
            return getSecondlyFormat();
        case MINUTELY:
            return getMinutelyFormat();
        case HOURLY:
            return getHourlyFormat();
        case DAILY:
            return getDailyFormat();
        case WEEKLY:
            return getWeeklyFormat();
        case MONTHLY:
            return getMonthlyFormat();
        case QUARTERLY:
            return getQuarterlyFormat();
        case YEARLY:
            return getYearlyFormat();
        default:
            throw new IllegalArgumentException("Update period illegal, or doesn't have defined format");
        }
    }

    Cache<Date, String> dateToStringCache = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.HOURS)
            .maximumSize(100).build();
    Cache<String, Date> stringToDateCache = CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.HOURS)
            .maximumSize(100).build();

    public String format(final Date date) {
        try {
            return dateToStringCache.get(date, new Callable<String>() {
                @Override
                public String call() {
                    return format().format(date);
                }
            });
        } catch (ExecutionException e) {
            return format().format(date);
        }
    }

    public Date parse(final String dateString) throws ParseException {
        try {
            return stringToDateCache.get(dateString, new Callable<Date>() {
                @Override
                public Date call() throws Exception {
                    return format().parse(dateString);
                }
            });
        } catch (ExecutionException e) {
            return format().parse(dateString);
        }
    }

    public String formatStr() {
        return this.format;
    }

    @Override
    public String getName() {
        return name();
    }

    public boolean canParseDateString(String dateString) {
        return formatStr().replaceAll("'", "").length() == dateString.length();
    }

    public float getNormalizationFactor() {
        return normalizationFactor;
    }

    public Date truncate(Date date) {
        switch (this) {
        case WEEKLY:
            Date truncDate = DateUtils.truncate(date, Calendar.DAY_OF_MONTH);
            Calendar cal = Calendar.getInstance();
            cal.setTime(truncDate);
            cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
            return cal.getTime();
        case QUARTERLY:
            Date dt = DateUtils.truncate(date, this.calendarField());
            dt.setMonth(dt.getMonth() - (dt.getMonth() % 3));
            return dt;
        default:
            return DateUtils.truncate(date, this.calendarField());
        }
    }

    public Calendar truncate(Calendar calendar) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(truncate(calendar.getTime()));
        return cal;
    }

    public void increment(Calendar calendar, int increment) {
        switch (this) {
        case QUARTERLY:
            increment *= 3;
        }
        calendar.add(calendarField(), increment);
    }

    public Date getCeilDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        boolean hasFraction = false;
        switch (this) {
        case YEARLY:
            if (cal.get(MONTH) != 0) {
                hasFraction = true;
                break;
            }
        case MONTHLY:
            if (cal.get(DAY_OF_MONTH) != 1) {
                hasFraction = true;
                break;
            }
        case DAILY:
            if (cal.get(Calendar.HOUR_OF_DAY) != 0) {
                hasFraction = true;
                break;
            }
        case HOURLY:
            if (cal.get(Calendar.MINUTE) != 0) {
                hasFraction = true;
                break;
            }
        case MINUTELY:
            if (cal.get(Calendar.SECOND) != 0) {
                hasFraction = true;
                break;
            }
        case SECONDLY:
        case CONTINUOUS:
            if (cal.get(Calendar.MILLISECOND) != 0) {
                hasFraction = true;
            }
            break;
        case WEEKLY:
            if (cal.get(Calendar.DAY_OF_WEEK) != 1) {
                hasFraction = true;
                break;
            }
        }

        if (hasFraction) {
            cal.add(this.calendarField(), 1);
            return getFloorDate(cal.getTime());
        } else {
            return date;
        }
    }

    public Date getFloorDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        switch (this) {
        case WEEKLY:
            cal.set(Calendar.DAY_OF_WEEK, 1);
            break;
        }
        switch (this) {
        case YEARLY:
            cal.set(MONTH, 0);
        case MONTHLY:
            cal.set(DAY_OF_MONTH, 1);
        case WEEKLY:
            // Already covered, only here for fall through cases
        case DAILY:
            cal.set(Calendar.HOUR_OF_DAY, 0);
        case HOURLY:
            cal.set(Calendar.MINUTE, 0);
        case MINUTELY:
            cal.set(Calendar.SECOND, 0);
        case SECONDLY:
        case CONTINUOUS:
            cal.set(Calendar.MILLISECOND, 0);
            break;
        }
        return cal.getTime();
    }

    public static class UpdatePeriodComparator implements Comparator<UpdatePeriod> {
        @Override
        public int compare(UpdatePeriod o1, UpdatePeriod o2) {
            if (o1 == null && o2 != null) {
                return -1;
            } else if (o1 != null && o2 == null) {
                return 1;
            } else if (o1 == null) {
                return 0;
            } else {
                if (o1.weight > o2.weight) {
                    return 1;
                } else if (o1.weight < o2.weight) {
                    return -1;
                } else {
                    return 0;
                }
            }
        }
    }
}