/** * */ 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.TreeMap; import java.util.TreeSet; import javax.activity.InvalidActivityException; import org.gcube.accounting.analytics.Filter; import org.gcube.accounting.analytics.Info; import org.gcube.accounting.analytics.NumberedFilter; import org.gcube.accounting.analytics.TemporalConstraint; import org.gcube.accounting.analytics.UsageValue; import org.gcube.accounting.analytics.exception.DuplicatedKeyFilterException; import org.gcube.accounting.analytics.exception.KeyException; import org.gcube.accounting.analytics.exception.ValueException; import org.gcube.accounting.datamodel.aggregation.AggregatedStorageStatusRecord; import org.gcube.accounting.datamodel.aggregation.AggregatedStorageUsageRecord; import org.gcube.documentstore.records.AggregatedRecord; import org.json.JSONException; import org.json.JSONObject; /** * @author Luca Frosini (ISTI - CNR) * */ public class AccountingPersistenceQuery implements AccountingPersistenceBackendQuery { private static final AccountingPersistenceQuery accountingPersistenceQuery; public static final int DEFAULT_LIMIT_RESULT_NUMBER = 5; private AccountingPersistenceQuery() { } static { accountingPersistenceQuery = new AccountingPersistenceQuery(); } protected static synchronized AccountingPersistenceQuery getInstance() { return accountingPersistenceQuery; } public static SortedSet getQuerableKeys(Class> clz) throws Exception { AggregatedRecord instance = clz.newInstance(); // limit filter key for accounting storage status (used from portlet // accounting for tad space) if (clz.equals(AggregatedStorageStatusRecord.class)) { SortedSet storageStatus = new TreeSet<>(); storageStatus.add(AggregatedStorageStatusRecord.CONSUMER_ID); storageStatus.add(AggregatedStorageStatusRecord.DATA_SERVICEID); return storageStatus; } else { return instance.getQuerableKeys(); } } public static String getDefaultOrderingProperties(Class> clz) { if (clz.isAssignableFrom(AggregatedStorageUsageRecord.class)) { return AggregatedStorageUsageRecord.DATA_VOLUME; } return AggregatedRecord.OPERATION_COUNT; } protected static JSONObject getPaddingJSONObject(Map unpaddedResults) throws JSONException { JSONObject jsonObject = new JSONObject(); // verify data consistency if (unpaddedResults.size() != 0) { Info auxInfo = new ArrayList(unpaddedResults.values()).get(0); JSONObject auxJsonObject = auxInfo.getValue(); @SuppressWarnings("unchecked") Iterator keys = auxJsonObject.keys(); 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 */ protected static SortedMap padMap(SortedMap unpaddedData, TemporalConstraint temporalConstraint) throws Exception { JSONObject jsonObject = getPaddingJSONObject(unpaddedData); SortedSet 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; } @Override public SortedMap getTimeSeries(Class> clz, TemporalConstraint temporalConstraint, List filters) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { return this.getTimeSeries(clz, temporalConstraint, filters, false); } public SortedMap getTimeSeries(Class> clz, TemporalConstraint temporalConstraint, List filters, boolean pad) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { SortedMap ret = AccountingPersistenceBackendQueryFactory.getInstance().getTimeSeries(clz, temporalConstraint, filters); if (ret == null) { ret = new TreeMap<>(); } if (pad) { ret = padMap(ret, temporalConstraint); } return ret; } @Override public SortedMap getNoContextTimeSeries(Class> clz, TemporalConstraint temporalConstraint, List filters) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { return this.getNoContextTimeSeries(clz, temporalConstraint, filters, false); } public SortedMap getNoContextTimeSeries(Class> clz, TemporalConstraint temporalConstraint, List filters, boolean pad) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { SortedMap ret = AccountingPersistenceBackendQueryFactory.getInstance() .getNoContextTimeSeries(clz, temporalConstraint, filters); if (ret == null) { ret = new TreeMap<>(); } if (pad) { ret = padMap(ret, temporalConstraint); } return ret; } public SortedMap> getTopValues( Class> clz, TemporalConstraint temporalConstraint, List filters, String topKey, String orderingProperty, boolean pad, int limit) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { SortedMap> got; if (orderingProperty == null) { orderingProperty = getDefaultOrderingProperties(clz); } got = AccountingPersistenceBackendQueryFactory.getInstance().getTopValues(clz, temporalConstraint, filters, topKey, orderingProperty); int count = got.size() > limit ? limit : got.size(); NumberedFilter firstRemovalKey = null; for (NumberedFilter nf : got.keySet()) { if (--count >= 0 || limit <= 0) { if (pad) { padMap(got.get(nf), temporalConstraint); } } else { if (firstRemovalKey == null) { firstRemovalKey = nf; } else { break; } } } if (firstRemovalKey != null) { return got.subMap(got.firstKey(), firstRemovalKey); } return got; } public SortedMap> getTopValues( Class> clz, TemporalConstraint temporalConstraint, List filters, String topKey) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { String orderingProperty = AccountingPersistenceQuery.getDefaultOrderingProperties(clz); return this.getTopValues(clz, temporalConstraint, filters, topKey, orderingProperty, false, 0); } @Override public SortedMap> getTopValues( Class> clz, TemporalConstraint temporalConstraint, List filters, String topKey, String orderingProperty) throws DuplicatedKeyFilterException, KeyException, ValueException, Exception { return this.getTopValues(clz, temporalConstraint, filters, topKey, orderingProperty, false, 0); } @Override public void close() throws Exception { AccountingPersistenceBackendQueryFactory.getInstance().close(); } @Override public void prepareConnection(AccountingPersistenceBackendQueryConfiguration configuration) throws Exception { throw new InvalidActivityException(); } @Override public SortedSet getFilterValues(Class> clz, TemporalConstraint temporalConstraint, List filters, String key) throws Exception { return getFilterValues(clz, temporalConstraint, filters, key, null); } @Override public SortedSet getFilterValues(Class> clz, TemporalConstraint temporalConstraint, List filters, String key, Integer limit) throws Exception { return AccountingPersistenceBackendQueryFactory.getInstance().getFilterValues(clz, temporalConstraint, filters, key, limit); } @Override public List getUsageValueQuotaTotal(List listUsage) throws Exception { return AccountingPersistenceBackendQueryFactory.getInstance().getUsageValueQuotaTotal(listUsage); } @Override public SortedMap> getContextTimeSeries( Class> clz, TemporalConstraint temporalConstraint, List filters, List contexts) throws Exception { return AccountingPersistenceBackendQueryFactory.getInstance().getContextTimeSeries(clz, temporalConstraint, filters, contexts); } public SortedMap> getContextTimeSeries( Class> clz, TemporalConstraint temporalConstraint, List filters, List contexts, boolean pad) throws DuplicatedKeyFilterException, Exception { SortedMap> got; got = AccountingPersistenceBackendQueryFactory.getInstance().getContextTimeSeries(clz, temporalConstraint, filters, contexts); int count = got.size(); Filter firstRemovalKey = null; for (Filter nf : got.keySet()) { if (--count >= 0) { if (pad) { padMap(got.get(nf), temporalConstraint); } } else { if (firstRemovalKey == null) { firstRemovalKey = nf; } else { break; } } } if (firstRemovalKey != null) { return got.subMap(got.firstKey(), firstRemovalKey); } return got; } @Override public String getRecord(String recordId, String type) throws Exception { String record = AccountingPersistenceBackendQueryFactory.getInstance().getRecord(recordId, type); return record; } @Override public SortedSet getSpaceProvidersIds() throws Exception { SortedSet providersId = AccountingPersistenceBackendQueryFactory.getInstance().getSpaceProvidersIds(); return providersId; } @Override public SortedMap> getSpaceTimeSeries(Class> clz, TemporalConstraint temporalConstraint, List filters, List providersId) throws Exception { SortedMap> spaceTimeSeries = AccountingPersistenceBackendQueryFactory .getInstance().getSpaceTimeSeries(clz, temporalConstraint, filters, providersId); int count = spaceTimeSeries.size(); Filter firstRemovalKey = null; for (Filter nf : spaceTimeSeries.keySet()) { if (--count >= 0) { padMapStorage(spaceTimeSeries.get(nf), temporalConstraint); } else { if (firstRemovalKey == null) { firstRemovalKey = nf; } else { break; } } } if (firstRemovalKey != null) { return spaceTimeSeries.subMap(spaceTimeSeries.firstKey(), firstRemovalKey); } return spaceTimeSeries; } protected SortedMap padMapStorage(SortedMap unpaddedData, TemporalConstraint temporalConstraint) throws Exception { SortedSet sequence = temporalConstraint.getCalendarSequence(); Long longValuePre = null; for (Calendar progressTime : sequence) { Long longValue = unpaddedData.get(progressTime); if (longValue == null) { unpaddedData.put(progressTime, longValuePre); } else { longValuePre = longValue; } } return unpaddedData; } @Override public boolean isConnectionActive() throws Exception { return AccountingPersistenceBackendQueryFactory.getInstance().isConnectionActive(); } }