Implemented padded results and related functionality
git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/accounting/accounting-analytics@117390 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
parent
500e578fb1
commit
1e78ae0fcd
6
pom.xml
6
pom.xml
|
@ -65,6 +65,12 @@
|
|||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.13</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,42 +0,0 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.gcube.accounting.analytics;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.gcube.accounting.analytics.exception.NoAvailableScopeException;
|
||||
import org.gcube.accounting.analytics.exception.NoUsableAccountingPersistenceQueryFound;
|
||||
import org.gcube.accounting.analytics.persistence.AccountingPersistenceQuery;
|
||||
import org.gcube.accounting.analytics.persistence.AccountingPersistenceQueryFactory;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
|
||||
/**
|
||||
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||
*/
|
||||
public class BasicQuery {
|
||||
|
||||
protected AccountingPersistenceQuery accountingPersistenceQuery;
|
||||
|
||||
public BasicQuery() throws NoAvailableScopeException, NoUsableAccountingPersistenceQueryFound {
|
||||
this.accountingPersistenceQuery = AccountingPersistenceQueryFactory.getInstance();
|
||||
}
|
||||
|
||||
public BasicQuery(String scope) throws NoAvailableScopeException, NoUsableAccountingPersistenceQueryFound {
|
||||
ScopeProvider.instance.set(scope);
|
||||
this.accountingPersistenceQuery = AccountingPersistenceQueryFactory.getInstance();
|
||||
}
|
||||
|
||||
public List<Info> getServiceInfo(TemporalConstraint temporalConstraint) {
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Info> getStorageInfo(TemporalConstraint temporalConstraint) {
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -60,7 +60,7 @@ public class Info {
|
|||
@Override
|
||||
public String toString(){
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS z");
|
||||
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
simpleDateFormat.setTimeZone(TemporalConstraint.DEFAULT_TIME_ZONE);
|
||||
return String.format("Date : %s, Value : %s", simpleDateFormat.format(date), value.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
*/
|
||||
package org.gcube.accounting.analytics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -15,6 +19,8 @@ import org.gcube.accounting.analytics.persistence.AccountingPersistenceQueryFact
|
|||
import org.gcube.accounting.datamodel.SingleUsageRecord;
|
||||
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -59,14 +65,72 @@ public class ResourceRecordQuery {
|
|||
this.accountingPersistenceQuery = AccountingPersistenceQueryFactory.getInstance();
|
||||
}
|
||||
|
||||
public List<Info> getInfo(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
TemporalConstraint temporalConstraint, List<Filter> filters) throws Exception{
|
||||
return accountingPersistenceQuery.query(usageRecordType, temporalConstraint, filters);
|
||||
protected static JSONObject getPaddingJSONObject(Map<Calendar, Info> unpaddedResults) throws JSONException{
|
||||
Info auxInfo = new ArrayList<Info>(unpaddedResults.values()).get(0);
|
||||
JSONObject auxJsonObject = auxInfo.getValue();
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<String> keys = auxJsonObject.keys();
|
||||
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
while(keys.hasNext()){
|
||||
String key = keys.next();
|
||||
jsonObject.put(key, 0);
|
||||
}
|
||||
|
||||
return jsonObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<Info> getPaddedResults(Map<Calendar, Info> unpaddedResults, TemporalConstraint temporalConstraint) throws JSONException{
|
||||
JSONObject jsonObject = getPaddingJSONObject(unpaddedResults);
|
||||
|
||||
List<Info> paddedResults = new ArrayList<Info>();
|
||||
List<Calendar> sequence = temporalConstraint.getCalendarSequence();
|
||||
|
||||
for(Calendar progressTime : sequence){
|
||||
if(unpaddedResults.get(progressTime)!=null){
|
||||
paddedResults.add(unpaddedResults.get(progressTime));
|
||||
}else{
|
||||
Date date = new Date(progressTime.getTimeInMillis());
|
||||
Info info = new Info(date, jsonObject);
|
||||
paddedResults.add(info);
|
||||
}
|
||||
}
|
||||
|
||||
return paddedResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return results with padding if pad is set to true.
|
||||
* @param usageRecordType
|
||||
* @param temporalConstraint
|
||||
* @param filters
|
||||
* @param pad
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<Info> getInfo(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
TemporalConstraint temporalConstraint, List<Filter> filters, boolean pad) throws Exception {
|
||||
Map<Calendar, Info> unpaddedResults = accountingPersistenceQuery.query(usageRecordType, temporalConstraint, filters);
|
||||
if(!pad){
|
||||
return new ArrayList<Info>(unpaddedResults.values());
|
||||
}
|
||||
|
||||
return getPaddedResults(unpaddedResults, temporalConstraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return unpadded result
|
||||
* @param usageRecordType
|
||||
* @param temporalConstraint
|
||||
* @param filters
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<Info> getInfo(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
TemporalConstraint temporalConstraint, List<Filter> filters) throws Exception{
|
||||
return getInfo(usageRecordType, temporalConstraint, filters, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,16 +3,52 @@
|
|||
*/
|
||||
package org.gcube.accounting.analytics;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||
*
|
||||
*/
|
||||
public class TemporalConstraint {
|
||||
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TemporalConstraint.class);
|
||||
|
||||
private static final String UTC_TIME_ZONE = "UTC";
|
||||
public static final TimeZone DEFAULT_TIME_ZONE = TimeZone.getTimeZone(UTC_TIME_ZONE);
|
||||
|
||||
public enum AggregationMode {
|
||||
YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY, SECONDLY, MILLISECONDLY
|
||||
}
|
||||
|
||||
public enum CalendarEnum {
|
||||
YEAR(Calendar.YEAR),
|
||||
MONTH(Calendar.MONTH),
|
||||
DAY(Calendar.DAY_OF_MONTH),
|
||||
HOUR(Calendar.HOUR_OF_DAY),
|
||||
MINUTE(Calendar.MINUTE),
|
||||
SECOND(Calendar.SECOND),
|
||||
MILLISECOND(Calendar.MILLISECOND);
|
||||
|
||||
private final int calendarValue;
|
||||
|
||||
CalendarEnum(int calendarValue){
|
||||
this.calendarValue = calendarValue;
|
||||
}
|
||||
|
||||
public int getCalendarValue(){
|
||||
return calendarValue;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
protected long startTime;
|
||||
protected long endTime;
|
||||
protected AggregationMode aggregationMode;
|
||||
|
@ -64,6 +100,88 @@ public class TemporalConstraint {
|
|||
public void setAggregationMode(AggregationMode aggregationMode) {
|
||||
this.aggregationMode = aggregationMode;
|
||||
}
|
||||
|
||||
public static String timeInMillisToString(long timeInMillis){
|
||||
Date date = new Date(timeInMillis);
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SS z");
|
||||
simpleDateFormat.setTimeZone(DEFAULT_TIME_ZONE);
|
||||
return String.format("%s (%d millis)", simpleDateFormat.format(date), timeInMillis);
|
||||
}
|
||||
|
||||
public static Calendar getAlignedCalendar(long millis, AggregationMode aggregationMode){
|
||||
Calendar alignedCalendar = Calendar.getInstance();
|
||||
alignedCalendar.setTimeZone(DEFAULT_TIME_ZONE);
|
||||
alignedCalendar.setTimeInMillis(millis);
|
||||
|
||||
CalendarEnum[] calendarValues = CalendarEnum.values();
|
||||
|
||||
for(int i=aggregationMode.ordinal()+1; i<calendarValues.length; i++){
|
||||
int calendarValue = calendarValues[i].getCalendarValue();
|
||||
|
||||
if(calendarValue == Calendar.DAY_OF_MONTH){
|
||||
alignedCalendar.set(calendarValue, 1);
|
||||
} else{
|
||||
alignedCalendar.set(calendarValue, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return alignedCalendar;
|
||||
}
|
||||
|
||||
public Calendar getAlignedStartTime(){
|
||||
return getAlignedCalendar(startTime, aggregationMode);
|
||||
}
|
||||
|
||||
public Calendar getAlignedEndTime(){
|
||||
return getAlignedCalendar(endTime, aggregationMode);
|
||||
}
|
||||
|
||||
public List<Calendar> getCalendarSequence(){
|
||||
List<Calendar> sequence = new ArrayList<Calendar>();
|
||||
|
||||
CalendarEnum[] calendarValues = CalendarEnum.values();
|
||||
int calendarValue = calendarValues[aggregationMode.ordinal()].getCalendarValue();
|
||||
|
||||
Calendar alignedStartTime = getAlignedStartTime();
|
||||
logger.trace("Aligned StartTime : {}", timeInMillisToString(alignedStartTime.getTimeInMillis()));
|
||||
|
||||
Calendar alignedEndTime = getAlignedEndTime();
|
||||
long alignedEndTimeInMillis = alignedEndTime.getTimeInMillis();
|
||||
logger.trace("Aligned EndTime : {}", timeInMillisToString(alignedEndTime.getTimeInMillis()));
|
||||
|
||||
Calendar progressTime = Calendar.getInstance();
|
||||
progressTime.setTimeZone(DEFAULT_TIME_ZONE);
|
||||
progressTime.setTimeInMillis(alignedStartTime.getTimeInMillis());
|
||||
|
||||
while(progressTime.getTimeInMillis() <= alignedEndTimeInMillis){
|
||||
logger.trace("Progress Time : {}", timeInMillisToString(progressTime.getTimeInMillis()));
|
||||
Calendar item = Calendar.getInstance();
|
||||
item.setTimeZone(DEFAULT_TIME_ZONE);
|
||||
item.setTimeInMillis(progressTime.getTimeInMillis());
|
||||
|
||||
sequence.add(item);
|
||||
progressTime.add(calendarValue, 1);
|
||||
}
|
||||
|
||||
return sequence;
|
||||
}
|
||||
|
||||
|
||||
public static List<String> getSequenceAsStringList(List<Calendar> sequence){
|
||||
List<String> stringSequence = new ArrayList<String>();
|
||||
for(Calendar calendar : sequence){
|
||||
stringSequence.add(timeInMillisToString(calendar.getTimeInMillis()));
|
||||
}
|
||||
return stringSequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("StartTime : %s, EndTime : %s, Aggregated %s",
|
||||
timeInMillisToString(startTime),
|
||||
timeInMillisToString(endTime),
|
||||
aggregationMode.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
*/
|
||||
package org.gcube.accounting.analytics.persistence;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gcube.accounting.analytics.Filter;
|
||||
import org.gcube.accounting.analytics.Info;
|
||||
|
@ -18,10 +20,10 @@ public abstract class AccountingPersistenceQuery {
|
|||
|
||||
protected abstract void prepareConnection(AccountingPersistenceQueryConfiguration configuration) throws Exception;
|
||||
|
||||
protected abstract List<Info> reallyQuery(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
protected abstract Map<Calendar, Info> reallyQuery(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
TemporalConstraint temporalConstraint, List<Filter> filters) throws Exception;
|
||||
|
||||
public List<Info> query(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
public Map<Calendar, Info> query(Class<? extends SingleUsageRecord> usageRecordType,
|
||||
TemporalConstraint temporalConstraint, List<Filter> filters) throws Exception{
|
||||
return reallyQuery(usageRecordType, temporalConstraint, filters);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/**
|
||||
*
|
||||
*/
|
||||
package org.gcube.accounting.analytics;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.gcube.accounting.analytics.TemporalConstraint.AggregationMode;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||
*
|
||||
*/
|
||||
public class TemporalConstraintTest {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(TemporalConstraintTest.class);
|
||||
|
||||
|
||||
long testTime = new Long("1437481211396"); // 2015-07-21 12:20:11:396 UTC
|
||||
long[] results = new long[]{
|
||||
new Long("1420070400000"), // 2015-01-01 00:00:00:00 UTC
|
||||
new Long("1435708800000"), // 2015-07-01 00:00:00:00 UTC
|
||||
new Long("1437436800000"), // 2015-07-21 00:00:00:00 UTC
|
||||
new Long("1437480000000"), // 2015-07-21 12:00:00:00 UTC
|
||||
new Long("1437481200000"), // 2015-07-21 12:20:00:00 UTC
|
||||
new Long("1437481211000"), // 2015-07-21 12:20:11:00 UTC
|
||||
testTime // 2015-07-21 12:20:11:396 UTC
|
||||
};
|
||||
|
||||
@Test
|
||||
public void getAlignedCalendarTest(){
|
||||
logger.debug(TemporalConstraint.timeInMillisToString(testTime));
|
||||
for(AggregationMode aggregationMode : AggregationMode.values()){
|
||||
Calendar alignedCalendar = TemporalConstraint.getAlignedCalendar(testTime, aggregationMode);
|
||||
long alignedInMillis = alignedCalendar.getTimeInMillis();
|
||||
logger.debug("With AggregationMode {} The aligned value of {} is {}",
|
||||
aggregationMode,
|
||||
TemporalConstraint.timeInMillisToString(testTime),
|
||||
TemporalConstraint.timeInMillisToString(alignedInMillis));
|
||||
Assert.assertEquals(results[aggregationMode.ordinal()], alignedInMillis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalendarSequenceTest(){
|
||||
Calendar endTime = Calendar.getInstance();
|
||||
|
||||
Calendar startTime = Calendar.getInstance();
|
||||
// 3 days
|
||||
int[] timeShift = new int[]{
|
||||
3, // days
|
||||
24, // hour in a day
|
||||
60, // min per hour
|
||||
60, // sec per min
|
||||
1000 // millisec per sec
|
||||
};
|
||||
|
||||
long shift = 1;
|
||||
for(int i=0; i<timeShift.length; i++){
|
||||
shift = shift * timeShift[i];
|
||||
}
|
||||
startTime.setTimeInMillis(endTime.getTimeInMillis()-(shift));
|
||||
|
||||
int[] expectedSequenceSize = new int[AggregationMode.values().length];
|
||||
expectedSequenceSize[0] = 1; // AggregationMode.YEARLY
|
||||
expectedSequenceSize[1] = 1; // AggregationMode.MONTHLY
|
||||
|
||||
for(int j=0; j<timeShift.length; j++){
|
||||
expectedSequenceSize[j+2] = expectedSequenceSize[j+1] * timeShift[j];
|
||||
};
|
||||
|
||||
for(AggregationMode aggregationMode : AggregationMode.values()){
|
||||
TemporalConstraint temporalConstraint = new TemporalConstraint(startTime.getTimeInMillis(), endTime.getTimeInMillis(), aggregationMode);
|
||||
if(aggregationMode==AggregationMode.MILLISECONDLY ||
|
||||
aggregationMode==AggregationMode.SECONDLY ||
|
||||
aggregationMode==AggregationMode.MINUTELY){
|
||||
break;
|
||||
}
|
||||
|
||||
List<Calendar> sequence = temporalConstraint.getCalendarSequence();
|
||||
if(aggregationMode.ordinal()<=AggregationMode.HOURLY.ordinal()){
|
||||
logger.debug("{} generate the following sequence (size {}) {}",
|
||||
temporalConstraint, sequence.size(),
|
||||
TemporalConstraint.getSequenceAsStringList(sequence));
|
||||
}else{
|
||||
logger.debug("{} generate asequence with size {}",
|
||||
temporalConstraint, sequence.size());
|
||||
}
|
||||
int expected = expectedSequenceSize[aggregationMode.ordinal()];
|
||||
|
||||
// Expected has 1 more value because the extremes are contained.
|
||||
// DAILY because the difference is 3 DAYS
|
||||
if(aggregationMode.ordinal()>=AggregationMode.DAILY.ordinal()){
|
||||
expected++;
|
||||
}
|
||||
|
||||
Assert.assertEquals(expected, sequence.size());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue