refs #2253: Accounting Manager - Top N Active Users

https://support.d4science.org/issues/2253
Reorganized Library

git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/accounting/accounting-analytics@125496 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Luca Frosini 2016-03-16 16:30:26 +00:00
parent 31e6f90591
commit 79c9373eae
5 changed files with 95 additions and 256 deletions

View File

@ -1,183 +0,0 @@
/**
*
*/
package org.gcube.accounting.analytics;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.gcube.accounting.analytics.exception.NoAvailableScopeException;
import org.gcube.accounting.analytics.exception.NoUsableAccountingPersistenceQueryFound;
import org.gcube.accounting.analytics.persistence.AccountingPersistenceBackendQuery;
import org.gcube.accounting.analytics.persistence.AccountingPersistenceBackendQueryFactory;
import org.gcube.documentstore.records.AggregatedRecord;
import org.gcube.documentstore.records.Record;
import org.gcube.documentstore.records.RecordUtility;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
*/
public class ResourceRecordQuery {
private static Logger logger = LoggerFactory
.getLogger(ResourceRecordQuery.class);
protected static Map<Class<? extends Record>, Set<String>> resourceRecords = null;
/**
* Return a Map containing a set of required fields for each Resource
* Records Types
*
* @return the Map
*/
public static synchronized Map<Class<? extends Record>, Set<String>> getResourceRecordsTypes() {
if (resourceRecords == null) {
resourceRecords = new HashMap<Class<? extends Record>, Set<String>>();
Collection<Class<? extends Record>> resourceRecordsTypes = RecordUtility
.getRecordClassesFound().values();
for (Class<? extends Record> resourceRecordsType : resourceRecordsTypes) {
try {
Record record = resourceRecordsType.newInstance();
resourceRecords.put(resourceRecordsType,
record.getRequiredFields());
} catch (InstantiationException | IllegalAccessException e) {
logger.error(String.format(
"Unable to correctly istantiate %s",
resourceRecordsType.getSimpleName()), e);
}
}
}
return resourceRecords;
}
protected AccountingPersistenceBackendQuery accountingPersistenceQuery;
/**
* Instantiate the ResourceRecord for the current scope
*
* @throws NoAvailableScopeException
* if there is not possible to query in the current scope
* @throws NoUsableAccountingPersistenceQueryFound
* if there is no available instance which can query in that
* scope
*/
public ResourceRecordQuery() throws NoAvailableScopeException,
NoUsableAccountingPersistenceQueryFound {
this.accountingPersistenceQuery = AccountingPersistenceBackendQueryFactory
.getInstance();
}
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;
}
/**
* Pad the data
*
* @param unpaddedData
* the data to be pad
* @param temporalConstraint
* temporalConstraint the temporal interval and the granularity
* of the data to pad
* @return the data padded taking in account the TemporalConstraint
* @throws Exception
* if fails
*/
public static List<Info> getPaddedResults(Map<Calendar, Info> unpaddedData,
TemporalConstraint temporalConstraint) throws Exception {
JSONObject jsonObject = getPaddingJSONObject(unpaddedData);
List<Info> paddedResults = new ArrayList<Info>();
List<Calendar> sequence = temporalConstraint.getCalendarSequence();
for (Calendar progressTime : sequence) {
if (unpaddedData.get(progressTime) != null) {
paddedResults.add(unpaddedData.get(progressTime));
} else {
Info info = new Info(progressTime, jsonObject);
paddedResults.add(info);
}
}
return paddedResults;
}
/**
* Return results with padding if pad is set to true.
*
* @param aggregatedRecordClass
* the UsageRecord type to query
* @param temporalConstraint
* the temporal interval and the granularity
* @param filters
* the list keys to filter (in AND)
* @param pad
* indicate is the results have to be padded with zeros when
* there is no data available at certain data points of sequence
* @return the requested list of Info
* @throws Exception
* if fails
*/
public List<Info> getInfo(
Class<? extends AggregatedRecord<?,?>> aggregatedRecordClass,
TemporalConstraint temporalConstraint, List<Filter> filters,
boolean pad) throws Exception {
Map<Calendar, Info> unpaddedResults = accountingPersistenceQuery
.getTimeSeries(aggregatedRecordClass, temporalConstraint,
filters);
if (!pad) {
return new ArrayList<Info>(unpaddedResults.values());
}
return getPaddedResults(unpaddedResults, temporalConstraint);
}
/**
* Return unpadded results
*
* @param aggregatedRecordClass
* the UsageRecord type to query
* @param temporalConstraint
* the temporal interval and the granularity
* @param filters
* the list keys to filter (in AND)
* @return the requested list of Info
* @throws Exception
* if fails
*/
public List<Info> getInfo(
Class<? extends AggregatedRecord<?,?>> aggregatedRecordClass,
TemporalConstraint temporalConstraint, List<Filter> filters)
throws Exception {
return getInfo(aggregatedRecordClass, temporalConstraint, filters,
false);
}
}

View File

@ -6,9 +6,12 @@ package org.gcube.accounting.analytics;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.SortedSet;
import java.util.TimeZone;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -152,8 +155,8 @@ public class TemporalConstraint {
return getAlignedCalendar(endTime, aggregationMode);
}
public List<Calendar> getCalendarSequence(){
List<Calendar> sequence = new ArrayList<Calendar>();
public SortedSet<Calendar> getCalendarSequence(){
SortedSet<Calendar> sequence = new TreeSet<>();
CalendarEnum[] calendarValues = CalendarEnum.values();
int calendarValue = calendarValues[aggregationMode.ordinal()].getCalendarValue();
@ -183,7 +186,7 @@ public class TemporalConstraint {
}
public static List<String> getSequenceAsStringList(List<Calendar> sequence){
public static List<String> getSequenceAsStringList(Collection<Calendar> sequence){
List<String> stringSequence = new ArrayList<String>();
for(Calendar calendar : sequence){
stringSequence.add(timeInMillisToString(calendar.getTimeInMillis()));

View File

@ -3,8 +3,11 @@
*/
package org.gcube.accounting.analytics.persistence;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeSet;
@ -17,6 +20,8 @@ import org.gcube.accounting.datamodel.UsageRecord;
import org.gcube.accounting.datamodel.aggregation.AggregatedStorageUsageRecord;
import org.gcube.documentstore.records.AggregatedRecord;
import org.gcube.documentstore.records.Record;
import org.json.JSONException;
import org.json.JSONObject;
/**
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
@ -26,6 +31,8 @@ public class AccountingPersistenceQuery {
private static final AccountingPersistenceQuery accountingPersistenceQuery;
public static final int DEFAULT_LIMIT_RESULT_NUMBER = 5;
private AccountingPersistenceQuery() {
}
@ -62,11 +69,18 @@ public class AccountingPersistenceQuery {
public SortedMap<Calendar, Info> getTimeSeries(
Class<? extends AggregatedRecord<?,?>> aggregatedRecordClass,
TemporalConstraint temporalConstraint, List<Filter> filters)
TemporalConstraint temporalConstraint, List<Filter> filters, boolean pad)
throws Exception {
return AccountingPersistenceBackendQueryFactory.getInstance()
SortedMap<Calendar, Info> ret =
AccountingPersistenceBackendQueryFactory.getInstance()
.getTimeSeries(aggregatedRecordClass, temporalConstraint,
filters);
if(pad){
ret = padMap(ret, temporalConstraint);
}
return ret;
}
public static String getDefaultOrderingProperties(Class<? extends AggregatedRecord<?, ?>> recordClass){
@ -76,8 +90,77 @@ public class AccountingPersistenceQuery {
return AggregatedRecord.OPERATION_COUNT;
}
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;
}
/**
* Pad the data
*
* @param unpaddedData
* the data to be pad
* @param temporalConstraint
* temporalConstraint the temporal interval and the granularity
* of the data to pad
* @return the data padded taking in account the TemporalConstraint
* @throws Exception
* if fails
*/
public static SortedMap<Calendar, Info> padMap(
SortedMap<Calendar, Info> unpaddedData,
TemporalConstraint temporalConstraint) throws Exception {
JSONObject jsonObject = getPaddingJSONObject(unpaddedData);
SortedSet<Calendar> sequence = temporalConstraint.getCalendarSequence();
for (Calendar progressTime : sequence) {
Info info = unpaddedData.get(progressTime);
if (info == null) {
info = new Info(progressTime, jsonObject);
unpaddedData.put(progressTime, info);
}
}
return unpaddedData;
}
public static SortedMap<NumberedFilter, SortedMap<Calendar, Info>> getTopValues(
Class<? extends AggregatedRecord<?,?>> aggregatedRecordClass,
TemporalConstraint temporalConstraint, List<Filter> filters,
String orderingProperty, boolean pad, int limit) throws Exception {
SortedMap<NumberedFilter, SortedMap<Calendar, Info>> ret;
if(orderingProperty==null){
orderingProperty = getDefaultOrderingProperties(aggregatedRecordClass);
}
ret = AccountingPersistenceBackendQueryFactory.getInstance()
.getTopValues(aggregatedRecordClass, temporalConstraint,
filters, orderingProperty);
if(pad){
int count = ret.size() > limit ? limit : ret.size();
while(--count >= 0){
for(NumberedFilter nf : ret.keySet()){
padMap(ret.get(nf), temporalConstraint);
}
}
}
return ret;
}
public static SortedMap<NumberedFilter, SortedMap<Calendar, Info>> getTopValues(
Class<? extends AggregatedRecord<?,?>> aggregatedRecordClass,
@ -96,7 +179,8 @@ public class AccountingPersistenceQuery {
.getNextPossibleValues(aggregatedRecordClass,
temporalConstraint, filters);
}
/**
* Close the connection to persistence
*

View File

@ -1,65 +0,0 @@
/**
*
*/
package org.gcube.accounting.analytics;
import java.util.HashSet;
import java.util.Set;
import org.gcube.accounting.datamodel.BasicUsageRecord;
import org.gcube.accounting.datamodel.usagerecords.JobUsageRecord;
import org.gcube.accounting.datamodel.usagerecords.PortletUsageRecord;
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
import org.gcube.accounting.datamodel.usagerecords.StorageUsageRecord;
import org.gcube.accounting.datamodel.usagerecords.TaskUsageRecord;
import org.gcube.documentstore.records.Record;
import org.junit.Assert;
import org.junit.Test;
/**
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
*/
public class ResourceRecordQueryTest {
public class TestUsageRecord extends BasicUsageRecord {
/**
* Generated Serial Version UID
*/
private static final long serialVersionUID = 1939161386352514727L;
@Override
protected String giveMeRecordType() {
return TestUsageRecord.class.getSimpleName();
}
}
public static Set<Class<? extends Record>> getExpectedResourceRecordsTypes(){
Set<Class<? extends Record>> expected = new HashSet<Class<? extends Record>>();
expected.add(ServiceUsageRecord.class);
expected.add(StorageUsageRecord.class);
expected.add(JobUsageRecord.class);
expected.add(TaskUsageRecord.class);
expected.add(PortletUsageRecord.class);
return expected;
}
@Test
public void testGetResourceRecordsTypes(){
Set<Class<? extends Record>> expected = getExpectedResourceRecordsTypes();
Set<Class<? extends Record>> found = ResourceRecordQuery.getResourceRecordsTypes().keySet();
Assert.assertTrue(expected.containsAll(found));
Assert.assertTrue(found.containsAll(expected));
}
@Test
public void testGetResourceRecordsTypesWithFakeClass(){
Set<Class<? extends Record>> expected = getExpectedResourceRecordsTypes();
expected.add(TestUsageRecord.class);
Set<Class<? extends Record>> found = ResourceRecordQuery.getResourceRecordsTypes().keySet();
Assert.assertTrue(expected.containsAll(found));
Assert.assertFalse(found.containsAll(expected));
}
}

View File

@ -4,7 +4,7 @@
package org.gcube.accounting.analytics;
import java.util.Calendar;
import java.util.List;
import java.util.Collection;
import org.gcube.accounting.analytics.TemporalConstraint.AggregationMode;
import org.junit.Assert;
@ -82,7 +82,7 @@ public class TemporalConstraintTest {
break;
}
List<Calendar> sequence = temporalConstraint.getCalendarSequence();
Collection<Calendar> sequence = temporalConstraint.getCalendarSequence();
if(aggregationMode.ordinal()<=AggregationMode.HOURLY.ordinal()){
logger.debug("{} generate the following sequence (size {}) {}",
temporalConstraint, sequence.size(),