/** * $URL:$ * $Id:$ * * Copyright (c) 2006-2009 The Sakai Foundation * * Licensed under the Educational Community 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.osedu.org/licenses/ECL-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.sakaiproject.sitestats.impl; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.sql.ResultSet; import java.sql.SQLException; import java.text.DateFormat; import java.text.NumberFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.imageio.ImageIO; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.CategoryLabelPositions; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.DateTickMarkPosition; import org.jfree.chart.axis.DateTickUnit; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.labels.CategoryItemLabelGenerator; import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.CombinedDomainXYPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.category.BarRenderer; import org.jfree.chart.renderer.category.CategoryItemRenderer; import org.jfree.chart.renderer.category.LayeredBarRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.title.LegendTitle; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.data.statistics.BoxAndWhiskerCategoryDataset; import org.jfree.data.statistics.DefaultBoxAndWhiskerCategoryDataset; import org.jfree.data.time.Day; import org.jfree.data.time.Month; import org.jfree.data.time.MovingAverage; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.time.Week; import org.jfree.data.xy.IntervalXYDataset; import org.jfree.ui.RectangleInsets; import org.jfree.util.SortOrder; import org.sakaiproject.db.api.SqlReader; import org.sakaiproject.db.api.SqlService; import org.sakaiproject.event.api.UsageSessionService; import org.sakaiproject.sitestats.api.ServerWideReportManager; import org.sakaiproject.sitestats.api.ServerWideStatsRecord; import org.sakaiproject.sitestats.api.StatsManager; import org.sakaiproject.util.ResourceLoader; /** * @author u4330369 * */ public class ServerWideReportManagerImpl implements ServerWideReportManager { /** Our log (commons). */ private static Log LOG = LogFactory .getLog (ServerWideReportManagerImpl.class); /** Message bundle */ private static ResourceLoader msgs = new ResourceLoader("Messages"); /** Dependency: SqlService */ private SqlService m_sqlService = null; /** Dependence: StatsManager */ private StatsManager M_sm = null; public void setStatsManager (StatsManager statsManager) { this.M_sm = statsManager; } /** * Dependency: SqlService. * * @param service * The SqlService. */ public void setSqlService (SqlService service) { m_sqlService = service; } /** Dependency: UsageSessionService */ private UsageSessionService m_usageSessionService; public void setUsageSessionService (UsageSessionService usageSessionService) { this.m_usageSessionService = usageSessionService; } public void init () { } public void destroy () { } /* * (non-Javadoc) * * @see org.sakaiproject.sitestats.api.ServerWideReportManager#getMonthlyLogin() */ public List<ServerWideStatsRecord> getMonthlyLogin () { String mySql = "select STR_TO_DATE(date_format(SESSION_START, '%Y-%m-01'),'%Y-%m-%d') as period, " + "count(*) as user_logins, " + "count(distinct SESSION_USER) as unique_users " + "from SAKAI_SESSION " + "group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); info.add (result.getLong (3)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } /* * (non-Javadoc) * * @see org.sakaiproject.sitestats.api.ServerWideReportManager#getWeeklyLogin() */ public List<ServerWideStatsRecord> getWeeklyLogin () { String mySql = "select STR_TO_DATE(concat(date_format(SESSION_START, '%x-%v'), ' Monday'),'%x-%v %W') as week_start," + " count(*) as user_logins, count(distinct SESSION_USER) as unique_users" + " from SAKAI_SESSION" + " group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); info.add (result.getLong (3)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } public List<ServerWideStatsRecord> getDailyLogin () { String mySql = "select date(SESSION_START) as session_date," + " count(*) as user_logins," + " count(distinct SESSION_USER) as unique_users" + " from SAKAI_SESSION" + " where SESSION_START > DATE_SUB(CURDATE(), INTERVAL 90 DAY)" + " group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); info.add (result.getLong (3)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } public List<ServerWideStatsRecord> getSiteCreatedDeletedStats (String period) { String sqlPeriod = ""; if (period.equals ("daily")) { sqlPeriod = "date(EVENT_DATE) as event_period"; } else if (period.equals ("weekly")) { sqlPeriod = "STR_TO_DATE(date_format(EVENT_DATE, '%x-%v Monday'),'%x-%v %W') as event_period"; } else { // monthly sqlPeriod = "STR_TO_DATE(date_format(EVENT_DATE, '%Y-%m-01'),'%Y-%m-%d') as event_period"; } String mySql = "select " + sqlPeriod + ", " + "sum(if(event = 'site.add' && ref not regexp '/site/[~!]',1,0)) as site_created, " + "sum(if(event = 'site.del' && ref not regexp '/site/[~!]',1,0)) as site_deleted " + "FROM SAKAI_EVENT "; if (period.equals ("daily")) { mySql = mySql + "where EVENT_DATE > DATE_SUB(CURDATE(), INTERVAL 90 DAY) "; } mySql = mySql + "group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); info.add (result.getLong (3)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } public List<ServerWideStatsRecord> getNewUserStats (String period) { String sqlPeriod = ""; if (period.equals ("daily")) { sqlPeriod = "date(EVENT_DATE) as event_period"; } else if (period.equals ("weekly")) { sqlPeriod = "STR_TO_DATE(date_format(EVENT_DATE, '%x-%v Monday'),'%x-%v %W') as event_period"; } else { // monthly sqlPeriod = "STR_TO_DATE(date_format(EVENT_DATE, '%Y-%m-01'),'%Y-%m-%d') as event_period"; } String mySql = "select " + sqlPeriod + ", " + "sum(if(event = 'site.add' && ref regexp '/site/[~!]',1,0)) as new_user " + "FROM SAKAI_EVENT "; if (period.equals ("daily")) { mySql = mySql + "where EVENT_DATE > DATE_SUB(CURDATE(), INTERVAL 90 DAY) "; } mySql = mySql + "group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } public List<ServerWideStatsRecord> getTop20Activities () { String mySql = "SELECT event, " + "sum(if(event_date > DATE_SUB(CURDATE(), INTERVAL 7 DAY),1,0))/7 as last7, " + "sum(if(event_date > DATE_SUB(CURDATE(), INTERVAL 30 DAY),1,0))/30 as last30, " + "sum(if(event_date > DATE_SUB(CURDATE(), INTERVAL 365 DAY),1,0))/365 as last365 " + "FROM SAKAI_EVENT " + "where event not in ('content.read', 'user.login', 'user.logout', 'pres.end', " + "'realm.upd', 'realm.add', 'realm.del', 'realm.upd.own') " + "and event_date > DATE_SUB(CURDATE(), INTERVAL 365 DAY) " + "group by 1 " + "order by 2 desc, 3 desc, 4 desc " + "LIMIT 20"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getString (1)); info.add (result.getDouble (2)); info.add (result.getDouble (3)); info.add (result.getDouble (4)); } catch (SQLException e) { return null; } return info; } }); return result; } public List<ServerWideStatsRecord> getWeeklyRegularUsers () { String mySql = "select s.week_start, sum(if(s.user_logins >= 5,1,0)) as five_plus, " + "sum(if(s.user_logins = 4,1,0)) as four, " + "sum(if(s.user_logins = 3,1,0)) as three, " + "sum(if(s.user_logins = 2,1,0)) as twice, " + "sum(if(s.user_logins = 1,1,0)) as once " + "from (select " + "STR_TO_DATE(concat(date_format(session_start, '%x-%v'), ' Monday'),'%x-%v %W') as week_start, " + "session_user, count(*) as user_logins " + "from SAKAI_SESSION group by 1, 2) as s " + "group by 1"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getLong (2)); info.add (result.getLong (3)); info.add (result.getLong (4)); info.add (result.getLong (5)); info.add (result.getLong (6)); } catch (SQLException e) { return null; } return info; } }); // remove the last entry, as it might not be a complete period result.remove (result.size () - 1); return result; } public List<ServerWideStatsRecord> getHourlyUsagePattern () { String mySql = "select date(SESSION_START) as session_date, " + "hour(session_start) as hour_start, " + "count(distinct SESSION_USER) as unique_users " + "from SAKAI_SESSION " + "where SESSION_START > DATE_SUB(CURDATE(), INTERVAL 30 DAY) " + "group by 1, 2"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getDate (1)); info.add (result.getInt (2)); info.add (result.getLong (3)); } catch (SQLException e) { return null; } return info; } }); return result; } public List<ServerWideStatsRecord> getToolCount () { String mySql = "SELECT registration, count(*) as site_count " + "FROM SAKAI_SITE_TOOL " + "where site_id regexp '^[[:digit:]]' " + "group by 1 " + "order by 2 desc"; List result = m_sqlService.dbRead (mySql, null, new SqlReader () { public Object readSqlResultRecord (ResultSet result) { ServerWideStatsRecord info = new ServerWideStatsRecordImpl (); try { info.add (result.getString (1)); info.add (result.getInt (2)); } catch (SQLException e) { return null; } return info; } }); return result; } public byte[] generateReportChart(String reportType, int width, int height) { if(reportType.equals(StatsManager.MONTHLY_LOGIN_REPORT)){ return createMonthlyLoginChart(width, height); }else if(reportType.equals(StatsManager.WEEKLY_LOGIN_REPORT)){ return createWeeklyLoginChart(width, height); }else if(reportType.equals(StatsManager.DAILY_LOGIN_REPORT)){ return createDailyLoginChart(width, height); }else if(reportType.equals(StatsManager.REGULAR_USERS_REPORT)){ CategoryDataset dataset = getRegularUsersDataSet(); if(dataset != null){ return generateStackedAreaChart(dataset, width, height); }else{ return generateNoDataChart(width, height); } }else if(reportType.equals(StatsManager.HOURLY_USAGE_REPORT)){ BoxAndWhiskerCategoryDataset dataset = getHourlyUsageDataSet(); if(dataset != null){ return generateBoxAndWhiskerChart(dataset, width, height); }else{ return generateNoDataChart(width, height); } }else if(reportType.equals(StatsManager.TOP_ACTIVITIES_REPORT)){ CategoryDataset dataset = getTopActivitiesDataSet(); if(dataset != null){ return generateLayeredBarChart(dataset, width, height); }else{ return generateNoDataChart(width, height); } }else if(reportType.equals(StatsManager.TOOL_REPORT)){ return createToolAnalysisChart(width, height); }else{ return generateNoDataChart(width, height); } } private IntervalXYDataset getMonthlyLoginsDataSet () { List<ServerWideStatsRecord> loginList = getMonthlyLogin (); if (loginList == null) { return null; } TimeSeries s1 = new TimeSeries (msgs.getString ("legend_logins"), Month.class); for (ServerWideStatsRecord login : loginList) { Month month = new Month ((Date) login.get (0)); s1.add (month, (Long) login.get (1)); } TimeSeriesCollection dataset = new TimeSeriesCollection (); dataset.addSeries (s1); return dataset; } private IntervalXYDataset getMonthlyUniqueLoginsDataSet () { List<ServerWideStatsRecord> loginList = getMonthlyLogin (); if (loginList == null) { return null; } TimeSeries s2 = new TimeSeries ( msgs.getString ("legend_unique_logins"), Month.class); for (ServerWideStatsRecord login : loginList) { Month month = new Month ((Date) login.get (0)); s2.add (month, (Long) login.get (2)); } TimeSeriesCollection dataset = new TimeSeriesCollection (); dataset.addSeries (s2); return dataset; } private IntervalXYDataset getWeeklyLoginsDataSet () { // LOG.info("Generating activityWeekBarDataSet"); List<ServerWideStatsRecord> loginList = getWeeklyLogin (); if (loginList == null) { return null; } TimeSeries s1 = new TimeSeries (msgs.getString ("legend_logins"), Week.class); TimeSeries s2 = new TimeSeries ( msgs.getString ("legend_unique_logins"), Week.class); for (ServerWideStatsRecord login : loginList) { Week week = new Week ((Date) login.get (0)); s1.add (week, (Long) login.get (1)); s2.add (week, (Long) login.get (2)); } TimeSeriesCollection dataset = new TimeSeriesCollection (); dataset.addSeries (s1); dataset.addSeries (s2); return dataset; } private IntervalXYDataset getDailyLoginsDataSet () { // LOG.info("Generating activityWeekBarDataSet"); List<ServerWideStatsRecord> loginList = getDailyLogin (); if (loginList == null) { return null; } TimeSeries s1 = new TimeSeries (msgs.getString ("legend_logins"), Day.class); TimeSeries s2 = new TimeSeries ( msgs.getString ("legend_unique_logins"), Day.class); for (ServerWideStatsRecord login : loginList) { Day day = new Day ((Date) login.get (0)); s1.add (day, (Long) login.get (1)); s2.add (day, (Long) login.get (2)); } TimeSeriesCollection dataset = new TimeSeriesCollection (); dataset.addSeries (s1); dataset.addSeries (s2); TimeSeries mavS1 = MovingAverage.createMovingAverage (s1, msgs.getString("legend_7day_logins"), 7, 7); dataset.addSeries (mavS1); TimeSeries mavS2 = MovingAverage.createMovingAverage (s2, msgs.getString("legend_7day_unique_logins"), 7, 7); dataset.addSeries (mavS2); return dataset; } private IntervalXYDataset getMonthlySiteUserDataSet () { List<ServerWideStatsRecord> siteCreatedDeletedList = getSiteCreatedDeletedStats ("monthly"); TimeSeriesCollection dataset = new TimeSeriesCollection (); if (siteCreatedDeletedList != null) { TimeSeries s1 = new TimeSeries (msgs.getString ("legend_site_created"), Month.class); TimeSeries s2 = new TimeSeries (msgs.getString ("legend_site_deleted"), Month.class); for (ServerWideStatsRecord login : siteCreatedDeletedList) { Month month = new Month ((Date) login.get (0)); s1.add (month, (Long) login.get (1)); s2.add (month, (Long) login.get (2)); } dataset.addSeries (s1); dataset.addSeries (s2); } List<ServerWideStatsRecord> newUserList = getNewUserStats ("monthly"); if (newUserList != null) { TimeSeries s3 = new TimeSeries (msgs.getString ("legend_new_user"), Month.class); for (ServerWideStatsRecord login : newUserList) { Month month = new Month ((Date) login.get (0)); s3.add (month, (Long) login.get (1)); } dataset.addSeries (s3); } return dataset; } private IntervalXYDataset getWeeklySiteUserDataSet () { List<ServerWideStatsRecord> siteCreatedDeletedList = getSiteCreatedDeletedStats ("weekly"); TimeSeriesCollection dataset = new TimeSeriesCollection (); if (siteCreatedDeletedList != null) { TimeSeries s1 = new TimeSeries (msgs.getString ("legend_site_created"), Week.class); TimeSeries s2 = new TimeSeries (msgs.getString ("legend_site_deleted"), Week.class); for (ServerWideStatsRecord login : siteCreatedDeletedList) { Week week = new Week ((Date) login.get (0)); s1.add (week, (Long) login.get (1)); s2.add (week, (Long) login.get (2)); } dataset.addSeries (s1); dataset.addSeries (s2); } List<ServerWideStatsRecord> newUserList = getNewUserStats ("weekly"); if (newUserList != null) { TimeSeries s3 = new TimeSeries (msgs.getString ("legend_new_user"), Week.class); for (ServerWideStatsRecord login : newUserList) { Week week = new Week ((Date) login.get (0)); s3.add (week, (Long) login.get (1)); } dataset.addSeries (s3); } return dataset; } private IntervalXYDataset getDailySiteUserDataSet () { List<ServerWideStatsRecord> siteCreatedDeletedList = getSiteCreatedDeletedStats ("daily"); TimeSeriesCollection dataset = new TimeSeriesCollection (); if (siteCreatedDeletedList != null) { TimeSeries s1 = new TimeSeries (msgs.getString ("legend_site_created"), Day.class); TimeSeries s2 = new TimeSeries (msgs.getString ("legend_site_deleted"), Day.class); for (ServerWideStatsRecord login : siteCreatedDeletedList) { Day day = new Day ((Date) login.get (0)); s1.add (day, (Long) login.get (1)); s2.add (day, (Long) login.get (2)); } dataset.addSeries (s1); dataset.addSeries (s2); } List<ServerWideStatsRecord> newUserList = getNewUserStats ("daily"); if (newUserList != null) { TimeSeries s3 = new TimeSeries (msgs.getString ("legend_new_user"), Day.class); for (ServerWideStatsRecord login : newUserList) { Day day = new Day ((Date) login.get (0)); s3.add (day, (Long) login.get (1)); } dataset.addSeries (s3); } return dataset; } private CategoryDataset getRegularUsersDataSet () { List<ServerWideStatsRecord> regularUsersList = getWeeklyRegularUsers (); if (regularUsersList == null) { return null; } DefaultCategoryDataset dataset = new DefaultCategoryDataset (); DateFormat formatter = new SimpleDateFormat ("yyyy-MM-dd"); for (ServerWideStatsRecord regularUsers : regularUsersList) { Date weekStart = ((Date) regularUsers.get (0)); dataset.addValue ((Long) regularUsers.get (1), "5+", formatter .format (weekStart)); dataset.addValue ((Long) regularUsers.get (2), "4", formatter .format (weekStart)); dataset.addValue ((Long) regularUsers.get (3), "3", formatter .format (weekStart)); dataset.addValue ((Long) regularUsers.get (4), "2", formatter .format (weekStart)); dataset.addValue ((Long) regularUsers.get (5), "1", formatter .format (weekStart)); } return dataset; } private BoxAndWhiskerCategoryDataset getHourlyUsageDataSet () { // LOG.info("Generating activityWeekBarDataSet"); List<ServerWideStatsRecord> hourlyUsagePattern = getHourlyUsagePattern (); if (hourlyUsagePattern == null) { return null; } DefaultBoxAndWhiskerCategoryDataset dataset = new DefaultBoxAndWhiskerCategoryDataset (); List[] hourList = new ArrayList[24]; for (int ii = 0; ii < 24; ii++) { hourList[ii] = new ArrayList (); } int totalDays = 0; Date prevDate = null; for (ServerWideStatsRecord regularUsers : hourlyUsagePattern) { Date currDate = (Date) regularUsers.get (0); if (!currDate.equals (prevDate)) { prevDate = currDate; totalDays++; } hourList[(Integer) regularUsers.get (1)].add ((Long) regularUsers .get (2)); } for (int ii = 0; ii < 24; ii++) { // add zero counts, when no data for the day for (int jj = hourList[ii].size (); jj < totalDays; jj++) { hourList[ii].add (Long.valueOf(0)); } dataset.add (hourList[ii], "Last 30 days", "" + ii); } return dataset; } private CategoryDataset getTopActivitiesDataSet () { List<ServerWideStatsRecord> topActivitiesList = getTop20Activities (); if (topActivitiesList == null) { return null; } DefaultCategoryDataset dataset = new DefaultCategoryDataset (); for (ServerWideStatsRecord regularUsers : topActivitiesList) { String event = (String) regularUsers.get (0); dataset.addValue ((Double) regularUsers.get (1), "last 7 days", event); dataset.addValue ((Double) regularUsers.get (2), "last 30 days", event); dataset.addValue ((Double) regularUsers.get (3), "last 365 days", event); } return dataset; } private CategoryDataset getToolAnalysisDataSet () { List<ServerWideStatsRecord> toolCountList = getToolCount (); if (toolCountList == null) { return null; } DefaultCategoryDataset dataset = new DefaultCategoryDataset (); for (ServerWideStatsRecord regularUsers : toolCountList) { String toolId = (String) regularUsers.get (0); dataset.addValue ((Integer) regularUsers.get (1), "", toolId); } return dataset; } private byte[] createMonthlyLoginChart (int width, int height) { IntervalXYDataset dataset1 = getMonthlyLoginsDataSet (); IntervalXYDataset dataset2 = getMonthlyUniqueLoginsDataSet (); IntervalXYDataset dataset3 = getMonthlySiteUserDataSet (); if ((dataset1 == null) || (dataset3 == null)) { return generateNoDataChart(width, height); } // create plot ... XYItemRenderer renderer1 = new XYLineAndShapeRenderer(true, false); renderer1.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer1.setSeriesPaint (0, Color.RED); DateAxis domainAxis = new DateAxis(""); domainAxis.setTickUnit (new DateTickUnit (DateTickUnit.MONTH, 1, new SimpleDateFormat ("yyyy-MM"))); domainAxis.setTickMarkPosition (DateTickMarkPosition.START); domainAxis.setVerticalTickLabels (true); domainAxis.setLowerMargin (0.01); domainAxis.setUpperMargin (0.01); NumberAxis axis1 = new NumberAxis(msgs.getString("legend_total_logins")); axis1.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); axis1.setLabelPaint(Color.RED); axis1.setTickLabelPaint(Color.RED); XYPlot plot1 = new XYPlot(dataset1, null, axis1, renderer1); plot1.setBackgroundPaint(Color.lightGray); plot1.setDomainGridlinePaint(Color.white); plot1.setRangeGridlinePaint(Color.white); // AXIS 2 NumberAxis axis2 = new NumberAxis(msgs.getString("legend_total_unique_users")); axis2.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); axis2.setLabelPaint(Color.BLUE); axis2.setTickLabelPaint(Color.BLUE); plot1.setRangeAxis(1, axis2); plot1.setDataset(1, dataset2); plot1.mapDatasetToRangeAxis(1, 1); XYItemRenderer renderer2 = new XYLineAndShapeRenderer(true, false); renderer2.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesPaint (0, Color.BLUE); plot1.setRenderer(1, renderer2); // add a third dataset and renderer... XYItemRenderer renderer3 = new XYLineAndShapeRenderer(true, false); renderer3.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer3.setSeriesStroke(1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer3.setSeriesStroke(2, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer3.setSeriesPaint(0, Color.GREEN); renderer3.setSeriesPaint(1, Color.BLACK); renderer3.setSeriesPaint(2, Color.CYAN); axis1 = new NumberAxis(msgs.getString("axis_count")); axis1.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); XYPlot plot2 = new XYPlot(dataset3, null, axis1, renderer3); plot2.setBackgroundPaint(Color.lightGray); plot2.setDomainGridlinePaint(Color.white); plot2.setRangeGridlinePaint(Color.white); CombinedDomainXYPlot cplot = new CombinedDomainXYPlot(domainAxis); cplot.add(plot1, 3); cplot.add(plot2, 2); cplot.setGap(8.0); cplot.setDomainGridlinePaint(Color.white); cplot.setDomainGridlinesVisible(true); // return a new chart containing the overlaid plot... JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, cplot, false); LegendTitle legend = new LegendTitle(cplot); chart.addSubtitle(legend); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] createWeeklyLoginChart (int width, int height) { IntervalXYDataset dataset1 = getWeeklyLoginsDataSet (); IntervalXYDataset dataset2 = getWeeklySiteUserDataSet (); if ((dataset1 == null) || (dataset2 == null)) { return generateNoDataChart(width, height); } // create plot ... XYItemRenderer renderer1 = new XYLineAndShapeRenderer(true, false); renderer1.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer1.setSeriesStroke(1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer1.setSeriesPaint (0, Color.RED); renderer1.setSeriesPaint (0, Color.BLUE); DateAxis domainAxis = new DateAxis(""); domainAxis.setTickUnit (new DateTickUnit (DateTickUnit.DAY, 7, new SimpleDateFormat ("yyyy-MM-dd"))); domainAxis.setTickMarkPosition (DateTickMarkPosition.START); domainAxis.setVerticalTickLabels (true); domainAxis.setLowerMargin (0.01); domainAxis.setUpperMargin (0.01); NumberAxis rangeAxis = new NumberAxis(msgs.getString("axis_count")); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); XYPlot plot1 = new XYPlot(dataset1, null, rangeAxis, renderer1); plot1.setBackgroundPaint(Color.lightGray); plot1.setDomainGridlinePaint(Color.white); plot1.setRangeGridlinePaint(Color.white); // add a second dataset and renderer... XYItemRenderer renderer2 = new XYLineAndShapeRenderer(true, false); renderer2.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesStroke(1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesStroke(2, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesPaint(0, Color.GREEN); renderer2.setSeriesPaint(1, Color.BLACK); renderer2.setSeriesPaint(2, Color.CYAN); rangeAxis = new NumberAxis(msgs.getString("axis_count")); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); XYPlot plot2 = new XYPlot(dataset2, null, rangeAxis, renderer2); plot2.setBackgroundPaint(Color.lightGray); plot2.setDomainGridlinePaint(Color.white); plot2.setRangeGridlinePaint(Color.white); CombinedDomainXYPlot cplot = new CombinedDomainXYPlot(domainAxis); cplot.add(plot1, 3); cplot.add(plot2, 2); cplot.setGap(8.0); cplot.setDomainGridlinePaint(Color.white); cplot.setDomainGridlinesVisible(true); // return a new chart containing the overlaid plot... JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, cplot, false); LegendTitle legend = new LegendTitle(cplot); chart.addSubtitle(legend); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] createDailyLoginChart (int width, int height) { IntervalXYDataset dataset1 = getDailyLoginsDataSet (); IntervalXYDataset dataset2 = getDailySiteUserDataSet (); if ((dataset1 == null) || (dataset2 == null)) { return generateNoDataChart(width, height); } // create plot ... XYItemRenderer renderer1 = new XYLineAndShapeRenderer(true, false); renderer1.setSeriesPaint (0, Color.RED); renderer1.setSeriesPaint (1, Color.BLUE); renderer1.setSeriesPaint (2, Color.RED); renderer1.setSeriesPaint (3, Color.BLUE); renderer1.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer1.setSeriesStroke(1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); BasicStroke dashLineStroke = new BasicStroke (2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 0, new float[] { 4 }, 0); renderer1.setSeriesStroke (2, dashLineStroke); renderer1.setSeriesStroke (3, dashLineStroke); DateAxis domainAxis = new DateAxis(""); domainAxis.setTickUnit (new DateTickUnit (DateTickUnit.DAY, 7, new SimpleDateFormat ("yyyy-MM-dd"))); domainAxis.setTickMarkPosition (DateTickMarkPosition.START); domainAxis.setVerticalTickLabels (true); domainAxis.setLowerMargin (0.01); domainAxis.setUpperMargin (0.01); NumberAxis rangeAxis = new NumberAxis(msgs.getString("axis_count")); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); XYPlot plot1 = new XYPlot(dataset1, null, rangeAxis, renderer1); plot1.setBackgroundPaint(Color.lightGray); plot1.setDomainGridlinePaint(Color.white); plot1.setRangeGridlinePaint(Color.white); // add a second dataset and renderer... XYItemRenderer renderer2 = new XYLineAndShapeRenderer(true, false); renderer2.setSeriesStroke(0, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesStroke(1, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesStroke(2, new BasicStroke(2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); renderer2.setSeriesPaint(0, Color.GREEN); renderer2.setSeriesPaint(1, Color.BLACK); renderer2.setSeriesPaint(2, Color.CYAN); rangeAxis = new NumberAxis(msgs.getString("axis_count")); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); XYPlot plot2 = new XYPlot(dataset2, null, rangeAxis, renderer2); plot2.setBackgroundPaint(Color.lightGray); plot2.setDomainGridlinePaint(Color.white); plot2.setRangeGridlinePaint(Color.white); CombinedDomainXYPlot cplot = new CombinedDomainXYPlot(domainAxis); cplot.add(plot1, 3); cplot.add(plot2, 2); cplot.setGap(8.0); cplot.setDomainGridlinePaint(Color.white); cplot.setDomainGridlinesVisible(true); // return a new chart containing the overlaid plot... JFreeChart chart = new JFreeChart(null, JFreeChart.DEFAULT_TITLE_FONT, cplot, false); LegendTitle legend = new LegendTitle(cplot); chart.addSubtitle(legend); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] generateStackedAreaChart (CategoryDataset dataset, int width, int height) { JFreeChart chart = ChartFactory.createStackedAreaChart (null, // chart title null, // domain axis label null, // range axis label dataset, // data PlotOrientation.VERTICAL, // the plot orientation true, // legend true, // tooltips false // urls ); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); CategoryPlot plot = (CategoryPlot) chart.getPlot (); // set transparency plot.setForegroundAlpha (0.7f); plot.setAxisOffset (new RectangleInsets (5.0, 5.0, 5.0, 5.0)); plot.setBackgroundPaint (Color.lightGray); plot.setDomainGridlinesVisible (true); plot.setDomainGridlinePaint (Color.white); plot.setRangeGridlinesVisible (true); plot.setRangeGridlinePaint (Color.white); // set colour of regular users using Karate belt colour: white, green, blue, brown, black/gold CategoryItemRenderer renderer = plot.getRenderer (); renderer.setSeriesPaint (0, new Color (205, 173, 0)); // gold users renderer.setSeriesPaint (1, new Color (139, 69, 19)); renderer.setSeriesPaint (2, Color.BLUE); renderer.setSeriesPaint (3, Color.GREEN); renderer.setSeriesPaint (4, Color.WHITE); // set the range axis to display integers only... NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis (); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); CategoryAxis domainAxis = (CategoryAxis) plot.getDomainAxis (); domainAxis.setCategoryLabelPositions (CategoryLabelPositions.DOWN_45); domainAxis.setLowerMargin(0.0); domainAxis.setUpperMargin(0.0); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] generateBoxAndWhiskerChart (BoxAndWhiskerCategoryDataset dataset, int width, int height) { JFreeChart chart = ChartFactory.createBoxAndWhiskerChart (null, null, null, dataset, false); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); CategoryPlot plot = (CategoryPlot) chart.getPlot (); plot.setDomainGridlinePaint (Color.white); plot.setDomainGridlinesVisible (true); plot.setRangeGridlinePaint (Color.white); NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis (); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); CategoryAxis domainAxis = (CategoryAxis) plot.getDomainAxis (); domainAxis.setLowerMargin (0.0); domainAxis.setUpperMargin (0.0); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] generateLayeredBarChart (CategoryDataset dataset, int width, int height) { JFreeChart chart = ChartFactory.createBarChart (null, // chart title null, // domain axis label null, // range axis label dataset, // data PlotOrientation.VERTICAL, // the plot orientation true, // legend true, // tooltips false // urls ); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); CategoryPlot plot = (CategoryPlot) chart.getPlot (); // disable bar outlines... LayeredBarRenderer renderer = new LayeredBarRenderer (); renderer.setDrawBarOutline (false); renderer.setSeriesBarWidth (0, .6); renderer.setSeriesBarWidth (1, .8); renderer.setSeriesBarWidth (2, 1.0); plot.setRenderer (renderer); // for this renderer, we need to draw the first series last... plot.setRowRenderingOrder (SortOrder.DESCENDING); // set up gradient paints for series... GradientPaint gp0 = new GradientPaint (0.0f, 0.0f, Color.blue, 0.0f, 0.0f, new Color (0, 0, 64)); GradientPaint gp1 = new GradientPaint (0.0f, 0.0f, Color.green, 0.0f, 0.0f, new Color (0, 64, 0)); GradientPaint gp2 = new GradientPaint (0.0f, 0.0f, Color.red, 0.0f, 0.0f, new Color (64, 0, 0)); renderer.setSeriesPaint (0, gp0); renderer.setSeriesPaint (1, gp1); renderer.setSeriesPaint (2, gp2); CategoryAxis domainAxis = (CategoryAxis) plot.getDomainAxis (); domainAxis.setCategoryLabelPositions (CategoryLabelPositions.DOWN_45); domainAxis.setLowerMargin (0.0); domainAxis.setUpperMargin (0.0); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] createToolAnalysisChart (int width, int height) { CategoryDataset dataset = getToolAnalysisDataSet (); if (dataset == null) { return generateNoDataChart(width, height); } JFreeChart chart = ChartFactory.createBarChart ( null, // chart title null, // domain axis label null, // range axis label dataset, // data PlotOrientation.HORIZONTAL, // the plot orientation false, // legend false, // tooltips false // urls ); // set background chart.setBackgroundPaint (parseColor (M_sm.getChartBackgroundColor ())); // set chart border chart.setPadding (new RectangleInsets (10, 5, 5, 5)); chart.setBorderVisible (true); chart.setBorderPaint (parseColor ("#cccccc")); // set anti alias chart.setAntiAlias (true); CategoryPlot plot = (CategoryPlot) chart.getPlot (); // set transparency plot.setForegroundAlpha (0.7f); plot.setAxisOffset (new RectangleInsets (5.0, 5.0, 5.0, 5.0)); plot.setBackgroundPaint (Color.lightGray); plot.setDomainGridlinesVisible (false); plot.setRangeGridlinesVisible (true); plot.setRangeGridlinePaint (Color.white); CategoryAxis domainAxis = plot.getDomainAxis(); domainAxis.setVisible(false); domainAxis.setUpperMargin (0); domainAxis.setLowerMargin (0); NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setUpperMargin(0.20); rangeAxis.setStandardTickUnits (NumberAxis.createIntegerTickUnits ()); BarRenderer renderer = (BarRenderer) plot.getRenderer(); CategoryItemLabelGenerator generator = new StandardCategoryItemLabelGenerator("{1}", NumberFormat.getInstance()); renderer.setBaseItemLabelGenerator(generator); renderer.setBaseItemLabelFont(new Font("SansSerif", Font.PLAIN, 9)); renderer.setBaseItemLabelsVisible(true); renderer.setItemMargin (0); renderer.setSeriesPaint (0, Color.BLUE); BufferedImage img = chart.createBufferedImage (width, height); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } private byte[] generateNoDataChart(int width, int height) { BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = img.createGraphics(); g2d.setBackground(parseColor(M_sm.getChartBackgroundColor())); g2d.clearRect(0, 0, width-1, height-1); g2d.setColor(parseColor("#cccccc")); g2d.drawRect(0, 0, width-1, height-1); Font f = new Font("SansSerif", Font.PLAIN, 12); g2d.setFont(f); FontMetrics fm = g2d.getFontMetrics(f); String noData = msgs.getString("no_data"); int noDataWidth = fm.stringWidth(noData); int noDataHeight = fm.getHeight(); g2d.setColor(parseColor("#555555")); g2d.drawString(noData, width/2 - noDataWidth/2, height/2 - noDataHeight/2 + 2); final ByteArrayOutputStream out = new ByteArrayOutputStream(); try{ ImageIO.write(img, "png", out); }catch(IOException e){ LOG.warn("Error occurred while generating SiteStats chart image data", e); } return out.toByteArray(); } public static Color parseColor(String color) { if(color != null) { if(color.trim().startsWith("#")){ // HTML colors (#FFFFFF format) return new Color(Integer.parseInt(color.substring(1), 16)); }else if(color.trim().startsWith("rgb")){ // HTML colors (rgb(255, 255, 255) format) String values = color.substring(color.indexOf("(") + 1, color.indexOf(")")); String rgb[] = values.split(","); return new Color(Integer.parseInt(rgb[0].trim()), Integer.parseInt(rgb[1].trim()), Integer.parseInt(rgb[2].trim())); }else{ // Colors by name if(color.equalsIgnoreCase("black")) return Color.black; if(color.equalsIgnoreCase("grey")) return Color.gray; if(color.equalsIgnoreCase("yellow")) return Color.yellow; if(color.equalsIgnoreCase("green")) return Color.green; if(color.equalsIgnoreCase("blue")) return Color.blue; if(color.equalsIgnoreCase("red")) return Color.red; if(color.equalsIgnoreCase("orange")) return Color.orange; if(color.equalsIgnoreCase("cyan")) return Color.cyan; if(color.equalsIgnoreCase("magenta")) return Color.magenta; if(color.equalsIgnoreCase("darkgray")) return Color.darkGray; if(color.equalsIgnoreCase("lightgray")) return Color.lightGray; if(color.equalsIgnoreCase("pink")) return Color.pink; if(color.equalsIgnoreCase("white")) return Color.white; } } LOG.info("Unable to parse body background-color (color:" + color+"). Assuming white."); return Color.white; } }