bb.util
Class DateUtil.DateStringCache

java.lang.Object
  extended by bb.util.DateUtil.DateStringCache
Enclosing class:
DateUtil

public static class DateUtil.DateStringCache
extends Object

Stores Date <--> String mappings (i.e. from the user's perspective, it is a bidirectional map).

If this class is used during formating/parsing (via format/parse), then a given Date/String will only be formated/parsed once. Thereafter, if a request is made to format/parse that Date/String, the previous result will be quickly retrieved and returned. Skipping duplicate format/parse operations yields top performance, since these operations are extremely slow. On the other hand, if the Date/String instances that are encountered are mostly unique, then caching is ineffective and using this class wastes both CPU and memory.

The most convenient way to construct an instance of this class is to use the single String arg constructor which takes a date and time pattern.

Regardless of whether format or parse is called, this class will attempt to store both the Date --> String mapping as well as the String --> Date mapping. A new Date --> String mapping is generated for every unique Date that is encountered. However, it is possible for the String --> Date mapping to not be added because of an asymmetry that is next described.

If the date and time pattern drops information, the bidirectional mapping provided by this class is not 1-1. For example, suppose that the pattern is the day of year pattern "yyyy-MM-dd", which drops all hour and smaller information. Then there are many Dates which will get mapped to the same String, but that String can only be mapped back to one Date. For instance, the Dates (in ISO 8601 format) 2000-01-02T03:04:00.000 and 2000-01-02T03:05:00.000 both get mapped to the same String "2000-01-02" if the pattern is "yyyy-MM-dd". In this example, what Date should the String "2000-01-02" get mapped to? We have seen that there are many possible choices (e.g. 2000-01-02T03:04:00.000 and 2000-01-02T03:05:00.000 are among the many). The convention used here is to always map a String to the "fundamental" Date, which is the sole Date which String parses into. In the example here, the String "2000-01-02" would get mapped to the Date corresponding to 2000-01-02T00:00:00.000.

In order to limit memory consumption, this class will only store sizeMax String <--> Date mappings. The clear and setSizeMax methods can be used to dynamically change the memory used.

This class is multithread safe.


Field Summary
private  ThreadLocal<DateFormat> dateFormatPerThread
          Used to format/parse Dates/Strings that lack a String/Date mapping.
private  Map<Date,String> dateToString
          Stores the Date --> String mappings.
private  AtomicLong numberFormatHits
          Number of times that format returned a cached value.
private  AtomicLong numberFormatMisses
          Number of times that format did not return a cached value.
private  AtomicLong numberFormatPutFails
          Number of times that format failed to cache data when it called put.
private  AtomicLong numberParseHits
          Number of times that parse returned a cached value.
private  AtomicLong numberParseMisses
          Number of times that parse did not return a cached value.
private  AtomicLong numberParsePutFails
          Number of times that parse failed to cache data when it called put.
private  String pattern
          Description of how to turn a Date into a String.
private  int sizeMax
          Specifies the maximum number of elements that dateToString and stringToDate may hold.
private static int sizeMax_default
          Default value for sizeMax.
private  Map<String,Date> stringToDate
          Stores the String --> Date mappings.
 
Constructor Summary
DateUtil.DateStringCache(String pattern)
          Simply calls this(pattern, sizeMax_default).
DateUtil.DateStringCache(String pattern, boolean useIsoDateFormat)
          Simply calls this(pattern, sizeMax_default, useIsoDateFormat).
DateUtil.DateStringCache(String pattern, int sizeMax)
          Simply calls this(pattern, sizeMax, false).
DateUtil.DateStringCache(String pattern, int sizeMax, boolean useIsoDateFormat)
          The fundamental constructor.
 
Method Summary
 void clear()
          Clears every Date <--> String mapping and resets all the counting fields back to 0.
 String format(Date date)
          Returns the string which is the correct format of date.
 String getIssues()
          Returns a description of any issues which this instance has encountered.
 String getPattern()
          Accessor for pattern.
 int getSizeMax()
          Accessor for sizeMax.
private static ThreadLocal<DateFormat> makeDateFormatPerThread(String pattern, boolean useIsoDateFormat)
           
 Date parse(String string)
          Returns the date which is the correct parse of string.
private  void put(Date date, boolean dateWasParsed, String string, AtomicLong putFails)
          Puts the date <--> mapping into the cache.
 void setSizeMax(int sizeMax)
          Mutator for sizeMax.
 String toString()
          Returns a labeled description of all the fields of this instance.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

sizeMax_default

private static final int sizeMax_default
Default value for sizeMax.

See Also:
Constant Field Values

pattern

private final String pattern
Description of how to turn a Date into a String. See SimpleDateFormat for details on what this can look like.


dateFormatPerThread

private final ThreadLocal<DateFormat> dateFormatPerThread
Used to format/parse Dates/Strings that lack a String/Date mapping.


sizeMax

private int sizeMax
Specifies the maximum number of elements that dateToString and stringToDate may hold.


dateToString

private final Map<Date,String> dateToString
Stores the Date --> String mappings.


stringToDate

private final Map<String,Date> stringToDate
Stores the String --> Date mappings.


numberFormatHits

private final AtomicLong numberFormatHits
Number of times that format returned a cached value. Note: the count is since the last call to setSizeMax/clear.


numberFormatMisses

private final AtomicLong numberFormatMisses
Number of times that format did not return a cached value. Note: the count is since the last call to setSizeMax/clear.


numberFormatPutFails

private final AtomicLong numberFormatPutFails
Number of times that format failed to cache data when it called put. Note: the count is since the last call to setSizeMax/clear.


numberParseHits

private final AtomicLong numberParseHits
Number of times that parse returned a cached value. Note: the count is since the last call to setSizeMax/clear.


numberParseMisses

private final AtomicLong numberParseMisses
Number of times that parse did not return a cached value. Note: the count is since the last call to setSizeMax/clear.


numberParsePutFails

private final AtomicLong numberParsePutFails
Number of times that parse failed to cache data when it called put. Note: the count is since the last call to setSizeMax/clear.

Constructor Detail

DateUtil.DateStringCache

public DateUtil.DateStringCache(String pattern)
                         throws IllegalArgumentException
Simply calls this(pattern, sizeMax_default).

Throws:
IllegalArgumentException - if pattern is blank

DateUtil.DateStringCache

public DateUtil.DateStringCache(String pattern,
                                int sizeMax)
                         throws IllegalArgumentException
Simply calls this(pattern, sizeMax, false).

Throws:
IllegalArgumentException - if pattern is blank; sizeMax < 0

DateUtil.DateStringCache

public DateUtil.DateStringCache(String pattern,
                                boolean useIsoDateFormat)
                         throws IllegalArgumentException
Simply calls this(pattern, sizeMax_default, useIsoDateFormat).

Throws:
IllegalArgumentException - if pattern is blank

DateUtil.DateStringCache

public DateUtil.DateStringCache(String pattern,
                                int sizeMax,
                                boolean useIsoDateFormat)
                         throws IllegalArgumentException
The fundamental constructor.

Parameters:
pattern - a date and time pattern String that will be supplied to a ThreadLocal which constructs DateFormat instances
sizeMax - the value for sizeMax
useIsoDateFormat - if true, then the ThreadLocal will construct DateUtil.IsoDateFormat instances out of pattern, else it will construct SimpleDateFormat instances
Throws:
IllegalArgumentException - if pattern is blank; sizeMax < 0
Method Detail

makeDateFormatPerThread

private static ThreadLocal<DateFormat> makeDateFormatPerThread(String pattern,
                                                               boolean useIsoDateFormat)
                                                        throws IllegalArgumentException
Throws:
IllegalArgumentException

getPattern

public String getPattern()
Accessor for pattern.


getSizeMax

public int getSizeMax()
Accessor for sizeMax.


setSizeMax

public void setSizeMax(int sizeMax)
                throws IllegalArgumentException
Mutator for sizeMax.

The sizeMax param may be smaller in order to save memory (e.g. sizeMax = 0 suppresses the cache entirely), or larger in order to get better cache coverage for higher performance.

Side effect: always calls clear.

Throws:
IllegalArgumentException - if sizeMax < 0

clear

public void clear()
Clears every Date <--> String mapping and resets all the counting fields back to 0. Dereferencing the mappings helps the objects involved to be garbage collected.


format

public String format(Date date)
              throws IllegalArgumentException
Returns the string which is the correct format of date.

A check if this instance already knows the format of date is first performed, and is immediately returned if so.

Otherwise, date is formated and returned. Before return, the date <--> string mapping is put into the cache if there is available space (i.e. the cache has < sizeMax mappings).

Throws:
IllegalArgumentException - if date == null

parse

public Date parse(String string)
           throws IllegalArgumentException,
                  ParseException
Returns the date which is the correct parse of string.

A check if this instance already knows the parse of string is first performed, and is immediately returned if so.

Otherwise, string is parsed and returned. Before return, the date <--> string mapping is put into the cache if there is available space (i.e. the cache has < sizeMax mappings).

Throws:
IllegalArgumentException - if string is blank
ParseException - if string must be parsed but is malformed

put

private void put(Date date,
                 boolean dateWasParsed,
                 String string,
                 AtomicLong putFails)
Puts the date <--> mapping into the cache.


getIssues

public String getIssues()
Returns a description of any issues which this instance has encountered.

Contract: the result is never null, but will be an empty String if there are no isssues. If non-empty, then the result always ends with a newline.


toString

public String toString()
Returns a labeled description of all the fields of this instance.

Overrides:
toString in class Object