
org.dspace.app.statistics.StatisticsLoader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dspace-api Show documentation
Show all versions of dspace-api Show documentation
DSpace core data model and service APIs.
The newest version!
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.statistics;
import java.io.File;
import java.io.FilenameFilter;
import java.time.Instant;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Helper class for loading the analysis / report files from the reports directory
*/
public class StatisticsLoader {
private static Map monthlyAnalysis = null;
private static Map monthlyReports = null;
private static StatsFile generalAnalysis = null;
private static StatsFile generalReport = null;
private static Instant 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 ThreadLocal monthlySDF;
private static ThreadLocal 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 ThreadLocal() {
@Override
protected DateTimeFormatter initialValue() {
return DateTimeFormatter.ofPattern("yyyy'-'M");
}
};
generalSDF = new ThreadLocal() {
@Override
protected DateTimeFormatter initialValue() {
return DateTimeFormatter.ofPattern("yyyy'-'M'-'dd");
}
};
}
/**
* Default constructor
*/
private StatisticsLoader() { }
/**
* Get an array of the dates of the report files.
*
* @return array of dates
*/
public static LocalDate[] getMonthlyReportDates() {
return sortDatesDescending(getDatesFromMap(monthlyReports));
}
/**
* Get an array of the dates of the analysis files.
*
* @return array of dates
*/
public static LocalDate[] getMonthlyAnalysisDates() {
return sortDatesDescending(getDatesFromMap(monthlyAnalysis));
}
/**
* Convert the formatted dates that are the keys of the map into a date array.
*
* @param monthlyMap map
* @return array of dates
*/
protected static LocalDate[] getDatesFromMap(Map monthlyMap) {
Set keys = monthlyMap.keySet();
LocalDate[] dates = new LocalDate[keys.size()];
int i = 0;
for (String date : keys) {
try {
dates[i] = YearMonth.parse(date, monthlySDF.get()).atDay(1);
} catch (DateTimeParseException pe) {
//ignore
}
i++;
}
return dates;
}
/**
* Sort the date array in descending (reverse chronological) order.
*
* @param dates array of dates
* @return sorted dates.
*/
protected static LocalDate[] sortDatesDescending(LocalDate[] dates) {
Arrays.sort(dates, new Comparator() {
@Override
public int compare(LocalDate d1, LocalDate d2) {
if (d1 == null && d2 == null) {
return 0;
} else if (d1 == null) {
return -1;
} else if (d2 == null) {
return 1;
} else if (d1.isBefore(d2)) {
return 1;
} else if (d2.isBefore(d1)) {
return -1;
}
return 0;
}
});
return dates;
}
/**
* Get the analysis file for a given date.
*
* @param date date
* @return File
*/
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 date
* @return File
*/
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 File
*/
public static File getGeneralAnalysis() {
StatisticsLoader.syncFileList();
return generalAnalysis == null ? null : generalAnalysis.file;
}
/**
* Get the current general report file.
*
* @return File
*/
public static File getGeneralReport() {
StatisticsLoader.syncFileList();
return generalReport == null ? null : generalReport.file;
}
/**
* Synchronize 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 (Instant.now().isAfter(lastLoaded.plus(1, ChronoUnit.HOURS))) {
StatisticsLoader.loadFileList(fileList);
}
}
/**
* Generate the cached file list from the array of files
*
* @param fileList array of files
*/
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 analysis / reports
Map newMonthlyAnalysis = new HashMap<>();
Map newMonthlyReports = new HashMap<>();
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.get());
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.get());
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.get());
if (statsFile != null) {
// If it is, ensure that we are pointing to the most recent file
if (newGeneralAnalysis == null || statsFile.date.isAfter(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.get());
if (statsFile != null) {
// If it is, ensure that we are pointing to the most recent file
if (newGeneralReport == null || statsFile.date.isAfter(newGeneralReport.date)) {
newGeneralReport = statsFile;
}
}
}
}
}
// Store the newly discovered values in the member cache
monthlyAnalysis = newMonthlyAnalysis;
monthlyReports = newMonthlyReports;
generalAnalysis = newGeneralAnalysis;
generalReport = newGeneralReport;
lastLoaded = Instant.now();
}
/**
* 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 file
* @param thisPattern pattern
* @param formatter date formatter
* @return StatsFile
*/
private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, DateTimeFormatter formatter) {
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 = LocalDate.parse(sf.dateStr, formatter);
} catch (DateTimeParseException e) {
// ignore
}
return sf;
}
return null;
}
/**
* Get an array of all the analysis and report files.
*
* @return array of files
*/
private static File[] getAnalysisAndReportFileList() {
ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
File reportDir = new File(configurationService.getProperty("log.report.dir"));
return reportDir.listFiles(new AnalysisAndReportFilter());
}
/**
* Simple class for holding information about an analysis/report file.
*/
private static class StatsFile {
File file;
String path;
LocalDate date;
String dateStr;
}
/**
* Filter used to restrict files in the reports directory to just
* analysis or report types.
*/
private static class AnalysisAndReportFilter implements FilenameFilter {
@Override
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;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy