/* * Copyright 2011 Future Systems * * Licensed 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.krakenapps.logdb; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; public abstract class LogTimelineCallback { private long callbackInterval = 2000; private Map<Long, Integer> timeline = new HashMap<Long, Integer>(); private long lastCallbackTime; private SpanValue[] spans = new SpanValue[] { new SpanValue(Calendar.MINUTE, 1), // new SpanValue(Calendar.MINUTE, 10), // new SpanValue(Calendar.HOUR_OF_DAY, 1), // new SpanValue(Calendar.DAY_OF_YEAR, 1), // new SpanValue(Calendar.WEEK_OF_YEAR, 1), // new SpanValue(Calendar.MONTH, 1) }; private int spansIndex = 0; public long getCallbackInterval() { return callbackInterval; } public void setCallbackInterval(long callbackInterval) { this.callbackInterval = callbackInterval; } public abstract int getSize(); public void put(Date date) { if (date == null) return; long time = date.getTime(); time = time - time % 86400; if (timeline.containsKey(time)) timeline.put(time, timeline.get(time) + 1); else timeline.put(time, 1); if (System.currentTimeMillis() > lastCallbackTime + callbackInterval) { callback(); lastCallbackTime = System.currentTimeMillis(); } } public void callback() { buildCallbackData(false); } public void eof() { buildCallbackData(true); } private void buildCallbackData(boolean isEnd) { int size = getSize(); int[] values = new int[size]; Long beginTime = null; if (timeline.isEmpty()) return; if (spansIndex >= spans.length) return; long[] index = new long[size]; while (true) { List<Long> keys = new ArrayList<Long>(timeline.keySet()); Collections.sort(keys, Collections.reverseOrder()); Calendar c = Calendar.getInstance(); c.setTimeInMillis(spans[spansIndex].getBaseTime(keys.get(0))); for (int i = size - 1; i >= 0; i--) { index[i] = c.getTimeInMillis(); c.add(spans[spansIndex].field, -spans[spansIndex].amount); } beginTime = index[0]; if (keys.get(keys.size() - 1) < beginTime) { if (++spansIndex >= spans.length) return; continue; } int indexPos = size - 1; for (Long key : keys) { while (key < index[indexPos]) indexPos--; values[indexPos] += timeline.get(key); } Map<Long, Integer> newTimeline = new HashMap<Long, Integer>(); for (int i = 0; i < size; i++) newTimeline.put(index[i], values[i]); timeline = newTimeline; break; } callback(new Date(beginTime), spans[spansIndex], values, isEnd); } protected abstract void callback(Date beginTime, SpanValue spanValue, int[] values, boolean isEnd); public class SpanValue { private int field; private int amount; private SpanValue(int field, int amount) { this.field = field; this.amount = amount; } public String getFieldName() { switch (field) { case Calendar.MINUTE: return "Minute"; case Calendar.HOUR_OF_DAY: return "Hour"; case Calendar.DAY_OF_YEAR: return "Day"; case Calendar.WEEK_OF_YEAR: return "Week"; case Calendar.MONTH: return "Month"; } return Integer.toString(field); } public int getAmount() { return amount; } public Date getBaseTime(Date time) { return new Date(getBaseTime(time.getTime())); } public long getBaseTime(long time) { switch (field) { case Calendar.MINUTE: case Calendar.HOUR_OF_DAY: case Calendar.DAY_OF_YEAR: case Calendar.WEEK_OF_YEAR: time += 291600000L; // base to Monday, 00:00:00 time -= time % (getMillis() * amount); time -= 291600000L; return time; case Calendar.MONTH: Calendar c = Calendar.getInstance(); c.setTimeInMillis(time); c.set(Calendar.MILLISECOND, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.DAY_OF_MONTH, 1); int monthOffset = c.get(Calendar.YEAR) * 12; int month = monthOffset + c.get(Calendar.MONTH); month -= month % amount; month -= monthOffset; if (month >= 0) c.set(Calendar.MONTH, month); else { c.set(Calendar.YEAR, c.get(Calendar.YEAR) - 1); c.set(Calendar.MONTH, month + 12); } return c.getTimeInMillis(); } return time; } private long getMillis() { switch (field) { case Calendar.MINUTE: return 60 * 1000L; case Calendar.HOUR_OF_DAY: return 60 * 60 * 1000L; case Calendar.DAY_OF_YEAR: return 24 * 60 * 60 * 1000L; case Calendar.WEEK_OF_YEAR: return 7 * 24 * 60 * 60 * 1000L; } return -1; } } }