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

net.snowflake.common.core.CalendarCache Maven / Gradle / Ivy

There is a newer version: 5.1.4
Show newest version
package net.snowflake.common.core;

import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.TimeZone;

/**
 * Created by mzukowski on 3/13/16.
 *
 * Implements a simple thread-local cache for GregorianCalendar objects.
 * Note, by default it is not enabled, and will re-create the objects.
 *
 */
public class CalendarCache
{
  private static class CalendarCacheState
  {
    HashMap map;

    boolean enabled;

    /** If set, we always use Gregorian calendar, even before 1582 */
    boolean alwaysGregorian;

    public CalendarCacheState()
    {
      map = new HashMap();
      enabled = false;
      alwaysGregorian = false;
    }
  };

  /** Thread local state */
  private static final ThreadLocal localState =
      new ThreadLocal()
      {
           @Override protected CalendarCacheState initialValue()
           {
             return new CalendarCacheState();
           }
      };

  /**
   * Enable or disable the cache
   * @param enabled true to enable cache or false
   */
  public static void setEnabled(boolean enabled)
  {
    localState.get().enabled = enabled;
  }

  /**
   * Set if the the calendars produced should not observe Julian calendar
   * before 1582.
   *
   * Calling this function also clears the cache.
   */

  public static void setAlwaysGregorian(boolean alwaysGregorian)
  {
    localState.get().alwaysGregorian = alwaysGregorian;

    // Clear the cache, in case old values had a different setting
    localState.get().map.clear();
  }

  /**
   * Helper function.
   * Returns a GregorianCalendar object.
   * @param timezone  Timezone to create the calendar in.
   * @param tzId      The id of the timezone (e.g. "America/Los_Angeles")
   * @param calId     Explicit ID of the calendar. Can be used e.g.
   *                  if more than one copy of the calendar for the same
   *                  timezone is needed.
   *                  Note, if specified, the caller is responsible for
   *                  making sure it's always the same timezone.
   * @return  The GregorianCalendar object. Note, it can be reused by other
   *          consumers, so be careful changing any settings in it
   */
  public static GregorianCalendar get(TimeZone timezone,
                                      String tzId,
                                      String calId)
  {
    CalendarCacheState state = localState.get();
    GregorianCalendar res;
    if (state.enabled)
    {
      res = state.map.get(calId);
      if (res == null)
      { // Not found, create it
        if (timezone == null)
        {
          // If not specified, create a timezone
          timezone = TimeZone.getTimeZone(tzId);
        }
        res = new GregorianCalendar(timezone);
        state.map.put(calId, res);
      } 
      else
      { // Found

        // Verify it's the same
        if (timezone != null & !res.getTimeZone().hasSameRules(timezone))
        {
          throw new IllegalArgumentException(
              "Cached timezone is not equivalent to the requested one:"
                  + timezone + "  VS  " + res.getTimeZone());
        }
      }
    }
    else
    {
      if (timezone == null)
      {
        // If not specified, create a timezone
        timezone = TimeZone.getTimeZone(tzId);
      }
      res = new GregorianCalendar(timezone);
    }
    // It is possible the previous user changed something in the calendar.
    // Clear it.
    // @note Actually, it seems even freshly created calendar instances
    // should be cleared.
    res.clear();

    // Force full Gregorian calendar
    if (state.alwaysGregorian)
    {
      res.setGregorianChange(new Date(Long.MIN_VALUE));
    }

    return res;
  }

  /**
   * Return a GregorianCalendar object identified by id. 
   * If caching is enabled and an object with the same id existed, it will be returned,
   * otherwise  a new object will be created.
   * @param timezone  Timezone to create the calendar in
   * @param calId     Explicit ID of the calendar. Can be used e.g.
   *                  if more than one copy of the calendar for the same
   *                  timezone is needed.
   *                  Note, if specified, the caller is responsible for
   *                  making sure it's always the same timezone.
   * @return  The GregorianCalendar object. Note, it can be reused by other
   *          consumers, so be careful changing any settings in it
   */
  public static GregorianCalendar get(TimeZone timezone, String calId)
  {
    return get(timezone, null, calId);
  }

  /**
   * Return a cached GregorianCalendar object. If doesn't exist, will be created.
   * @param timezone  Timezone to create the calendar in
   * @return  The GregorianCalendar object. Note, it can be reused by other
   *          consumers, so do not change any non-basic settings in it
   *          (like date).
   */
  public static GregorianCalendar get(TimeZone timezone)
  {
    // Use TimeZone id to lookup the Calendar
    return get(timezone, null, timezone.getID());
  }

  /**
   * Return a cached GregorianCalendar object. If doesn't exist, will be created.
   * @param tzId The id of the timezone (e.g. "America/Los_Angeles")
   * @return  The GregorianCalendar object. Note, it can be reused by other
   *          consumers, so do not change any non-basic settings in it
   *          (like date).
   */
  public static GregorianCalendar get(String tzId)
  {
    // Pass null as timezone - we'll create it when needed.
    // We use tzId also as a calendar ID.
    return get(null, tzId, tzId);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy