rapture.event.generator.EventGenerator.java Source code

Java tutorial

Introduction

Here is the source code for rapture.event.generator.EventGenerator.java

Source

/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2011-2016 Incapture Technologies LLC
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package rapture.event.generator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import rapture.common.TimedEventRecord;

import com.google.common.collect.HashBiMap;

/**
 * Generate event names given a date/calendar object
 * 
 * @author alanmoore
 * 
 */
public class EventGenerator {
    /**
     * This must be called with a minute movement - or you'll get repeats
     * 
     * @param cal
     * @param periodic
     * @param periodic
     * @return
     */
    public static List<String> generateEventNames(DateTime cal, boolean periodic) {
        List<String> ret = new ArrayList<String>();
        generatePeriodic(ret, cal, periodic);
        return ret;
    }

    private static void checkAdd(int dayOfWeek, int checkValue, int[] valids, String name, String prefix,
            List<String> ret) {
        for (int v : valids) {
            if ((checkValue % v) == 0) {
                ret.add(String.format("%s/daily/%s/%02d", prefix, name, v));
                ret.add(String.format("%s/%s/%s/%02d", prefix, isWeekend(dayOfWeek) ? "weekend" : "weekday", name,
                        v));
                ret.add(String.format("%s/%s/%s/%02d", prefix, getDOWName(dayOfWeek), name, v));
            }
        }
    }

    private static String getDOWName(int jodaTimeDay) {
        return dow[jodaTimeDay - 1];
    }

    // JODA Chronology uses ISO standard where Monday = 1 and Sunday = 7
    // Does it hurt to have two Sundays? Should zero be an error?
    private static String[] dow = { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
    private static int[] minuteChecks = new int[] { 1, 10, 15, 30 };
    private static int[] hourChecks = new int[] { 1, 12 };

    private static String[] supportedTimeZones = { "America/New_York", "America/Los_Angeles", "Europe/London",
            "UTC" };

    public static String[] getSupportedZones() {
        return supportedTimeZones;
    }

    private static HashBiMap<String, String> timeZoneBiMap = HashBiMap.create();
    private static Map<String, DateTimeZone> timeZones = new HashMap<String, DateTimeZone>();

    public static String getConvertedTimeZone(String realTimeZone) {
        return timeZoneBiMap.get(realTimeZone);
    }

    public static String getRealTimeZone(String convertedTimeZone) {
        return timeZoneBiMap.inverse().get(convertedTimeZone);
    }

    public static DateTimeZone getRealDateTimeZone(String timeZoneString) {
        return timeZones.get(getRealTimeZone(timeZoneString));
    }

    static {
        for (int i = 0; i < supportedTimeZones.length; i++) {
            timeZones.put(supportedTimeZones[i], DateTimeZone.forID(supportedTimeZones[i]));
            String alternate = supportedTimeZones[i].replace('/', '-');
            timeZoneBiMap.put(supportedTimeZones[i], alternate);
        }

    }

    private static DateTimeFormatter hmFormat = DateTimeFormat.forPattern("HH/mm");

    private static boolean isWeekend(int dow) {
        return dow >= 6;
    }

    private static void generatePeriodic(List<String> ret, DateTime dt, boolean periodic) {
        // We guarantee that each call to this function, cal will be advanced a
        // minute at least

        int dayOfWeek = dt.getDayOfWeek();
        if (periodic) {
            checkAdd(dayOfWeek, dt.getMinuteOfHour(), minuteChecks, "minutes", "/time", ret);
            if (dt.getMinuteOfHour() == 0) {
                checkAdd(dayOfWeek, dt.getHourOfDay(), hourChecks, "hours", "/time", ret);
                if (dt.getHourOfDay() == 0) {
                    ret.add("/time/days" + dt.getDayOfMonth());
                    if (dt.getDayOfMonth() == 1) {
                        ret.add("/time/months" + dt.getMonthOfYear());
                    }
                }
            }
        }

        // We construct, for each supported timezone,
        // timezone/daily/[timezone]/hour/minute
        // timezone/weekend/ (if a weekend)
        // timezone/weekeday/ (if a weekday)
        // timezone/day

        // So initially create the end point for each timezone, then push it out
        // We assume dt is in UT (but does this matter?)

        for (Map.Entry<String, DateTimeZone> zoneEntry : timeZones.entrySet()) {
            DateTime dtLocal = dt.withZone(zoneEntry.getValue());
            String convertedZone = getConvertedTimeZone(zoneEntry.getKey());
            int localDow = dtLocal.getDayOfWeek();
            String endField = hmFormat.print(dtLocal);
            ret.add(String.format("/timezone/daily/%s/%s", convertedZone, endField));
            ret.add(String.format("/timezone/%s/%s/%s", isWeekend(localDow) ? "weekend" : "weekday", convertedZone,
                    endField));
            ret.add(String.format("/timezone/%s/%s/%s", getDOWName(localDow), convertedZone, endField));
        }
    }

    public static Collection<? extends TimedEventRecord> generateWeeklyEventRecords(DateTime startDt,
            EventHelper eventHelper) {
        // Given a start date, look forward one week (7 days), showing events
        // that are at most one minute granular. Don't show periodic events
        // Do some attempt to order them correctly
        List<TimedEventRecord> records = new ArrayList<TimedEventRecord>();
        int currentDow = startDt.getDayOfWeek();
        DateTime endPoint = startDt.plusDays(7);
        DateTime current = startDt.plus(0);
        int endDow = endPoint.getDayOfWeek();
        boolean first = true;
        while (currentDow != endDow || first) {
            first = false;
            String startPoint = String.format("/timezone/%s", getDOWName(currentDow));
            List<TimedEventRecord> recs = eventHelper.filterEvent(startPoint, current);
            if (recs != null) {
                records.addAll(recs);
            }
            startPoint = "/timezone/daily";
            recs = eventHelper.filterEvent(startPoint, current);
            if (recs != null) {
                records.addAll(recs);
            }
            if (isWeekend(currentDow)) {
                startPoint = "/timezone/weekend";
                recs = eventHelper.filterEvent(startPoint, current);
            } else {
                startPoint = "/timezone/weekday";
                recs = eventHelper.filterEvent(startPoint, current);
            }
            if (recs != null) {
                records.addAll(recs);
            }
            current = current.plusDays(1);
            currentDow = current.getDayOfWeek();
        }
        return records;
    }

}