StatService.java
package sk.iway.iwcm.stat.rest;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.doc.GroupsTreeService;
import sk.iway.iwcm.stat.ChartType;
import sk.iway.iwcm.stat.Column;
import sk.iway.iwcm.stat.FilterHeaderDto;
import sk.iway.iwcm.stat.StatTableDB;
import sk.iway.iwcm.stat.jpa.SearchEnginesDTO;
import sk.iway.iwcm.users.UsersDB;
/**
* Main goal of this Service is help with extended filters that all Stat section pages contains and to reduce dudplicity codes.
*/
public class StatService {
private static final int MAX_ROWS = 100;
private static final int MAX_BAR_COLUMNS = 10;
private StatService() {
//it's just tools class
}
/**
* Function will set default range into dateRangeArr. Default range is 1 month.
* @param dateRangeArr - [0] dateFrom, [1] dateTo
* @param statType - type of stat, can be days, weeks, months
*/
private static void setDefaultRange(Date [] dateRangeArr, String statType) {
Calendar cal = Calendar.getInstance();
//If date to is not set, set it
if(dateRangeArr[1] == null) {
cal.setTime(new Date());
dateRangeArr[1] = cal.getTime(); //To NOW
} else {
//Use allready preapred dateTo
cal.setTime(dateRangeArr[1]);
}
if(Tools.isNotEmpty(statType) && "months".equals(statType)) {
//Stat type is set to months, set default range 6 month
cal.add(Calendar.MONTH, -6); //From 6 month's ago
} else {
//Stat type is not set OR its days/weeks, set default range 1 month
cal.add(Calendar.MONTH, -1); //From 1 month ago
}
dateRangeArr[0] = cal.getTime();
}
public static Date[] processDateRangeString(String stringRange) {
return processDateRangeString(stringRange, null);
}
/**
* Function will handle String on input and retun array of 2 Date values. This values represent date range from-to.
* In case of input that contain "daterange:" prefix (added by date picker), function can handle this prefix.
* If input is empty 1 month range is returned.
* If input contain two values in milliseconds separeted by "-", this values will be used for date range.
* If input contain only one value without "-", this value will represent dateFrom, dateTo will be computed and range
* will be 1 month.
* If input contain only one value that start with "-", this represent dateTo, dateFrom will be computed and range
* will be 1 month.
* Any other input will be clasified as invalid and default 1 month range will be returned.
* @param stringRange string of milliseconds represent date
* @return array with 2 Date values
*/
public static Date[] processDateRangeString(String stringRange, String statType) {
//Represent dateFrom, dateTo
Date [] dateRangeArr = {null, null};
//Remove prefix "daterange:" is is there
if(stringRange != null)
stringRange = stringRange.replaceFirst("^daterange:", "");
else stringRange = "";
String stringTo;
String stringFrom;
Calendar cal = Calendar.getInstance();
if(stringRange.contains("-")) {
if(stringRange.startsWith("-")) {
//We have only set dateTo
stringTo = stringRange.split("-")[1];
//First check if its valid string
if(Tools.isEmpty(stringTo)) {
//String is no valid, set default month range
setDefaultRange(dateRangeArr, statType);
} else {
//We have set only dateTo
cal.setTimeInMillis(Long.parseLong(stringTo));
dateRangeArr[1] = cal.getTime();
//dateFrom set at default range
setDefaultRange(dateRangeArr, statType);
}
} else {
//We have set both dateFrom and dateTo
stringFrom = stringRange.split("-")[0];
cal.setTimeInMillis(Long.parseLong(stringFrom));
dateRangeArr[0] = cal.getTime();
stringTo = stringRange.split("-")[1];
cal.setTimeInMillis(Long.parseLong(stringTo));
dateRangeArr[1] = cal.getTime();
}
} else {
//We have set only dateFrom
stringFrom = stringRange;
//First check if its valid string
if(Tools.isEmpty(stringFrom)) {
//String is no valid, set default range
setDefaultRange(dateRangeArr, statType);
} else {
//Range is dateFrom - now
cal.setTimeInMillis(Long.parseLong(stringFrom));
dateRangeArr[0] = cal.getTime();
dateRangeArr[1] = new Date(); //To actual date
}
}
//align dateRangeArr[0] to start of day
if(dateRangeArr[0] != null) {
cal.setTime(dateRangeArr[0]);
if (cal.get(Calendar.HOUR_OF_DAY)==0 && cal.get(Calendar.MINUTE)==0 && cal.get(Calendar.SECOND)==0) {
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
}
dateRangeArr[0] = cal.getTime();
}
//align dateRangeArr[1] to end of day
if(dateRangeArr[1] != null) {
cal.setTime(dateRangeArr[1]);
if (cal.get(Calendar.HOUR_OF_DAY)==0 && cal.get(Calendar.MINUTE)==0 && cal.get(Calendar.SECOND)==0) {
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
}
dateRangeArr[1] = cal.getTime();
}
return dateRangeArr;
}
/**
* Function is case-insensitive, and if input string value is equal to one of ChartType enum, this enum value
* will be returned. If input is null/empty/or does not match any of ChartType values, function will return
* NOT_CHART enum value as default value.
* @param chartType String value that represent one of ChartTzpe enum values
* @return ChartType enum value
*/
public static ChartType stringToChartTypeEnum(String chartType) {
if(chartType == null || chartType.equalsIgnoreCase("notChart"))
return ChartType.NOT_CHART;
else if("pie".equalsIgnoreCase(chartType))
return ChartType.PIE;
else if("line".equalsIgnoreCase(chartType))
return ChartType.LINE;
else if("bar".equalsIgnoreCase(chartType))
return ChartType.BAR;
else return ChartType.NOT_CHART;
}
/**
* Function handle Map of parameters returned by Overrided searchItem and use them for creating new
* FilterHeaderDto variable (where this handled params are set). If any param is not found in map, default value will be set.
* Default values are defined by FilterHeaderDto itself.
* Because not every class has same name for date range value (mostly refered as dayDate), there is option use input parameter
* specialDateName and set what param we want find in map, that repsent dayDate. If specialDateName isnt set, function will
* use default param name dayDate.
* @param params map of params return by overrided function searchItem
* @param specialDateName name of param that is in map and represent date range param dayDate
* @return FilterHeaderDto variable that contain handled params
*/
public static FilterHeaderDto processMapToStatFilter(Map<String, String> params, String specialDateName, Identity user) {
FilterHeaderDto filter = new FilterHeaderDto();
String stringRange = "";
//Check if we want to look for special named date variable
String searchDate = "";
if(specialDateName != null) {
if(!specialDateName.startsWith("search")) searchDate = "search" + specialDateName;
else searchDate = specialDateName;
} else {
searchDate = "searchDayDate";
}
//Get params from map
for (Map.Entry<String, String> entry : params.entrySet()) {
//In specific case, FE returned value as String "undefined"
String value = entry.getValue();
if("undefined".equals(value)) value = "";
if(entry.getKey().equalsIgnoreCase(searchDate)) {
stringRange = value;
} else if("searchRootDir".equalsIgnoreCase(entry.getKey())) {
String rootGroupIdString = value;
filter.setRootGroupId(Tools.getIntValue(rootGroupIdString, -1));
} else if("searchFilterBotsOut".equalsIgnoreCase(entry.getKey())) {
String filterBotsOutString = value;
filter.setFilterBotsOut(Boolean.parseBoolean(filterBotsOutString));
} else if("chartType".equalsIgnoreCase(entry.getKey())) {
String chartTypString = value;
filter.setChartType(stringToChartTypeEnum(chartTypString));
} else if("searchUrl".equalsIgnoreCase(entry.getKey())) {
filter.setUrl(value);
} else if("searchEngine".equalsIgnoreCase(entry.getKey())) {
filter.setSearchEngineName(value);
} else if("searchWebPage".equalsIgnoreCase(entry.getKey())) {
String webPageIdString = value;
filter.setWebPageId(Tools.getIntValue(webPageIdString, -1));
} else if("statType".equalsIgnoreCase(entry.getKey())) {
filter.setStatType( value );
}
}
//Process dateString
Date[] dateRange = processDateRangeString(stringRange, filter.getStatType());
//Set date range into filter
filter.setDateFrom(dateRange[0]);
filter.setDateTo(dateRange[1]);
// Safety FIRST
filter.setRootGroupId( GroupsTreeService.gerDefaultGroupTreeOptionForUser(filter.getRootGroupId(), user).getGroupId());
return filter;
}
/**
* Function handle parameters from request and use them for creating new FilterHeaderDto variable (where thi handled params are set).
* If any param is not found in map, default value will be set. Default values are defined by FilterHeaderDto itself.
* Because not every class has same name for date range value (mostly refered as dayDate), there is option use input parameter
* specialDateName and set what param we want find in map, that repsent dayDate. If specialDateName isnt set, function will
* use default param name dayDate.
* @param request request that contain params to handle
* @param specialDateName name of param that is in map and represent date range param dayDate
* @return FilterHeaderDto variable that contain handled params
*/
public static FilterHeaderDto processRequestToStatFilter(HttpServletRequest request, String specialDateName) {
FilterHeaderDto filter = new FilterHeaderDto();
//Check if we want to look for special named date variable
String searchDate = "";
if(specialDateName != null)
searchDate = specialDateName;
else {
if (Tools.getStringValue(request.getParameter("searchdayDate"), null) != null) searchDate = "searchdayDate";
else if (Tools.getStringValue(request.getParameter("searchDayDate"), null) != null) searchDate = "searchDayDate";
else searchDate = "dayDate";
}
//Process dateString
Date[] dateRange = processDateRangeString(request.getParameter(searchDate));
//Set date range into filter
filter.setDateFrom(dateRange[0]);
filter.setDateTo(dateRange[1]);
//Set rootGroupId with query
filter.setRootGroupId(Tools.getIntValue(request.getParameter("searchRootDir"), -1));
if(filter.getRootGroupId() == -1)
filter.setRootGroupId(Tools.getIntValue(request.getParameter("rootDir"), -1));
//Set filter bots out
filter.setFilterBotsOut(Tools.getBooleanValue(request.getParameter("searchFilterBotsOut"), false));
if(Boolean.FALSE.equals(filter.getFilterBotsOut()))
filter.setFilterBotsOut(Tools.getBooleanValue(request.getParameter("filterBotsOut"), false));
//Set chart type
String chartType = Tools.getStringValue(request.getParameter("searchChartType"), "notChart");
if("notChart".equals(chartType)) chartType = Tools.getStringValue(request.getParameter("chartType"), "notChart");
filter.setChartType(stringToChartTypeEnum(chartType));
//Set url
filter.setUrl(Tools.getStringValue(request.getParameter("searchUrl"), ""));
if("".equals( filter.getUrl() ))
filter.setUrl(Tools.getStringValue(request.getParameter("url"), ""));
if("".equals( filter.getUrl() ))
filter.setUrl(Tools.getStringValue(request.getParameter("searchurl"), ""));
//Set search engine name
filter.setSearchEngineName(Tools.getStringValue(request.getParameter("searchEngine"), ""));
if("".equals( filter.getSearchEngineName() ))
filter.setSearchEngineName(Tools.getStringValue(request.getParameter("engine"), ""));
//Set web page id
filter.setWebPageId(Tools.getIntValue(request.getParameter("searchWebPage"), -1));
if(filter.getWebPageId() == -1)
filter.setWebPageId(Tools.getIntValue(request.getParameter("webPage"), -1));
//Set stat type
filter.setStatType( Tools.getStringValue(request.getParameter("searchStatType"), "days") );
if("days".equals( filter.getStatType() ))
filter.setStatType( Tools.getStringValue(request.getParameter("statType"), "days") );
// Safety FIRST
filter.setRootGroupId( GroupsTreeService.gerDefaultGroupTreeOptionForUser(filter.getRootGroupId(), UsersDB.getCurrentUser(request)).getGroupId() );
return filter;
}
public static List<SearchEnginesDTO> getSearchEnginesTableData(FilterHeaderDto filter) {
List<Column> columns;
updateFilter(filter);
if(filter.getChartType() == ChartType.PIE)
columns = StatTableDB.getSearchEnginesCount(MAX_ROWS, filter.getDateFrom(), filter.getDateTo(), filter.getRootGroupIdQuery());
else
columns = StatTableDB.getSearchEnginesQuery(MAX_ROWS, filter.getDateFrom(), filter.getDateTo(), filter.getRootGroupIdQuery());
return columnsToItems(columns, filter.getChartType());
}
public static List<SearchEnginesDTO> getSearchEnginesPieChartData(Date from, Date to, String rootGroupIdQuery) {
List<Column> columns = StatTableDB.getSearchEnginesCount(MAX_ROWS, from, to, rootGroupIdQuery);
return columnsToItems(columns, ChartType.PIE);
}
private static FilterHeaderDto updateFilter(FilterHeaderDto filter) {
if(!filter.getSearchEngineName().isEmpty())
filter.setRootGroupIdQuery(filter.getRootGroupIdQuery() + " AND s.server='" + filter.getSearchEngineName() + "' ");
if(filter.getWebPageId() != -1)
filter.setRootGroupIdQuery(filter.getRootGroupIdQuery() + " AND s.doc_id = '" + filter.getWebPageId() + "' ");
filter.setRootGroupIdQuery(filter.getRootGroupIdQuery());
return filter;
}
private static List<SearchEnginesDTO> columnsToItems(List<Column> columns, ChartType chartType) {
List<SearchEnginesDTO> items = new ArrayList<>();
int order = 1;
if(chartType == ChartType.PIE) {
for(Column column : columns) {
SearchEnginesDTO item = new SearchEnginesDTO();
item.setOrder(order);
item.setAccesCount(column.getIntColumn2());
item.setServerName(column.getColumn1());
items.add(item);
order++;
}
} else {
//Compute sum of all visits
int sum = 0;
for(Column column : columns) {
sum += column.getIntColumn1();
}
if (sum > 0) {
for(Column column : columns) {
SearchEnginesDTO item = new SearchEnginesDTO();
item.setOrder(order);
item.setQueryCount(column.getIntColumn1());
item.setQueryName(column.getColumn2());
item.setPercentage((double) item.getQueryCount() * 100 / sum);
items.add(item);
if(chartType == ChartType.BAR && order >= MAX_BAR_COLUMNS) break;
order++;
}
}
}
return items;
}
}