proj.zoie.hourglass.impl.HourGlassScheduler Maven / Gradle / Ivy
package proj.zoie.hourglass.impl;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Random;
import org.apache.log4j.Logger;
public class HourGlassScheduler
{
public static final Logger log = Logger.getLogger(HourGlassScheduler.class.getName());
private String _schedule;
private final FREQUENCY _freq;
private int[] _params = new int[6];
private int _trimThreshold = Integer.MAX_VALUE;
private boolean _appendOnly = true;
private static ThreadLocal dateFormatter = new ThreadLocal()
{
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
}
};
public static enum FREQUENCY
{
MINUTELY, // good for use in testing
HOURLY,
DAILY,
}
public HourGlassScheduler(FREQUENCY freq, String schedule)
{
// format "ss mm hh [ss mm hh]"
// We will pick a time schedule randomly between the first and second schedules.
_schedule = schedule;
_freq = freq;
String [] param = _schedule.split(" ");
for(int i = 0; i < Math.min(_params.length, param.length); i++)
{
_params[i] = parseParam(param[i]);
}
int size = _params.length / 2;
if (param.length <= size)
{
// We have only one schedule.
for (int i = 0; i < size; ++i)
{
_params[size + i] = _params[i];
}
}
log.info("schedule: " + Arrays.toString(_params) + " frequenty: " + _freq);
if (param.length > size)
{
// We have a start and an end.
int start = _params[0] + (_params[1] * 60) + (_params[2] * 3600);
int end = _params[3] + (_params[4] * 60) + (_params[5] * 3600);
int gap = end - start;
if (gap < 0) gap = gap + 86400 /* one day */;
if (gap != 0)
{
start += new Random().nextInt(gap);
start %= 86400 /* one day */;
_params[0] = start % 60;
_params[1] = (start % 3600) / 60;
_params[2] = start / 3600;
}
}
log.info("schedule final: " + Arrays.toString(_params) + " frequenty: " + _freq);
}
public HourGlassScheduler(FREQUENCY freq, String schedule, int trimThreshold)
{
this(freq, schedule);
_trimThreshold = trimThreshold;
log.info("schedule: " + Arrays.toString(_params) + " frequenty: " + _freq + " trimThreshold: keep last " + _trimThreshold + " rolling periods");
}
public HourGlassScheduler(FREQUENCY freq, String schedule, boolean appendOnly)
{
this(freq, schedule);
_appendOnly = appendOnly;
}
public HourGlassScheduler(FREQUENCY freq, String schedule, boolean appendOnly, int trimThreshold)
{
this(freq, schedule, appendOnly);
_trimThreshold = trimThreshold;
log.info("schedule: " + Arrays.toString(_params) + " frequenty: " + _freq + " trimThreshold: keep last " + _trimThreshold + " rolling periods");
}
private int parseParam(String param)
{
if (param.indexOf('*')>=0) return 0;
int ret = 0;
try
{
ret = Integer.parseInt(param.trim());
} catch(NumberFormatException e)
{
throw new IllegalArgumentException("Failed to instantiate HourGlassScheduler", e);
}
return ret;
}
public FREQUENCY getFreq()
{
return _freq;
}
public int getTrimThreshold()
{
return _trimThreshold;
}
public boolean isAppendOnly()
{
return _appendOnly;
}
protected Calendar getNextRoll()
{
long timenow = System.currentTimeMillis();
Calendar next = Calendar.getInstance();
next.setTimeInMillis(timenow);
Calendar now = Calendar.getInstance();
now.setTimeInMillis(timenow);
switch(_freq)
{
case MINUTELY: // set the second so that every minute we switch over at the same second
next.set(Calendar.SECOND, _params[0]);
if (!next.after(now)) next.add(Calendar.MINUTE, 1);
break;
case HOURLY: // set the second and minute so that we switch over at the same time in the hour
next.set(Calendar.SECOND, _params[0]);
next.set(Calendar.MINUTE, _params[1]);
if (!next.after(now)) next.add(Calendar.HOUR_OF_DAY, 1);
break;
case DAILY: // set hour, minute, second so that we switch over at the same time of the day
next.set(Calendar.SECOND, _params[0]);
next.set(Calendar.MINUTE, _params[1]);
next.set(Calendar.HOUR_OF_DAY, _params[2]);
if (!next.after(now)) next.add(Calendar.DAY_OF_MONTH, 1);
break;
}
return next;
}
Calendar getCurrentRoll()
{
Calendar current = getNextRoll();
switch(_freq)
{
case MINUTELY:
current.add(Calendar.MINUTE, -1);
break;
case HOURLY:
current.add(Calendar.HOUR_OF_DAY, -1);
break;
case DAILY:
current.add(Calendar.DAY_OF_MONTH, -1);
break;
}
return current;
}
public Calendar getTrimTime(Calendar now)
{
Calendar threshold = (Calendar) now.clone();
int trimUnit = 60*60*24;
switch(getFreq())
{
case MINUTELY:
trimUnit = 60;
break;
case HOURLY:
trimUnit = 60*60;
break;
case DAILY:
trimUnit = 60*60*24;
break;
}
threshold.add(Calendar.SECOND, - trimUnit * _trimThreshold);
return threshold;
}
/**
* convert a Calendar time to a folder name using GMT time string
* @param cal
* @return a String for folder name
*/
public String getFolderName(Calendar cal)
{
return dateFormatter.get().format(cal.getTime());
}
@Override
public String toString()
{
return "HourGlassScheduler:" + _freq + " " + _schedule;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy