mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 18:14:26 +00:00
integrated from branch 1.5
Statistics viewer for XMLUI, based on existing DStat. Note that this generates the view from the analysis files (.dat), does not require HTML report generation. git-svn-id: http://scm.dspace.org/svn/repo/trunk@3102 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -44,6 +44,7 @@ import org.dspace.app.statistics.Report;
|
|||||||
import org.dspace.app.statistics.Stat;
|
import org.dspace.app.statistics.Stat;
|
||||||
import org.dspace.app.statistics.Statistics;
|
import org.dspace.app.statistics.Statistics;
|
||||||
import org.dspace.app.statistics.ReportTools;
|
import org.dspace.app.statistics.ReportTools;
|
||||||
|
import org.dspace.core.ConfigurationManager;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
|
||||||
@@ -54,13 +55,14 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides HTML reports for the ReportGenerator class
|
* This class provides HTML reports for the ReportGenerator class
|
||||||
*
|
*
|
||||||
* @author Richard Jones
|
* @author Richard Jones
|
||||||
*/
|
*/
|
||||||
public class HTMLReport extends Report
|
public class HTMLReport implements Report
|
||||||
{
|
{
|
||||||
// FIXME: all of these methods should do some content escaping before
|
// FIXME: all of these methods should do some content escaping before
|
||||||
// outputting anything
|
// outputting anything
|
||||||
@@ -80,6 +82,10 @@ public class HTMLReport extends Report
|
|||||||
/** end date for report */
|
/** end date for report */
|
||||||
private Date end = null;
|
private Date end = null;
|
||||||
|
|
||||||
|
/** the output file to which to write aggregation data */
|
||||||
|
private static String output = ConfigurationManager.getProperty("dspace.dir") +
|
||||||
|
File.separator + "log" + File.separator + "report";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor for HTML reporting
|
* constructor for HTML reporting
|
||||||
*/
|
*/
|
||||||
@@ -88,6 +94,14 @@ public class HTMLReport extends Report
|
|||||||
// empty constructor
|
// empty constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setOutput(String newOutput)
|
||||||
|
{
|
||||||
|
if (newOutput != null)
|
||||||
|
{
|
||||||
|
output = newOutput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return a string containing the report as generated by this class
|
* return a string containing the report as generated by this class
|
||||||
*
|
*
|
||||||
@@ -120,6 +134,23 @@ public class HTMLReport extends Report
|
|||||||
// output the footer and return
|
// output the footer and return
|
||||||
frag.append(footer());
|
frag.append(footer());
|
||||||
|
|
||||||
|
// NB: HTMLReport now takes responsibility to write the output file,
|
||||||
|
// so that the Report/ReportGenerator can have more general usage
|
||||||
|
// finally write the string into the output file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileOutputStream fos = new FileOutputStream(output);
|
||||||
|
OutputStreamWriter osr = new OutputStreamWriter(fos, "UTF-8");
|
||||||
|
PrintWriter out = new PrintWriter(osr);
|
||||||
|
out.write(frag.toString());
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
System.out.println("Unable to write to output file " + output);
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
return frag.toString();
|
return frag.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -48,30 +48,18 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to define an interface to a generic report generating
|
* Sn interface to a generic report generating
|
||||||
* class, and to provide the polymorphism necessary to allow the report
|
* class, and to provide the polymorphism necessary to allow the report
|
||||||
* generator to generate any number of different formats of report
|
* generator to generate any number of different formats of report
|
||||||
*
|
*
|
||||||
|
* Note: This used to be an abstract class, but has been made an interface as there wasn't
|
||||||
|
* any logic contained within it. It's also been made public, so that you can create a Report
|
||||||
|
* type without monkeying about in the statistics package.
|
||||||
|
*
|
||||||
* @author Richard Jones
|
* @author Richard Jones
|
||||||
*/
|
*/
|
||||||
abstract class Report
|
public interface Report
|
||||||
{
|
{
|
||||||
|
|
||||||
/** a list of the statistics blocks being managed by this class */
|
|
||||||
private List blocks = new ArrayList();
|
|
||||||
|
|
||||||
/** the title for the page */
|
|
||||||
private String pageTitle = null;
|
|
||||||
|
|
||||||
/** the main title for the page */
|
|
||||||
private String mainTitle = null;
|
|
||||||
|
|
||||||
/** start date for report */
|
|
||||||
private Date start = null;
|
|
||||||
|
|
||||||
/** end date for report */
|
|
||||||
private Date end = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* output any top headers that this page needs
|
* output any top headers that this page needs
|
||||||
*
|
*
|
||||||
|
@@ -70,6 +70,7 @@ import java.util.Map;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class performs the action of coordinating a usage report being
|
* This class performs the action of coordinating a usage report being
|
||||||
@@ -172,16 +173,9 @@ public class ReportGenerator
|
|||||||
// report generator config data
|
// report generator config data
|
||||||
////////////////
|
////////////////
|
||||||
|
|
||||||
/** the format of the report to be output */
|
|
||||||
private static String format = null;
|
|
||||||
|
|
||||||
/** the input file to build the report from */
|
/** the input file to build the report from */
|
||||||
private static String input = null;
|
private static String input = null;
|
||||||
|
|
||||||
/** the output file to which to write aggregation data */
|
|
||||||
private static String output = ConfigurationManager.getProperty("dspace.dir") +
|
|
||||||
File.separator + "log" + File.separator + "report";
|
|
||||||
|
|
||||||
/** the log file action to human readable action map */
|
/** the log file action to human readable action map */
|
||||||
private static String map = ConfigurationManager.getProperty("dspace.dir") +
|
private static String map = ConfigurationManager.getProperty("dspace.dir") +
|
||||||
File.separator + "config" + File.separator + "dstat.map";
|
File.separator + "config" + File.separator + "dstat.map";
|
||||||
@@ -240,6 +234,9 @@ public class ReportGenerator
|
|||||||
* aggregation data and output a file containing the report in the
|
* aggregation data and output a file containing the report in the
|
||||||
* requested format
|
* requested format
|
||||||
*
|
*
|
||||||
|
* this method is retained for backwards compatibility, but delegates the actual
|
||||||
|
* wprk to a new method
|
||||||
|
*
|
||||||
* @param context the DSpace context in which this action is performed
|
* @param context the DSpace context in which this action is performed
|
||||||
* @param myFormat the desired output format (currently on HTML supported)
|
* @param myFormat the desired output format (currently on HTML supported)
|
||||||
* @param myInput the aggregation file to be turned into a report
|
* @param myInput the aggregation file to be turned into a report
|
||||||
@@ -249,6 +246,32 @@ public class ReportGenerator
|
|||||||
String myInput, String myOutput,
|
String myInput, String myOutput,
|
||||||
String myMap)
|
String myMap)
|
||||||
throws Exception
|
throws Exception
|
||||||
|
{
|
||||||
|
// create the relevant report type
|
||||||
|
// FIXME: at the moment we only support HTML report generation
|
||||||
|
Report report = null;
|
||||||
|
if (myFormat.equals("html"))
|
||||||
|
{
|
||||||
|
report = new HTMLReport();
|
||||||
|
((HTMLReport)report).setOutput(myOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myMap != null)
|
||||||
|
{
|
||||||
|
map = myMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportGenerator.processReport(context, report, myInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* using the pre-configuration information passed here, read in the
|
||||||
|
* aggregation data and output a file containing the report in the
|
||||||
|
* requested format
|
||||||
|
*/
|
||||||
|
public static void processReport(Context context, Report report,
|
||||||
|
String myInput)
|
||||||
|
throws Exception, SQLException
|
||||||
{
|
{
|
||||||
startTime = new GregorianCalendar();
|
startTime = new GregorianCalendar();
|
||||||
|
|
||||||
@@ -264,7 +287,7 @@ public class ReportGenerator
|
|||||||
generalSummary = new ArrayList();
|
generalSummary = new ArrayList();
|
||||||
|
|
||||||
// set the parameters for this analysis
|
// set the parameters for this analysis
|
||||||
setParameters(myFormat, myInput, myOutput, myMap);
|
setParameters(myInput);
|
||||||
|
|
||||||
// pre prepare our standard file readers and buffered readers
|
// pre prepare our standard file readers and buffered readers
|
||||||
FileReader fr = null;
|
FileReader fr = null;
|
||||||
@@ -276,14 +299,6 @@ public class ReportGenerator
|
|||||||
// load the log file action to human readable action map
|
// load the log file action to human readable action map
|
||||||
readMap(map);
|
readMap(map);
|
||||||
|
|
||||||
// create the relevant report type
|
|
||||||
// FIXME: at the moment we only support HTML report generation
|
|
||||||
Report report = null;
|
|
||||||
if (format.equals("html"))
|
|
||||||
{
|
|
||||||
report = new HTMLReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
report.setStartDate(startDate);
|
report.setStartDate(startDate);
|
||||||
report.setEndDate(endDate);
|
report.setEndDate(endDate);
|
||||||
report.setMainTitle(name, serverName);
|
report.setMainTitle(name, serverName);
|
||||||
@@ -352,7 +367,8 @@ public class ReportGenerator
|
|||||||
String info = null;
|
String info = null;
|
||||||
for (i = 0; i < items.length; i++)
|
for (i = 0; i < items.length; i++)
|
||||||
{
|
{
|
||||||
if (i < itemLookup)
|
// Allow negative value to say that all items should be looked up
|
||||||
|
if (itemLookup < 0 || i < itemLookup)
|
||||||
{
|
{
|
||||||
info = getItemInfo(context, items[i].getKey());
|
info = getItemInfo(context, items[i].getKey());
|
||||||
}
|
}
|
||||||
@@ -460,20 +476,7 @@ public class ReportGenerator
|
|||||||
|
|
||||||
report.addBlock(process);
|
report.addBlock(process);
|
||||||
|
|
||||||
// finally write the string into the output file
|
report.render();
|
||||||
try
|
|
||||||
{
|
|
||||||
FileOutputStream fos = new FileOutputStream(output);
|
|
||||||
OutputStreamWriter osr = new OutputStreamWriter(fos, "UTF-8");
|
|
||||||
PrintWriter out = new PrintWriter(osr);
|
|
||||||
out.write(report.render());
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
System.out.println("Unable to write to output file " + output);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -595,34 +598,15 @@ public class ReportGenerator
|
|||||||
* the command line with args or calling the processReport method statically
|
* the command line with args or calling the processReport method statically
|
||||||
* from elsewhere
|
* from elsewhere
|
||||||
*
|
*
|
||||||
* @param myFormat the log file directory to be analysed
|
|
||||||
* @param myInput regex for log file names
|
* @param myInput regex for log file names
|
||||||
* @param myOutput config file to use for dstat
|
|
||||||
* @param myMap the action map file to use for translations
|
|
||||||
*/
|
*/
|
||||||
public static void setParameters(String myFormat, String myInput,
|
public static void setParameters(String myInput)
|
||||||
String myOutput, String myMap)
|
|
||||||
{
|
{
|
||||||
if (myFormat != null)
|
|
||||||
{
|
|
||||||
format = myFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myInput != null)
|
if (myInput != null)
|
||||||
{
|
{
|
||||||
input = myInput;
|
input = myInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myOutput != null)
|
|
||||||
{
|
|
||||||
output = myOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myMap != null)
|
|
||||||
{
|
|
||||||
map = myMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,9 +634,13 @@ public class ReportGenerator
|
|||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
System.out.println("Failed to read input file: " + input);
|
System.out.println("Failed to read input file: " + input);
|
||||||
System.exit(0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first initialise a date format object to do our date processing
|
||||||
|
// if necessary
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy");
|
||||||
|
|
||||||
// FIXME: although this works, it is not very elegant
|
// FIXME: although this works, it is not very elegant
|
||||||
// loop through the aggregator file and read in the values
|
// loop through the aggregator file and read in the values
|
||||||
while ((record = br.readLine()) != null)
|
while ((record = br.readLine()) != null)
|
||||||
@@ -699,64 +687,48 @@ public class ReportGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if the line is real, then we carry on
|
// if the line is real, then we carry on
|
||||||
|
|
||||||
// first initialise a date format object to do our date processing
|
|
||||||
// if necessary
|
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy");
|
|
||||||
|
|
||||||
// read the analysis contents in
|
// read the analysis contents in
|
||||||
if (section.equals("archive"))
|
if (section.equals("archive"))
|
||||||
{
|
{
|
||||||
archiveStats.put(key, value);
|
archiveStats.put(key, value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("action"))
|
||||||
if (section.equals("action"))
|
|
||||||
{
|
{
|
||||||
actionAggregator.put(key, value);
|
actionAggregator.put(key, value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("user"))
|
||||||
if (section.equals("user"))
|
|
||||||
{
|
{
|
||||||
userAggregator.put(key, value);
|
userAggregator.put(key, value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("search"))
|
||||||
if (section.equals("search"))
|
|
||||||
{
|
{
|
||||||
searchAggregator.put(key, value);
|
searchAggregator.put(key, value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("item"))
|
||||||
if (section.equals("item"))
|
|
||||||
{
|
{
|
||||||
itemAggregator.put(key, value);
|
itemAggregator.put(key, value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("user_email"))
|
||||||
// read the config details used to make this report in
|
|
||||||
if (section.equals("user_email"))
|
|
||||||
{
|
{
|
||||||
userEmail = value;
|
userEmail = value;
|
||||||
}
|
}
|
||||||
|
else if (section.equals("item_floor"))
|
||||||
if (section.equals("item_floor"))
|
|
||||||
{
|
{
|
||||||
itemFloor = Integer.parseInt(value);
|
itemFloor = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("search_floor"))
|
||||||
if (section.equals("search_floor"))
|
|
||||||
{
|
{
|
||||||
searchFloor = Integer.parseInt(value);
|
searchFloor = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("host_url"))
|
||||||
if (section.equals("host_url"))
|
|
||||||
{
|
{
|
||||||
url = value;
|
url = value;
|
||||||
}
|
}
|
||||||
|
else if (section.equals("item_lookup"))
|
||||||
if (section.equals("item_lookup"))
|
|
||||||
{
|
{
|
||||||
itemLookup = Integer.parseInt(value);
|
itemLookup = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("avg_item_views"))
|
||||||
if (section.equals("avg_item_views"))
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -767,43 +739,35 @@ public class ReportGenerator
|
|||||||
avgItemViews = 0;
|
avgItemViews = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (section.equals("server_name"))
|
||||||
if (section.equals("server_name"))
|
|
||||||
{
|
{
|
||||||
serverName = value;
|
serverName = value;
|
||||||
}
|
}
|
||||||
|
else if (section.equals("service_name"))
|
||||||
if (section.equals("service_name"))
|
|
||||||
{
|
{
|
||||||
name = value;
|
name = value;
|
||||||
}
|
}
|
||||||
|
else if (section.equals("start_date"))
|
||||||
if (section.equals("start_date"))
|
|
||||||
{
|
{
|
||||||
startDate = sdf.parse(value);
|
startDate = sdf.parse(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("end_date"))
|
||||||
if (section.equals("end_date"))
|
|
||||||
{
|
{
|
||||||
endDate = sdf.parse(value);
|
endDate = sdf.parse(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("analysis_process_time"))
|
||||||
if (section.equals("analysis_process_time"))
|
|
||||||
{
|
{
|
||||||
processTime = Integer.parseInt(value);
|
processTime = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("general_summary"))
|
||||||
if (section.equals("general_summary"))
|
|
||||||
{
|
{
|
||||||
generalSummary.add(value);
|
generalSummary.add(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("log_lines"))
|
||||||
if (section.equals("log_lines"))
|
|
||||||
{
|
{
|
||||||
logLines = Integer.parseInt(value);
|
logLines = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
else if (section.equals("warnings"))
|
||||||
if (section.equals("warnings"))
|
|
||||||
{
|
{
|
||||||
warnings = Integer.parseInt(value);
|
warnings = Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,397 @@
|
|||||||
|
/*
|
||||||
|
* StatisticsLoader.java
|
||||||
|
*
|
||||||
|
* Version: $Revision: 1.0 $
|
||||||
|
*
|
||||||
|
* Date: $Date: 2007/08/28 10:00:00 $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
|
||||||
|
* Institute of Technology. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of the Hewlett-Packard Company nor the name of the
|
||||||
|
* Massachusetts Institute of Technology nor the names of their
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||||
|
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dspace.app.statistics;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.time.DateUtils;
|
||||||
|
import org.dspace.core.ConfigurationManager;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for loading the analysis / report files from the reports directory
|
||||||
|
*/
|
||||||
|
public class StatisticsLoader
|
||||||
|
{
|
||||||
|
private static Map<String, StatsFile> monthlyAnalysis = null;
|
||||||
|
private static Map<String, StatsFile> monthlyReports = null;
|
||||||
|
|
||||||
|
private static StatsFile generalAnalysis = null;
|
||||||
|
private static StatsFile generalReport = null;
|
||||||
|
|
||||||
|
private static Date lastLoaded = null;
|
||||||
|
private static int fileCount = 0;
|
||||||
|
|
||||||
|
private static Pattern analysisMonthlyPattern;
|
||||||
|
private static Pattern analysisGeneralPattern;
|
||||||
|
private static Pattern reportMonthlyPattern;
|
||||||
|
private static Pattern reportGeneralPattern;
|
||||||
|
|
||||||
|
private static SimpleDateFormat monthlySDF;
|
||||||
|
private static SimpleDateFormat generalSDF;
|
||||||
|
|
||||||
|
// one time initialisation of the regex patterns and formatters we will use
|
||||||
|
static
|
||||||
|
{
|
||||||
|
analysisMonthlyPattern = Pattern.compile("dspace-log-monthly-([0-9][0-9][0-9][0-9]-[0-9]+)\\.dat");
|
||||||
|
analysisGeneralPattern = Pattern.compile("dspace-log-general-([0-9]+-[0-9]+-[0-9]+)\\.dat");
|
||||||
|
reportMonthlyPattern = Pattern.compile("report-([0-9][0-9][0-9][0-9]-[0-9]+)\\.html");
|
||||||
|
reportGeneralPattern = Pattern.compile("report-general-([0-9]+-[0-9]+-[0-9]+)\\.html");
|
||||||
|
|
||||||
|
monthlySDF = new SimpleDateFormat("yyyy'-'M");
|
||||||
|
generalSDF = new SimpleDateFormat("yyyy'-'M'-'dd");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of the dates of the report files
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Date[] getMonthlyReportDates()
|
||||||
|
{
|
||||||
|
return sortDatesDescending(getDatesFromMap(monthlyReports));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of the dates of the analysis files
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Date[] getMonthlyAnalysisDates()
|
||||||
|
{
|
||||||
|
return sortDatesDescending(getDatesFromMap(monthlyAnalysis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the formatted dates that are the keys of the map into a date array
|
||||||
|
* @param monthlyMap
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected static Date[] getDatesFromMap(Map<String, StatsFile> monthlyMap)
|
||||||
|
{
|
||||||
|
Set<String> keys = monthlyMap.keySet();
|
||||||
|
Date[] dates = new Date[keys.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (String date : keys)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dates[i] = monthlySDF.parse(date);
|
||||||
|
}
|
||||||
|
catch (ParseException pe)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the date array in descending (reverse chronological) order
|
||||||
|
* @param dates
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected static Date[] sortDatesDescending(Date[] dates)
|
||||||
|
{
|
||||||
|
Arrays.sort(dates, new Comparator<Date>() {
|
||||||
|
SimpleDateFormat sdf = monthlySDF;
|
||||||
|
public int compare(Date d1, Date d2)
|
||||||
|
{
|
||||||
|
if (d1 == null && d2 == null)
|
||||||
|
return 0;
|
||||||
|
else if (d1 == null)
|
||||||
|
return -1;
|
||||||
|
else if (d2 == null)
|
||||||
|
return 1;
|
||||||
|
else if (d1.before(d2))
|
||||||
|
return 1;
|
||||||
|
else if (d2.before(d1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return dates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the analysis file for a given date
|
||||||
|
* @param date
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getAnalysisFor(String date)
|
||||||
|
{
|
||||||
|
StatisticsLoader.syncFileList();
|
||||||
|
StatsFile sf = (monthlyAnalysis == null ? null : monthlyAnalysis.get(date));
|
||||||
|
return sf == null ? null : sf.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the report file for a given date
|
||||||
|
* @param date
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getReportFor(String date)
|
||||||
|
{
|
||||||
|
StatisticsLoader.syncFileList();
|
||||||
|
StatsFile sf = (monthlyReports == null ? null : monthlyReports.get(date));
|
||||||
|
return sf == null ? null : sf.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current general analysis file
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getGeneralAnalysis()
|
||||||
|
{
|
||||||
|
StatisticsLoader.syncFileList();
|
||||||
|
return generalAnalysis == null ? null : generalAnalysis.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current general report file
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static File getGeneralReport()
|
||||||
|
{
|
||||||
|
StatisticsLoader.syncFileList();
|
||||||
|
return generalReport == null ? null : generalReport.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncronize the cached list of analysis / report files with the reports directory
|
||||||
|
*
|
||||||
|
* We synchronize if:
|
||||||
|
*
|
||||||
|
* 1) The number of files is different (ie. files have been added or removed)
|
||||||
|
* 2) We haven't cached anything yet
|
||||||
|
* 3) The cache was last generate over an hour ago
|
||||||
|
*/
|
||||||
|
private static void syncFileList()
|
||||||
|
{
|
||||||
|
// Get an array of all the analysis and report files present
|
||||||
|
File[] fileList = StatisticsLoader.getAnalysisAndReportFileList();
|
||||||
|
|
||||||
|
if (fileList != null && fileList.length != fileCount)
|
||||||
|
StatisticsLoader.loadFileList(fileList);
|
||||||
|
else if (lastLoaded == null)
|
||||||
|
StatisticsLoader.loadFileList(fileList);
|
||||||
|
else if (DateUtils.addHours(lastLoaded, 1).before(new Date()))
|
||||||
|
StatisticsLoader.loadFileList(fileList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the cached file list from the array of files
|
||||||
|
* @param fileList
|
||||||
|
*/
|
||||||
|
private static synchronized void loadFileList(File[] fileList)
|
||||||
|
{
|
||||||
|
// If we haven't been passed an array of files, get one now
|
||||||
|
if (fileList == null || fileList.length == 0)
|
||||||
|
{
|
||||||
|
fileList = StatisticsLoader.getAnalysisAndReportFileList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new maps for the monthly analyis / reports
|
||||||
|
Map<String, StatsFile> newMonthlyAnalysis = new HashMap<String, StatsFile>();
|
||||||
|
Map<String, StatsFile> newMonthlyReports = new HashMap<String, StatsFile>();
|
||||||
|
|
||||||
|
StatsFile newGeneralAnalysis = null;
|
||||||
|
StatsFile newGeneralReport = null;
|
||||||
|
|
||||||
|
if (fileList != null)
|
||||||
|
{
|
||||||
|
for (File thisFile : fileList)
|
||||||
|
{
|
||||||
|
StatsFile statsFile = null;
|
||||||
|
|
||||||
|
// If we haven't identified this file yet
|
||||||
|
if (statsFile == null)
|
||||||
|
{
|
||||||
|
// See if it is a monthly analysis file
|
||||||
|
statsFile = makeStatsFile(thisFile, analysisMonthlyPattern, monthlySDF);
|
||||||
|
if (statsFile != null)
|
||||||
|
{
|
||||||
|
// If it is, add it to the map
|
||||||
|
newMonthlyAnalysis.put(statsFile.dateStr, statsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't identified this file yet
|
||||||
|
if (statsFile == null)
|
||||||
|
{
|
||||||
|
// See if it is a monthly report file
|
||||||
|
statsFile = makeStatsFile(thisFile, reportMonthlyPattern, monthlySDF);
|
||||||
|
if (statsFile != null)
|
||||||
|
{
|
||||||
|
// If it is, add it to the map
|
||||||
|
newMonthlyReports.put(statsFile.dateStr, statsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't identified this file yet
|
||||||
|
if (statsFile == null)
|
||||||
|
{
|
||||||
|
// See if it is a general analysis file
|
||||||
|
statsFile = makeStatsFile(thisFile, analysisGeneralPattern, generalSDF);
|
||||||
|
if (statsFile != null)
|
||||||
|
{
|
||||||
|
// If it is, ensure that we are pointing to the most recent file
|
||||||
|
if (newGeneralAnalysis == null || statsFile.date.after(newGeneralAnalysis.date))
|
||||||
|
{
|
||||||
|
newGeneralAnalysis = statsFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we haven't identified this file yet
|
||||||
|
if (statsFile == null)
|
||||||
|
{
|
||||||
|
// See if it is a general report file
|
||||||
|
statsFile = makeStatsFile(thisFile, reportGeneralPattern, generalSDF);
|
||||||
|
if (statsFile != null)
|
||||||
|
{
|
||||||
|
// If it is, ensure that we are pointing to the most recent file
|
||||||
|
if (newGeneralReport == null || statsFile.date.after(newGeneralReport.date))
|
||||||
|
{
|
||||||
|
newGeneralReport = statsFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the newly discovered values in the member cache
|
||||||
|
monthlyAnalysis = newMonthlyAnalysis;
|
||||||
|
monthlyReports = newMonthlyReports;
|
||||||
|
generalAnalysis = newGeneralAnalysis;
|
||||||
|
generalReport = newGeneralReport;
|
||||||
|
lastLoaded = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a StatsFile entry for this file. The pattern and date formatters are used to
|
||||||
|
* identify the file as a particular type, and extract the relevant information.
|
||||||
|
* If the file is not identified by the formatter provided, then we return null
|
||||||
|
* @param thisFile
|
||||||
|
* @param thisPattern
|
||||||
|
* @param sdf
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, SimpleDateFormat sdf)
|
||||||
|
{
|
||||||
|
Matcher matcher = thisPattern.matcher(thisFile.getName());
|
||||||
|
if (matcher.matches())
|
||||||
|
{
|
||||||
|
StatsFile sf = new StatsFile();
|
||||||
|
sf.file = thisFile;
|
||||||
|
sf.path = thisFile.getPath();
|
||||||
|
sf.dateStr = matcher.group(1).trim();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sf.date = sdf.parse(sf.dateStr);
|
||||||
|
}
|
||||||
|
catch (ParseException e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of all the analysis and report files
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static File[] getAnalysisAndReportFileList()
|
||||||
|
{
|
||||||
|
File reportDir = new File(ConfigurationManager.getProperty("report.dir"));
|
||||||
|
if (reportDir != null)
|
||||||
|
{
|
||||||
|
return reportDir.listFiles(new AnalysisAndReportFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple class for holding information about an analysis/report file
|
||||||
|
*/
|
||||||
|
private static class StatsFile
|
||||||
|
{
|
||||||
|
File file;
|
||||||
|
String path;
|
||||||
|
Date date;
|
||||||
|
String dateStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter used to restrict files in the reports directory to just analysis or report types
|
||||||
|
*/
|
||||||
|
private static class AnalysisAndReportFilter implements FilenameFilter
|
||||||
|
{
|
||||||
|
public boolean accept(File dir, String name)
|
||||||
|
{
|
||||||
|
if (analysisMonthlyPattern.matcher(name).matches())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (analysisGeneralPattern.matcher(name).matches())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (reportMonthlyPattern.matcher(name).matches())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (reportGeneralPattern.matcher(name).matches())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -109,6 +109,8 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
|
|||||||
private static final Message T_context_export_community = message("xmlui.administrative.Navigation.context_export_community");
|
private static final Message T_context_export_community = message("xmlui.administrative.Navigation.context_export_community");
|
||||||
private static final Message T_account_export = message("xmlui.administrative.Navigation.account_export");
|
private static final Message T_account_export = message("xmlui.administrative.Navigation.account_export");
|
||||||
|
|
||||||
|
private static final Message T_statistics = message("xmlui.administrative.Navigation.statistics");
|
||||||
|
|
||||||
|
|
||||||
/** exports available for download */
|
/** exports available for download */
|
||||||
java.util.List<String> availableExports = null;
|
java.util.List<String> availableExports = null;
|
||||||
@@ -303,6 +305,7 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
|
|||||||
admin.addItemXref(contextPath+"/admin/item", T_administrative_items);
|
admin.addItemXref(contextPath+"/admin/item", T_administrative_items);
|
||||||
admin.addItemXref(contextPath+"/admin/withdrawn", T_administrative_withdrawn);
|
admin.addItemXref(contextPath+"/admin/withdrawn", T_administrative_withdrawn);
|
||||||
admin.addItemXref(contextPath+"/admin/panel", T_administrative_control_panel);
|
admin.addItemXref(contextPath+"/admin/panel", T_administrative_control_panel);
|
||||||
|
admin.addItemXref(contextPath+"/statistics", T_statistics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -88,18 +88,6 @@ public class Navigation extends AbstractDSpaceTransformer implements CacheablePr
|
|||||||
private static final Message T_communities_and_collections =
|
private static final Message T_communities_and_collections =
|
||||||
message("xmlui.ArtifactBrowser.Navigation.communities_and_collections");
|
message("xmlui.ArtifactBrowser.Navigation.communities_and_collections");
|
||||||
|
|
||||||
private static final Message T_browse_titles =
|
|
||||||
message("xmlui.ArtifactBrowser.Navigation.browse_titles");
|
|
||||||
|
|
||||||
private static final Message T_browse_authors =
|
|
||||||
message("xmlui.ArtifactBrowser.Navigation.browse_authors");
|
|
||||||
|
|
||||||
private static final Message T_browse_subjects =
|
|
||||||
message("xmlui.ArtifactBrowser.Navigation.browse_subjects");
|
|
||||||
|
|
||||||
private static final Message T_browse_dates =
|
|
||||||
message("xmlui.ArtifactBrowser.Navigation.browse_dates");
|
|
||||||
|
|
||||||
private static final Message T_head_this_collection =
|
private static final Message T_head_this_collection =
|
||||||
message("xmlui.ArtifactBrowser.Navigation.head_this_collection");
|
message("xmlui.ArtifactBrowser.Navigation.head_this_collection");
|
||||||
|
|
||||||
|
@@ -0,0 +1,640 @@
|
|||||||
|
/*
|
||||||
|
* Statistics.java
|
||||||
|
*
|
||||||
|
* Version: $Revision: 1.0 $
|
||||||
|
*
|
||||||
|
* Date: $Date: 2007/08/28 10:00:00 $
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
|
||||||
|
* Institute of Technology. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of the Hewlett-Packard Company nor the name of the
|
||||||
|
* Massachusetts Institute of Technology nor the names of their
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||||
|
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||||
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.dspace.app.xmlui.aspect.artifactbrowser;
|
||||||
|
|
||||||
|
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||||
|
import org.dspace.app.xmlui.wing.element.*;
|
||||||
|
import org.dspace.app.xmlui.wing.element.List;
|
||||||
|
import org.dspace.app.xmlui.wing.WingException;
|
||||||
|
import org.dspace.app.xmlui.wing.Message;
|
||||||
|
import org.dspace.app.xmlui.utils.UIException;
|
||||||
|
import org.dspace.app.xmlui.utils.DSpaceValidity;
|
||||||
|
import org.dspace.app.statistics.*;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
|
import org.dspace.authorize.AuthorizeManager;
|
||||||
|
import org.dspace.core.ConfigurationManager;
|
||||||
|
import org.apache.cocoon.caching.CacheableProcessingComponent;
|
||||||
|
import org.apache.cocoon.environment.Request;
|
||||||
|
import org.apache.cocoon.environment.ObjectModelHelper;
|
||||||
|
import org.apache.excalibur.source.SourceValidity;
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformer to display statistics data in XML UI.
|
||||||
|
*
|
||||||
|
* Unlike the JSP interface that pre-generates HTML and stores in the reports folder,
|
||||||
|
* this class transforms the raw analysis data into a Wing representation
|
||||||
|
*/
|
||||||
|
public class StatisticsViewer extends AbstractDSpaceTransformer implements CacheableProcessingComponent
|
||||||
|
{
|
||||||
|
private final static Logger log = Logger.getLogger(StatisticsViewer.class);
|
||||||
|
|
||||||
|
private final static Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||||
|
|
||||||
|
private final static Message T_choose_report = message("xmlui.ArtifactBrowser.StatisticsViewer.choose_month");
|
||||||
|
private final static Message T_page_title = message("xmlui.ArtifactBrowser.StatisticsViewer.report.title");
|
||||||
|
|
||||||
|
private final static Message T_empty_title = message("xmlui.ArtifactBrowser.StatisticsViewer.no_report.title");
|
||||||
|
private final static Message T_empty_text = message("xmlui.ArtifactBrowser.StatisticsViewer.no_report.text");
|
||||||
|
|
||||||
|
private final static SimpleDateFormat sdfDisplay = new SimpleDateFormat("MM'/'yyyy");
|
||||||
|
private final static SimpleDateFormat sdfLink = new SimpleDateFormat("yyyy'-'M");
|
||||||
|
|
||||||
|
private boolean initialised = false;
|
||||||
|
private String reportDate = null;
|
||||||
|
private SourceValidity validity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the caching key for this report
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Serializable getKey()
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
|
||||||
|
if (reportDate != null)
|
||||||
|
return reportDate;
|
||||||
|
|
||||||
|
return "general";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the validity for this cached entry
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public SourceValidity getValidity()
|
||||||
|
{
|
||||||
|
if (validity == null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
boolean showReport = ConfigurationManager.getBooleanProperty("report.public");
|
||||||
|
|
||||||
|
// If the report isn't public
|
||||||
|
if (!showReport)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Administrators can always view reports
|
||||||
|
showReport = AuthorizeManager.isAdmin(context);
|
||||||
|
}
|
||||||
|
catch (SQLException sqle)
|
||||||
|
{
|
||||||
|
log.error("Unable to check for administrator", sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only generate a validity if the report is visible
|
||||||
|
if (showReport)
|
||||||
|
{
|
||||||
|
File analysisFile = null;
|
||||||
|
|
||||||
|
// Get a file for the report data
|
||||||
|
if (reportDate != null)
|
||||||
|
analysisFile = StatisticsLoader.getAnalysisFor(reportDate);
|
||||||
|
else
|
||||||
|
analysisFile = StatisticsLoader.getGeneralAnalysis();
|
||||||
|
|
||||||
|
if (analysisFile != null)
|
||||||
|
{
|
||||||
|
// Generate the validity based on the properties of the report data file
|
||||||
|
DSpaceValidity newValidity = new DSpaceValidity();
|
||||||
|
newValidity.add(Long.toString(analysisFile.lastModified()));
|
||||||
|
newValidity.add("-");
|
||||||
|
newValidity.add(Long.toString(analysisFile.length()));
|
||||||
|
validity = newValidity.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add additional navigation options. This is to allow selection of a monthly report
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
* @throws SAXException
|
||||||
|
* @throws WingException
|
||||||
|
* @throws UIException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
*/
|
||||||
|
public void addOptions(Options options) throws SAXException, WingException,
|
||||||
|
UIException, SQLException, IOException, AuthorizeException
|
||||||
|
{
|
||||||
|
Date[] monthlyDates = StatisticsLoader.getMonthlyAnalysisDates();
|
||||||
|
|
||||||
|
if (monthlyDates != null && monthlyDates.length > 0)
|
||||||
|
{
|
||||||
|
List statList = options.addList("statsreports");
|
||||||
|
statList.setHead(T_choose_report);
|
||||||
|
|
||||||
|
HashMap<String, String> params = new HashMap<String, String>();
|
||||||
|
for (Date date : monthlyDates)
|
||||||
|
{
|
||||||
|
params.put("date", sdfLink.format(date));
|
||||||
|
statList.addItemXref(super.generateURL("statistics", params), sdfDisplay.format(date));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add title, etc. metadata
|
||||||
|
*
|
||||||
|
* @param pageMeta
|
||||||
|
* @throws SAXException
|
||||||
|
* @throws WingException
|
||||||
|
* @throws UIException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
*/
|
||||||
|
public void addPageMeta(PageMeta pageMeta) throws SAXException, WingException, UIException,
|
||||||
|
SQLException, IOException, AuthorizeException
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
|
||||||
|
pageMeta.addMetadata("title").addContent(T_page_title);
|
||||||
|
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||||
|
pageMeta.addTrail().addContent(T_page_title);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the body of the report
|
||||||
|
*
|
||||||
|
* @param body
|
||||||
|
* @throws SAXException
|
||||||
|
* @throws WingException
|
||||||
|
* @throws UIException
|
||||||
|
* @throws SQLException
|
||||||
|
* @throws IOException
|
||||||
|
* @throws AuthorizeException
|
||||||
|
*/
|
||||||
|
public void addBody(Body body) throws SAXException, WingException, UIException, SQLException,
|
||||||
|
IOException, AuthorizeException
|
||||||
|
{
|
||||||
|
initialise();
|
||||||
|
boolean publicise = ConfigurationManager.getBooleanProperty("report.public");
|
||||||
|
|
||||||
|
// Check that the reports are either public, or user is an administrator
|
||||||
|
if (!publicise && !AuthorizeManager.isAdmin(context))
|
||||||
|
throw new AuthorizeException();
|
||||||
|
|
||||||
|
// Retrieve the report data to display
|
||||||
|
File analysisFile;
|
||||||
|
if (reportDate != null)
|
||||||
|
analysisFile = StatisticsLoader.getAnalysisFor(reportDate);
|
||||||
|
else
|
||||||
|
analysisFile = StatisticsLoader.getGeneralAnalysis();
|
||||||
|
|
||||||
|
// Create the renderer for the results
|
||||||
|
Division div = body.addDivision("statistics", "primary");
|
||||||
|
|
||||||
|
if (analysisFile != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Generate the XML stream
|
||||||
|
Report myRep = new XMLUIReport(div);
|
||||||
|
ReportGenerator.processReport(context, myRep, analysisFile.getCanonicalPath());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new UIException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
div.setHead(T_empty_title);
|
||||||
|
div.addPara(T_empty_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise the member variables from the request
|
||||||
|
*/
|
||||||
|
private void initialise()
|
||||||
|
{
|
||||||
|
if (!initialised)
|
||||||
|
{
|
||||||
|
Request request = ObjectModelHelper.getRequest(objectModel);
|
||||||
|
reportDate = (String) request.getParameter("date");
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the member variables so that the instance can be reused
|
||||||
|
*/
|
||||||
|
public void recycle()
|
||||||
|
{
|
||||||
|
initialised = false;
|
||||||
|
reportDate = null;
|
||||||
|
validity = null;
|
||||||
|
super.recycle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of the Report interface, to output the statistics data for xmlui
|
||||||
|
* Note that all methods that return Strings return 'null' in this implementation, as
|
||||||
|
* all the outputting is done directly using the Wing framework.
|
||||||
|
*/
|
||||||
|
class XMLUIReport implements Report
|
||||||
|
{
|
||||||
|
private ArrayList<Statistics> blocks = new ArrayList<Statistics>();
|
||||||
|
|
||||||
|
private String mainTitle = null;
|
||||||
|
private String pageTitle = null;
|
||||||
|
|
||||||
|
/** start date for report */
|
||||||
|
private Date start = null;
|
||||||
|
|
||||||
|
/** end date for report */
|
||||||
|
private Date end = null;
|
||||||
|
|
||||||
|
private Division rootDiv;
|
||||||
|
private Division currDiv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the default constructor, so that you have to pass in a Division
|
||||||
|
*/
|
||||||
|
private XMLUIReport() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create instance, providing the Wing element that we will be adding to
|
||||||
|
*
|
||||||
|
* @param myDiv
|
||||||
|
*/
|
||||||
|
public XMLUIReport(Division myDiv)
|
||||||
|
{
|
||||||
|
rootDiv = myDiv;
|
||||||
|
currDiv = myDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the header for the report - currently not supported
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String header()
|
||||||
|
{
|
||||||
|
return header("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently not supported
|
||||||
|
public String header(String title)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the main title to the report
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String mainTitle()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rootDiv.setHead(mainTitle);
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the date range for this report
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String dateRange()
|
||||||
|
{
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
DateFormat df = DateFormat.getDateInstance();
|
||||||
|
if (start != null)
|
||||||
|
{
|
||||||
|
content.append(df.format(start));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content.append("from start of records ");
|
||||||
|
}
|
||||||
|
|
||||||
|
content.append(" to ");
|
||||||
|
|
||||||
|
if (end != null)
|
||||||
|
{
|
||||||
|
content.append(df.format(end));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
content.append(" end of records");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
rootDiv.addDivision("reportDate").addPara(content.toString());
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the section header
|
||||||
|
* @param title
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String sectionHeader(String title)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
currDiv.setHead(title);
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the current statistics block
|
||||||
|
* @param content
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String statBlock(Statistics content)
|
||||||
|
{
|
||||||
|
Stat[] stats = content.getStats();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int rows = stats.length;
|
||||||
|
if (content.getStatName() != null || content.getResultName() != null)
|
||||||
|
rows++;
|
||||||
|
|
||||||
|
Table block = currDiv.addTable("reportBlock", rows, 2);
|
||||||
|
|
||||||
|
// prepare the table headers
|
||||||
|
if (content.getStatName() != null || content.getResultName() != null)
|
||||||
|
{
|
||||||
|
Row row = block.addRow();
|
||||||
|
if (content.getStatName() != null)
|
||||||
|
{
|
||||||
|
row.addCellContent(content.getStatName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.addCellContent(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.getResultName() != null)
|
||||||
|
{
|
||||||
|
row.addCellContent(content.getResultName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.addCellContent(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// output the statistics in the table
|
||||||
|
for (int i = 0; i < stats.length; i++)
|
||||||
|
{
|
||||||
|
Row row = block.addRow();
|
||||||
|
if (stats[i].getReference() != null)
|
||||||
|
{
|
||||||
|
row.addCell().addXref(stats[i].getReference()).addContent(stats[i].getKey());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.addCell().addContent(stats[i].getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats[i].getUnits() != null)
|
||||||
|
{
|
||||||
|
row.addCell(null, null, "right").addContent(stats[i].getValue() + " " + stats[i].getUnits());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
row.addCell(null, null, "right").addContent(ReportTools.numberFormat(stats[i].getValue()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output any information about the lower boundary restriction for this section
|
||||||
|
* @param floor
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String floorInfo(int floor)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (floor > 0)
|
||||||
|
{
|
||||||
|
currDiv.addDivision("reportFloor").addPara("(more than " + ReportTools.numberFormat(floor) + " times)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output an explanation for this section
|
||||||
|
*
|
||||||
|
* @param explanation
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String blockExplanation(String explanation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (explanation != null)
|
||||||
|
{
|
||||||
|
currDiv.addDivision("reportExplanation").addPara(explanation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output the footer
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String footer()
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the main title for this report
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* @param serverName
|
||||||
|
*/
|
||||||
|
public void setMainTitle(String name, String serverName)
|
||||||
|
{
|
||||||
|
mainTitle = "Statistics for " + name;
|
||||||
|
|
||||||
|
if (ConfigurationManager.getBooleanProperty("report.show.server", true))
|
||||||
|
mainTitle += " on " + serverName;
|
||||||
|
|
||||||
|
if (pageTitle == null)
|
||||||
|
{
|
||||||
|
pageTitle = mainTitle;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a block to report on
|
||||||
|
*
|
||||||
|
* @param stat
|
||||||
|
*/
|
||||||
|
public void addBlock(Statistics stat)
|
||||||
|
{
|
||||||
|
blocks.add(stat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the statistics into an XML stream
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public String render()
|
||||||
|
{
|
||||||
|
Pattern space = Pattern.compile(" ");
|
||||||
|
|
||||||
|
// Output the heading information
|
||||||
|
header(pageTitle);
|
||||||
|
mainTitle();
|
||||||
|
dateRange();
|
||||||
|
|
||||||
|
// Loop through all the sections
|
||||||
|
for (Statistics stats : blocks)
|
||||||
|
{
|
||||||
|
// navigation();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String title = stats.getSectionHeader();
|
||||||
|
String aName = title.toLowerCase();
|
||||||
|
Matcher matchSpace = space.matcher(aName);
|
||||||
|
aName = matchSpace.replaceAll("_");
|
||||||
|
|
||||||
|
// Create a new division for each section
|
||||||
|
currDiv = rootDiv.addDivision(aName);
|
||||||
|
sectionHeader(title);
|
||||||
|
// topLink();
|
||||||
|
blockExplanation(stats.getExplanation());
|
||||||
|
floorInfo(stats.getFloor());
|
||||||
|
statBlock(stats);
|
||||||
|
currDiv = rootDiv;
|
||||||
|
}
|
||||||
|
catch (WingException we)
|
||||||
|
{
|
||||||
|
log.error("Error creating XML for report", we);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the start date for this report
|
||||||
|
* @param start
|
||||||
|
*/
|
||||||
|
public void setStartDate(Date start)
|
||||||
|
{
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the end date for this report
|
||||||
|
* @param end
|
||||||
|
*/
|
||||||
|
public void setEndDate(Date end)
|
||||||
|
{
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -64,9 +64,9 @@ and searching the repository.
|
|||||||
<map:transformer name="Contact" src="org.dspace.app.xmlui.aspect.artifactbrowser.Contact"/>
|
<map:transformer name="Contact" src="org.dspace.app.xmlui.aspect.artifactbrowser.Contact"/>
|
||||||
<map:transformer name="RestrictedItem" src="org.dspace.app.xmlui.aspect.artifactbrowser.RestrictedItem"/>
|
<map:transformer name="RestrictedItem" src="org.dspace.app.xmlui.aspect.artifactbrowser.RestrictedItem"/>
|
||||||
<map:transformer name="FrontPageSearch" src="org.dspace.app.xmlui.aspect.artifactbrowser.FrontPageSearch"/>
|
<map:transformer name="FrontPageSearch" src="org.dspace.app.xmlui.aspect.artifactbrowser.FrontPageSearch"/>
|
||||||
|
<map:transformer name="Statistics" src="org.dspace.app.xmlui.aspect.artifactbrowser.StatisticsViewer"/>
|
||||||
</map:transformers>
|
</map:transformers>
|
||||||
|
|
||||||
|
|
||||||
<map:matchers default="wildcard">
|
<map:matchers default="wildcard">
|
||||||
<map:matcher name="HandleTypeMatcher" src="org.dspace.app.xmlui.aspect.general.HandleTypeMatcher"/>
|
<map:matcher name="HandleTypeMatcher" src="org.dspace.app.xmlui.aspect.general.HandleTypeMatcher"/>
|
||||||
<map:matcher name="HandleAuthorizedMatcher" src="org.dspace.app.xmlui.aspect.general.HandleAuthorizedMatcher"/>
|
<map:matcher name="HandleAuthorizedMatcher" src="org.dspace.app.xmlui.aspect.general.HandleAuthorizedMatcher"/>
|
||||||
@@ -244,6 +244,12 @@ and searching the repository.
|
|||||||
<!-- Handle specific features (legacy) -->
|
<!-- Handle specific features (legacy) -->
|
||||||
<map:match pattern="handle/*/**">
|
<map:match pattern="handle/*/**">
|
||||||
|
|
||||||
|
<!-- Display statistics -->
|
||||||
|
<map:match pattern="statistics">
|
||||||
|
<map:transform type="Statistics"/>
|
||||||
|
<map:serialize type="xml"/>
|
||||||
|
</map:match>
|
||||||
|
|
||||||
<!-- Inform the user that the item they are viewing is a restricted resource -->
|
<!-- Inform the user that the item they are viewing is a restricted resource -->
|
||||||
<map:match pattern="handle/*/*/restricted-resource">
|
<map:match pattern="handle/*/*/restricted-resource">
|
||||||
<map:transform type="RestrictedItem"/>
|
<map:transform type="RestrictedItem"/>
|
||||||
|
@@ -490,6 +490,10 @@ td {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.ds-table-cell.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
*.first-cell {
|
*.first-cell {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
Reference in New Issue
Block a user