/**
* $RCSfile $
* $Revision $
* $Date $
*
* Copyright (C) 2008 Jive Software. All rights reserved.
*
* 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.jivesoftware.openfire.reporting.graph;
import org.jivesoftware.openfire.reporting.stats.StatsViewer;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.axis.*;
import org.jfree.chart.encoders.KeypointPNGEncoderAdapter;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.renderer.xy.XYAreaRenderer;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.time.*;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.util.Rotation;
import org.jivesoftware.openfire.stats.Statistic;
import org.jivesoftware.util.JiveGlobals;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.text.NumberFormat;
/**
* Builds graphs off of statistics tracked in the <i>StatsEngine</i>.
*
* @author Alexander Wenckus
* @see StatsViewer
*/
public class GraphEngine {
private StatsViewer statsViewer;
private static final long YEAR = 31104000000L;
private static final long MONTH = 2592000000L;
private static final long WEEK = 604800000L;
private static final long DAY = 86400000L;
private TickUnits tickUnits;
private Locale oldLocale;
/**
* Default constructor used by the plugin container to construct the graph engine.
*
* @param statsViewer The viewer provides an mechanism to view the data being tracked by the <i>StatsEngine</i>.
*/
public GraphEngine(StatsViewer statsViewer) {
this.statsViewer = statsViewer;
}
/**
* Creates a graph in PNG format. The PNG graph is encoded by the KeypointPNGEncoderAdapter
* so that the resulting PNG is encoded with alpha transparency.
*
* @param key
* @param width
* @param height
* @param startTime
* @param endTime
* @param dataPoints
* @return
* @throws IOException
*/
public byte[] generateGraph(String key, int width, int height, String color, long startTime, long endTime,
int dataPoints) throws IOException
{
JFreeChart chart = generateChart(key, width, height, color, startTime, endTime,dataPoints);
KeypointPNGEncoderAdapter encoder = new KeypointPNGEncoderAdapter();
encoder.setEncodingAlpha(true);
return encoder.encode(chart.createBufferedImage(width, height, BufferedImage.BITMASK, null));
}
/**
* Creates a chart.
*
* @param key
* @param width
* @param height
* @param startTime
* @param endTime
* @param dataPoints
* @return
* @throws IOException
*/
public JFreeChart generateChart(String key, int width, int height, String color, long startTime, long endTime,
int dataPoints) throws IOException
{
Statistic[] def = statsViewer.getStatistic(key);
if (def == null) {
return null;
}
XYDataset data = populateData(key, def, startTime, endTime, dataPoints);
if (data == null) {
return null;
}
JFreeChart chart;
switch(def[0].getStatType()) {
case count:
chart = createTimeBarChart(null, color, def[0].getUnits(), data);
break;
default:
chart = createTimeAreaChart(null, color, def[0].getUnits(), data);
}
return chart;
}
/**
* Generates a Sparkline type graph. Sparkline graphs
* are "intense, simple, wordlike graphics" so named by Edward Tufte. The big
* difference between the graph produced by this method compared to the
* graph produced by the <code>generateGraph</code> method is that this one
* produces graphs with no x-axis and no y-axis and is usually smaller in size.
* @param key
* @param width
* @param height
* @param startTime
* @param endTime
* @param dataPoints
* @return
* @throws IOException
*/
public byte[] generateSparklinesGraph(String key, int width, int height, String color, long startTime,
long endTime, int dataPoints) throws IOException
{
Statistic[] def = statsViewer.getStatistic(key);
if (def == null) {
return null;
}
JFreeChart chart;
switch (def[0].getStatType()) {
case count:
chart = generateSparklineBarGraph(key, color, def, startTime, endTime, dataPoints);
break;
default:
chart = generateSparklineAreaChart(key, color, def, startTime, endTime, dataPoints);
}
KeypointPNGEncoderAdapter encoder = new KeypointPNGEncoderAdapter();
encoder.setEncodingAlpha(true);
return encoder.encode(chart.createBufferedImage(width, height, BufferedImage.BITMASK, null));
}
private XYDataset populateData(String key, Statistic[] def, long startTime, long endTime,
int dataPoints)
{
double[][] values = statsViewer.getData(key, startTime, endTime, dataPoints);
long timePeriod = endTime - startTime;
TimeSeries[] series = new TimeSeries[values.length];
TimeSeriesCollection dataSet = new TimeSeriesCollection();
for (int d = 0; d < values.length; d++) {
series[d] = new TimeSeries(def[d].getName(), getTimePeriodClass(timePeriod));
Statistic.Type type = def[d].getStatType();
long interval = timePeriod / values[d].length;
for (int i = 0; i < values[d].length; i++) {
series[d].addOrUpdate(
getTimePeriod(timePeriod, new Date(startTime + (i * interval)),
JiveGlobals.getTimeZone()), cleanData(type, values[d][i]));
}
dataSet.addSeries(series[d]);
}
return dataSet;
}
private Class<? extends RegularTimePeriod> getTimePeriodClass(long timePeriod) {
if (timePeriod > 86400000) {
return Day.class;
} else if (timePeriod > 3600000) {
return Hour.class;
} else {
return Minute.class;
}
}
private RegularTimePeriod getTimePeriod(long timePeriod, Date date, TimeZone zone) {
if (timePeriod > 86400000) {
return new Day(date, zone);
} else if (timePeriod > 3600000) {
return new Hour(date, zone);
} else {
return new Minute(date, zone);
}
}
/**
* Round up a defined value.
*
* @param type the type of Statistic.
* @param value the value.
* @return the rounded up value.
*/
private double cleanData(Statistic.Type type, double value) {
if(type == Statistic.Type.count) {
return Math.round(value);
}
return value;
}
/**
* Generates a generic Time Area Chart.
*
* @param title the title of the Chart.
* @param valueLabel the Y Axis label.
* @param data the data to populate with.
* @return the generated Chart.
*/
private JFreeChart createTimeAreaChart(String title, String color, String valueLabel, XYDataset data) {
PlotOrientation orientation = PlotOrientation.VERTICAL;
DateAxis xAxis = generateTimeAxis();
NumberAxis yAxis = new NumberAxis(valueLabel);
NumberFormat formatter = NumberFormat.getNumberInstance(JiveGlobals.getLocale());
formatter.setMaximumFractionDigits(2);
formatter.setMinimumFractionDigits(0);
yAxis.setNumberFormatOverride(formatter);
XYAreaRenderer renderer = new XYAreaRenderer(XYAreaRenderer.AREA);
renderer.setOutline(true);
return createChart(title, data, xAxis, yAxis, orientation, renderer,
GraphDefinition.getDefinition(color));
}
/**
* Generates a generic Time Bar Chart.
*
* @param title the title of the Chart.
* @param valueLabel the X Axis Label.
* @param data the data to populate with.
* @return the generated Chart.
*/
private JFreeChart createTimeBarChart(String title, String color, String valueLabel, XYDataset data) {
PlotOrientation orientation = PlotOrientation.VERTICAL;
DateAxis xAxis = generateTimeAxis();
NumberAxis yAxis = new NumberAxis(valueLabel);
NumberFormat formatter = NumberFormat.getNumberInstance(JiveGlobals.getLocale());
formatter.setMaximumFractionDigits(2);
formatter.setMinimumFractionDigits(0);
yAxis.setNumberFormatOverride(formatter);
yAxis.setAutoRangeIncludesZero(true);
return createChart(title, data, xAxis, yAxis, orientation, new XYBarRenderer(),
GraphDefinition.getDefinition(color));
}
/**
* Generates a Chart.
*
* @param title the title of the chart.
* @param data the data to use in the chart.
* @param xAxis the variables to use on the xAxis.
* @param yAxis the variables to use on the yAxis.
* @param orientation the orientation
* @param itemRenderer the type of renderer to use.
* @return the generated chart.
*/
private JFreeChart createChart(String title, XYDataset data, ValueAxis xAxis, ValueAxis yAxis,
PlotOrientation orientation, XYItemRenderer itemRenderer, GraphDefinition def)
{
int seriesCount = data.getSeriesCount();
for(int i = 0; i < seriesCount; i++) {
itemRenderer.setSeriesPaint(i, def.getInlineColor(i));
itemRenderer.setSeriesOutlinePaint(i, def.getOutlineColor(i));
}
XYPlot plot = new XYPlot(data, xAxis, yAxis, null);
plot.setOrientation(orientation);
plot.setRenderer(itemRenderer);
return createChart(title, plot);
}
private JFreeChart createChart(String title, XYPlot plot) {
JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, false);
chart.setBackgroundPaint(Color.white);
return chart;
}
/**
* Generates a simple Time Axis.
*
* @return the generated Time Axis.
*/
private DateAxis generateTimeAxis() {
DateAxis xAxis = new DateAxis("");
xAxis.setLowerMargin(0.05);
xAxis.setUpperMargin(0.02);
xAxis.setLabel(null);
xAxis.setTickLabelsVisible(true);
xAxis.setTickMarksVisible(true);
xAxis.setAxisLineVisible(true);
xAxis.setNegativeArrowVisible(false);
xAxis.setPositiveArrowVisible(false);
xAxis.setVisible(true);
xAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
Locale locale = JiveGlobals.getLocale();
// If the tick units have not yet been setup or the locale has changed
if(tickUnits == null || !locale.equals(oldLocale)) {
tickUnits = createTickUnits(locale, JiveGlobals.getTimeZone());
oldLocale = locale;
}
xAxis.setStandardTickUnits(tickUnits);
return xAxis;
}
private TickUnits createTickUnits(Locale locale, TimeZone zone) {
TickUnits units = new TickUnits();
// date formatters
DateFormat f1 = new SimpleDateFormat("HH:mm:ss.SSS", locale);
DateFormat f2 = new SimpleDateFormat("HH:mm:ss", locale);
DateFormat f3 = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
DateFormat f4 = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT, locale);
DateFormat f5 = new SimpleDateFormat("d-MMM", locale);
DateFormat f6 = new SimpleDateFormat("MMM-yyyy", locale);
DateFormat f7 = new SimpleDateFormat("yyyy", locale);
// NOTE: timezone not needed on date formatters because dates have already been converted
// to the appropriate timezone by the respective RegularTimePeriod (Minute, Hour, Day, etc)
// see:
// http://www.jfree.org/jfreechart/api/gjdoc/org/jfree/data/time/Hour.html#Hour:Date:TimeZone
//
// If you do use a timezone on the formatters and the Jive TimeZone has been set to something
// other than the system timezone, time specific charts will show incorrect values.
/*
f1.setTimeZone(zone);
f2.setTimeZone(zone);
f3.setTimeZone(zone);
f4.setTimeZone(zone);
f5.setTimeZone(zone);
f6.setTimeZone(zone);
f7.setTimeZone(zone);
*/
// milliseconds
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 5, DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 10, DateTickUnit.MILLISECOND, 1, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 25, DateTickUnit.MILLISECOND, 5, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 50, DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 100, DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit( DateTickUnit.MILLISECOND, 250, DateTickUnit.MILLISECOND, 10, f1));
units.add(new DateTickUnit(DateTickUnit.MILLISECOND, 500, DateTickUnit.MILLISECOND, 50, f1));
// seconds
units.add(new DateTickUnit(DateTickUnit.SECOND, 1, DateTickUnit.MILLISECOND, 50, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 5, DateTickUnit.SECOND, 1, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 10, DateTickUnit.SECOND, 1, f2));
units.add(new DateTickUnit(DateTickUnit.SECOND, 30, DateTickUnit.SECOND, 5, f2));
// minutes
units.add(new DateTickUnit(DateTickUnit.MINUTE, 1, DateTickUnit.SECOND, 5, f3));
units.add( new DateTickUnit(DateTickUnit.MINUTE, 2, DateTickUnit.SECOND, 10, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 5, DateTickUnit.MINUTE, 1, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 10, DateTickUnit.MINUTE, 1, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 15, DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 20, DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.MINUTE, 30, DateTickUnit.MINUTE, 5, f3));
// hours
units.add(new DateTickUnit(DateTickUnit.HOUR, 1, DateTickUnit.MINUTE, 5, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 2, DateTickUnit.MINUTE, 10, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 4, DateTickUnit.MINUTE, 30, f3) );
units.add(new DateTickUnit(DateTickUnit.HOUR, 6, DateTickUnit.HOUR, 1, f3));
units.add(new DateTickUnit(DateTickUnit.HOUR, 12, DateTickUnit.HOUR, 1, f4));
// days
units.add(new DateTickUnit(DateTickUnit.DAY, 1, DateTickUnit.HOUR, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 2, DateTickUnit.HOUR, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 7, DateTickUnit.DAY, 1, f5));
units.add(new DateTickUnit(DateTickUnit.DAY, 15, DateTickUnit.DAY, 1, f5));
// months
units.add(new DateTickUnit(DateTickUnit.MONTH, 1, DateTickUnit.DAY, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 2, DateTickUnit.DAY, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 3, DateTickUnit.MONTH, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 4, DateTickUnit.MONTH, 1, f6));
units.add(new DateTickUnit(DateTickUnit.MONTH, 6, DateTickUnit.MONTH, 1, f6));
// years
units.add(new DateTickUnit(DateTickUnit.YEAR, 1, DateTickUnit.MONTH, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 2, DateTickUnit.MONTH, 3, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 5, DateTickUnit.YEAR, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 10, DateTickUnit.YEAR, 1, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 25, DateTickUnit.YEAR, 5, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 50, DateTickUnit.YEAR, 10, f7));
units.add(new DateTickUnit(DateTickUnit.YEAR, 100, DateTickUnit.YEAR, 20, f7));
return units;
}
/**
* Generates a SparkLine Time Area Chart.
* @param key
* @param stats
* @param startTime
* @param endTime
* @return chart
*/
private JFreeChart generateSparklineAreaChart(String key, String color, Statistic [] stats, long startTime, long endTime, int dataPoints) {
Color backgroundColor = getBackgroundColor();
XYDataset dataset = populateData(key, stats, startTime, endTime, dataPoints);
JFreeChart chart = ChartFactory.createXYAreaChart(
null, // chart title
null, // xaxis label
null, // yaxis label
dataset, // data
PlotOrientation.VERTICAL,
false, // include legend
false, // tooltips?
false // URLs?
);
chart.setBackgroundPaint(backgroundColor);
chart.setBorderVisible(false);
chart.setBorderPaint(null);
XYPlot plot = (XYPlot)chart.getPlot();
plot.setForegroundAlpha(1.0f);
plot.setDomainGridlinesVisible(false);
plot.setDomainCrosshairVisible(false);
plot.setRangeCrosshairVisible(false);
plot.setBackgroundPaint(backgroundColor);
plot.setRangeGridlinesVisible(false);
GraphDefinition graphDef = GraphDefinition.getDefinition(color);
Color plotColor = graphDef.getInlineColor(0);
plot.getRenderer().setSeriesPaint(0, plotColor);
plot.getRenderer().setBaseItemLabelsVisible(false);
plot.getRenderer().setBaseOutlinePaint(backgroundColor);
plot.setOutlineStroke(null);
plot.setDomainGridlinePaint(null);
NumberAxis xAxis = (NumberAxis)chart.getXYPlot().getDomainAxis();
xAxis.setLabel(null);
xAxis.setTickLabelsVisible(true);
xAxis.setTickMarksVisible(true);
xAxis.setAxisLineVisible(false);
xAxis.setNegativeArrowVisible(false);
xAxis.setPositiveArrowVisible(false);
xAxis.setVisible(false);
NumberAxis yAxis = (NumberAxis)chart.getXYPlot().getRangeAxis();
yAxis.setTickLabelsVisible(false);
yAxis.setTickMarksVisible(false);
yAxis.setAxisLineVisible(false);
yAxis.setNegativeArrowVisible(false);
yAxis.setPositiveArrowVisible(false);
yAxis.setVisible(false);
return chart;
}
/**
* Creates a Pie Chart based on map.
*
* @return the Pie Chart generated.
*/
public JFreeChart getPieChart(Map<String, Double> pieValues) {
DefaultPieDataset dataset = new DefaultPieDataset();
for (String key : pieValues.keySet()) {
dataset.setValue(key, pieValues.get(key));
}
JFreeChart chart = ChartFactory.createPieChart3D(
null, // chart title
dataset, // data
true, // include legend
true,
false
);
chart.setBackgroundPaint(Color.white);
chart.setBorderVisible(false);
chart.setBorderPaint(null);
PiePlot plot = (PiePlot)chart.getPlot();
plot.setSectionOutlinesVisible(false);
plot.setLabelFont(new Font("SansSerif", Font.BOLD, 12));
plot.setNoDataMessage("No data available");
plot.setCircular(true);
plot.setLabelGap(0.02);
plot.setOutlinePaint(null);
plot.setLabelLinksVisible(false);
plot.setLabelGenerator(null);
plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0}"));
plot.setStartAngle(270);
plot.setDirection(Rotation.ANTICLOCKWISE);
plot.setForegroundAlpha(0.60f);
plot.setInteriorGap(0.33);
return chart;
}
/**
* Generates a Sparkline Bar Graph.
*
* @param def the key of the statistic object.
* @return the generated chart.
*/
public JFreeChart generateSparklineBarGraph(String key, String color, Statistic [] def, long startTime,
long endTime, int dataPoints)
{
Color backgroundColor = getBackgroundColor();
IntervalXYDataset dataset = (IntervalXYDataset) populateData(key, def, startTime, endTime, dataPoints);
JFreeChart chart = ChartFactory.createXYBarChart(
null, // chart title
null, // domain axis label
true,
null, // range axis label
dataset, // data
PlotOrientation.VERTICAL,
false, // include legend
false, // tooltips?
false // URLs?
);
chart.setBackgroundPaint(backgroundColor);
chart.setBorderVisible(false);
chart.setBorderPaint(null);
XYPlot plot = (XYPlot)chart.getPlot();
plot.setDomainGridlinesVisible(false);
plot.setDomainCrosshairVisible(false);
plot.setRangeCrosshairVisible(false);
plot.setBackgroundPaint(backgroundColor);
plot.setRangeGridlinesVisible(false);
GraphDefinition graphDef = GraphDefinition.getDefinition(color);
Color plotColor = graphDef.getInlineColor(0);
plot.getRenderer().setSeriesPaint(0, plotColor);
plot.getRenderer().setBaseItemLabelsVisible(false);
plot.getRenderer().setBaseOutlinePaint(backgroundColor);
plot.setOutlineStroke(null);
plot.setDomainGridlinePaint(null);
ValueAxis xAxis = chart.getXYPlot().getDomainAxis();
xAxis.setLabel(null);
xAxis.setTickLabelsVisible(true);
xAxis.setTickMarksVisible(true);
xAxis.setAxisLineVisible(false);
xAxis.setNegativeArrowVisible(false);
xAxis.setPositiveArrowVisible(false);
xAxis.setVisible(false);
ValueAxis yAxis = chart.getXYPlot().getRangeAxis();
yAxis.setTickLabelsVisible(false);
yAxis.setTickMarksVisible(false);
yAxis.setAxisLineVisible(false);
yAxis.setNegativeArrowVisible(false);
yAxis.setPositiveArrowVisible(false);
yAxis.setVisible(false);
return chart;
}
/**
* Takes a hexidecimel color value and returns its color equivelent.
*
* @param hexColor The hex color to be parsed
* @return The java color object
*/
private static Color getColor(String hexColor) {
return new Color(Integer.valueOf(hexColor.substring(0, 2), 16),
Integer.valueOf(hexColor.substring(2, 4), 16),
Integer.valueOf(hexColor.substring(4, 6), 16));
}
/**
* Returns a color that can be used as a background.
* @return Color
*/
private static Color getBackgroundColor() {
return new Color(255,255,255);
}
public static long[] parseTimePeriod(String timeperiod) {
if (null == timeperiod)
timeperiod = "last60minutes";
Date fromDate = null;
Date toDate = null;
long dataPoints = 60;
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
// Reset the day fields so we're at the beginning of the day.
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// Compute "this week" by resetting the day of the week to the first day of the week
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date thisWeekStart = cal.getTime();
Date thisWeekEnd = now;
// Compute last week - start with the end boundary which is 1 millisecond before the start of this week
cal.add(Calendar.MILLISECOND, -1);
Date lastWeekEnd = cal.getTime();
// Add that millisecond back, subtract 7 days for the start boundary of "last week"
cal.add(Calendar.MILLISECOND, 1);
cal.add(Calendar.DAY_OF_YEAR, -7);
Date lastWeekStart = cal.getTime();
// Reset the time
cal.setTime(now);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// Reset to the 1st day of the month, make the the start boundary for "this month"
cal.set(Calendar.DAY_OF_MONTH, cal.getMinimum(Calendar.DAY_OF_MONTH));
Date thisMonthStart = cal.getTime();
Date thisMonthEnd = now;
// Compute last month
cal.add(Calendar.MILLISECOND, -1);
Date lastMonthEnd = cal.getTime();
cal.add(Calendar.MILLISECOND, 1);
cal.add(Calendar.MONTH, -1);
Date lastMonthStart = cal.getTime();
// Compute last 3 months
cal.setTime(now);
cal.add(Calendar.MONTH, -2);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date last3MonthsStart = cal.getTime();
Date last3MonthsEnd = now;
// Compute last 7 days:
cal.setTime(now);
cal.add(Calendar.DAY_OF_YEAR, -6);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date last7DaysStart = cal.getTime();
Date last7DaysEnd = now;
// Compute last 60 minutes;
cal.setTime(now);
cal.add(Calendar.MINUTE, -60);
Date last60MinutesStart = cal.getTime();
Date last60MinutesEnd = now;
// Compute last 24 hours;
cal.setTime(now);
cal.add(Calendar.HOUR, -23);
Date last24HoursStart = cal.getTime();
Date last24HoursEnd = now;
// Done, reset the cal internal date to now
cal.setTime(now);
if ("thisweek".equals(timeperiod)) {
fromDate = thisWeekStart;
toDate = thisWeekEnd;
dataPoints = 7;
} else if ("last7days".equals(timeperiod)) {
fromDate = last7DaysStart;
toDate = last7DaysEnd;
dataPoints = 7;
} else if ("lastweek".equals(timeperiod)) {
fromDate = lastWeekStart;
toDate = lastWeekEnd;
dataPoints = 7;
} else if ("thismonth".equals(timeperiod)) {
fromDate = thisMonthStart;
toDate = thisMonthEnd;
dataPoints = 30;
} else if ("lastmonth".equals(timeperiod)) {
fromDate = lastMonthStart;
toDate = lastMonthEnd;
dataPoints = 30;
} else if ("last3months".equals(timeperiod)) {
fromDate = last3MonthsStart;
toDate = last3MonthsEnd;
dataPoints = (long)Math.ceil((toDate.getTime() - fromDate.getTime()) / WEEK);
} else if ("last60minutes".equals(timeperiod)) {
fromDate = last60MinutesStart;
toDate = last60MinutesEnd;
dataPoints = 60;
} else if ("last24hours".equals(timeperiod)) {
fromDate = last24HoursStart;
toDate = last24HoursEnd;
dataPoints = 48;
} else {
String[] dates = timeperiod.split("to");
if (dates.length > 0) {
DateFormat formDateFormatter = new SimpleDateFormat("MM/dd/yy");
String fromDateParam = dates[0];
String toDateParam = dates[1];
if (fromDateParam != null) {
try {
fromDate = formDateFormatter.parse(fromDateParam);
}
catch (Exception e) {
// ignore formatting exception
}
}
if (toDateParam != null) {
try {
toDate = formDateFormatter.parse(toDateParam);
// Make this date be the end of the day (so it's the day *inclusive*, not *exclusive*)
Calendar adjusted = Calendar.getInstance();
adjusted.setTime(toDate);
adjusted.set(Calendar.HOUR_OF_DAY, 23);
adjusted.set(Calendar.MINUTE, 59);
adjusted.set(Calendar.SECOND, 59);
adjusted.set(Calendar.MILLISECOND, 999);
toDate = adjusted.getTime();
}
catch (Exception e) {
// ignore formatting exception
}
}
dataPoints = discoverDataPoints(fromDate, toDate);
}
}
// default to last 60 minutes
if (null == fromDate && null==toDate) {
return new long[] {last60MinutesStart.getTime(), last60MinutesEnd.getTime(), dataPoints};
} else if (null == fromDate) {
return new long[] {0, toDate.getTime(), dataPoints};
} else if (null == toDate) {
return new long[] {fromDate.getTime(), now.getTime(), dataPoints};
} else {
return new long[] {fromDate.getTime(), toDate.getTime(), dataPoints};
}
}
private static int discoverDataPoints(Date fromDate, Date toDate) {
long delta = toDate.getTime() - fromDate.getTime();
if(delta > YEAR) {
return (int)(delta / MONTH);
}
else if (delta > 2 * MONTH) {
return (int)(delta / WEEK);
}
else {
return (int)(delta / DAY);
}
}
public static class GraphDefinition {
public static final GraphDefinition standard_light;
public static final GraphDefinition standard_dark;
private Color[] inlineColors;
private Color[] outlineColors;
static {
standard_light = new GraphDefinition(
new Color[]{new Color(246, 171, 77), getColor("B1C3D9")},
new Color[]{new Color(217, 126, 12), getColor("17518C")}
);
standard_dark = new GraphDefinition(
new Color[]{new Color(116, 128, 141), getColor("74808D")},
new Color[]{new Color(116, 128, 141), getColor("74808D")}
);
}
public static GraphDefinition getDefinition(String colorscheme) {
GraphDefinition graphDef = GraphDefinition.standard_light;
if (colorscheme != null && colorscheme.equalsIgnoreCase("dark")) {
graphDef = GraphDefinition.standard_dark;
}
return graphDef;
}
public GraphDefinition(Color[] inlineColors, Color[] outlineColors) {
this.inlineColors = inlineColors;
this.outlineColors = outlineColors;
}
public Color getInlineColor(int index) {
return inlineColors[index];
}
public Color[] getInlineColors() {
return inlineColors;
}
public Color getOutlineColor(int index) {
return outlineColors[index];
}
public Color[] getOutlineColors() {
return outlineColors;
}
}
}