Implemented the dimension values retrieval mechanism for the selection

tables
This commit is contained in:
Lennart Hensler committed 2014-09-17 11:54:55 +02:00
1 parent 9e2dde79b4
commit 3e6df27ef1
11 files changed
+247 -56

No files matched your search

@@ -1,12 +1,19 @@
package com.sap.sailing.datamining.factories;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.datamining.data.HasGPSFixContext;
import com.sap.sailing.datamining.data.HasTrackedLegContext;
import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext;
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.datamining.Query;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.factories.ProcessorFactory;
@@ -24,51 +31,97 @@ public final class DataMiningFactory {
private DataMiningFactory() {
}
public static <DataSourceType, ElementType> Query<Double> createQuery(DataSourceType dataSource, final QueryDefinition queryDefinition, final FunctionProvider functionProvider) {
return new ProcessorQuery<Double, DataSourceType>(DataMiningActivator.getExecutor(), dataSource,
public static <ElementType> Query<Double> createQuery(RacingEventService dataSource, final QueryDefinition queryDefinition, final FunctionProvider functionProvider) {
return new ProcessorQuery<Double, RacingEventService>(DataMiningActivator.getExecutor(), dataSource,
DataMiningActivator.getStringMessages(), DataMiningStringMessages.Util.getLocaleFor(queryDefinition.getLocaleInfoName())) {
@Override
protected Processor<DataSourceType> createFirstProcessor() {
protected Processor<RacingEventService> createFirstProcessor() {
Processor<GroupedDataEntry<Double>> aggregationProcessor = ProcessorFactory.createAggregationProcessor(/*query*/ this, queryDefinition.getAggregatorType());
@SuppressWarnings("unchecked") // TODO Clean, after the deprecated components have been removed
Function<Double> extractionFunction = (Function<Double>) functionProvider.getFunctionForDTO(queryDefinition.getStatisticToCalculate());
Processor<GroupedDataEntry<ElementType>> extractionProcessor = ProcessorFactory.createExtractionProcessor(aggregationProcessor, extractionFunction);
List<Function<?>> dimensionsToGroupBy = getDimensionsToGroupBy(queryDefinition, functionProvider);
List<Function<?>> dimensionsToGroupBy = convertDTOsToFunctions(queryDefinition.getDimensionsToGroupBy(), functionProvider);
Processor<ElementType> groupingProcessor = ProcessorFactory.createGroupingProcessor(extractionProcessor, dimensionsToGroupBy);
SailingDataRetrievalLevels dataRetrievalLevel = calculateDataRetrievalLevel(extractionFunction);
Processor<DataSourceType> firstRetrievalProcessor = SailingDataRetrieverFactory.createRetrievalProcessorChain(dataRetrievalLevel, groupingProcessor, queryDefinition.getFilterSelection(), functionProvider);
Processor<RacingEventService> firstRetrievalProcessor = SailingDataRetrieverFactory.createRetrievalProcessorChain(dataRetrievalLevel, groupingProcessor, queryDefinition.getFilterSelection(), functionProvider);
return firstRetrievalProcessor;
}
};
}
private static List<Function<?>> getDimensionsToGroupBy(QueryDefinition queryDefinition, FunctionProvider functionProvider) {
@SuppressWarnings("unchecked")
public static Query<Set<Object>> createDimensionValuesQuery(RacingEventService dataSource, final Collection<FunctionDTO> dimensionDTOs, final FunctionProvider functionProvider) {
return new ProcessorQuery<Set<Object>, RacingEventService>(DataMiningActivator.getExecutor(), dataSource) {
@Override
protected Processor<RacingEventService> createFirstProcessor() {
Processor<GroupedDataEntry<Object>> valueCollector = ProcessorFactory.createGroupedDataCollectingAsSetProcessor(/*query*/ this);
Collection<Function<?>> dimensions = convertDTOsToFunctions(dimensionDTOs, functionProvider);
Map<SailingDataRetrievalLevels, Collection<Function<?>>> dimensionsMappedByRetrievalLevel = mapFunctionsByRetrievalLevel(dimensions);
SailingDataRetrievalLevels deepestRetrievalLevel = getDeepestRetrievalLevel(dimensionsMappedByRetrievalLevel.keySet());
Processor<?> retrievalProcessor = null;
for (int i = deepestRetrievalLevel.ordinal(); i >= 0; i--) {
SailingDataRetrievalLevels retrievalLevel = SailingDataRetrievalLevels.values()[i];
Collection<Function<?>> dimensionsForRetrievalLevel = dimensionsMappedByRetrievalLevel.containsKey(retrievalLevel) ? dimensionsMappedByRetrievalLevel.get(retrievalLevel) : new ArrayList<Function<?>>();
Collection<Processor<?>> retrievalResultReceivers = ProcessorFactory.createGroupingExtractorsForDimensions(valueCollector, dimensionsForRetrievalLevel);
if (retrievalProcessor != null) {
retrievalResultReceivers.add(retrievalProcessor);
}
retrievalProcessor = SailingDataRetrieverFactory.createRetrievalProcessorWithoutFilter(retrievalLevel, retrievalResultReceivers);
}
// A retrieval processor created this way results always in a Processor<RacingEventService>
return (Processor<RacingEventService>) retrievalProcessor;
}
};
}
private static List<Function<?>> convertDTOsToFunctions(Collection<FunctionDTO> functionDTOs, FunctionProvider functionProvider) {
List<Function<?>> dimensionsToGroupBy = new ArrayList<>();
for (FunctionDTO functionDTO : queryDefinition.getDimensionsToGroupBy()) {
for (FunctionDTO functionDTO : functionDTOs) {
dimensionsToGroupBy.add(functionProvider.getFunctionForDTO(functionDTO));
}
return dimensionsToGroupBy;
}
private static SailingDataRetrievalLevels calculateDataRetrievalLevel(Function<Double> extractionFunction) {
if (extractionFunction.getDeclaringType().equals(HasTrackedRaceContext.class)) {
private static Map<SailingDataRetrievalLevels, Collection<Function<?>>> mapFunctionsByRetrievalLevel(Collection<Function<?>> functions) {
Map<SailingDataRetrievalLevels, Collection<Function<?>>> mappedFunctions = new HashMap<>();
for (Function<?> function : functions) {
SailingDataRetrievalLevels retrievalLevel = calculateDataRetrievalLevel(function);
if (!mappedFunctions.containsKey(retrievalLevel)) {
mappedFunctions.put(retrievalLevel, new HashSet<Function<?>>());
}
mappedFunctions.get(retrievalLevel).add(function);
}
return mappedFunctions;
}
private static SailingDataRetrievalLevels calculateDataRetrievalLevel(Function<?> function) {
if (function.getDeclaringType().equals(HasTrackedRaceContext.class)) {
return SailingDataRetrievalLevels.TrackedRace;
}
if (extractionFunction.getDeclaringType().equals(HasTrackedLegContext.class)) {
if (function.getDeclaringType().equals(HasTrackedLegContext.class)) {
return SailingDataRetrievalLevels.TrackedLeg;
}
if (extractionFunction.getDeclaringType().equals(HasTrackedLegOfCompetitorContext.class)) {
if (function.getDeclaringType().equals(HasTrackedLegOfCompetitorContext.class)) {
return SailingDataRetrievalLevels.TrackedLegOfCompetitor;
}
if (extractionFunction.getDeclaringType().equals(HasGPSFixContext.class)) {
if (function.getDeclaringType().equals(HasGPSFixContext.class)) {
return SailingDataRetrievalLevels.GPSFix;
}
return SailingDataRetrievalLevels.GPSFix;
}
private static SailingDataRetrievalLevels getDeepestRetrievalLevel(Collection<SailingDataRetrievalLevels> retrievalLevels) {
return Collections.max(retrievalLevels);
}
}
@@ -20,6 +20,7 @@ import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorFilterin
import com.sap.sailing.datamining.impl.components.TrackedRaceFilteringRetrievalProcessor;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.RegattaLeaderboard;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.datamining.components.FilterCriteria;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.functions.Function;
@@ -44,12 +45,12 @@ public final class SailingDataRetrieverFactory {
* @return The first processor of the retrieval chain.
*/
@SuppressWarnings("unchecked")
public static <DataSourceType, ElementType> Processor<DataSourceType> createRetrievalProcessorChain(SailingDataRetrievalLevels dataRetrievalLevel, Processor<ElementType> groupingProcessor, Map<FunctionDTO, Iterable<? extends Serializable>> filterSelection, FunctionProvider functionProvider) {
public static <ElementType> Processor<RacingEventService> createRetrievalProcessorChain(SailingDataRetrievalLevels dataRetrievalLevel, Processor<ElementType> groupingProcessor, Map<FunctionDTO, Iterable<? extends Serializable>> filterSelection, FunctionProvider functionProvider) {
Processor<?> resultReceiver = groupingProcessor;
for (int i = dataRetrievalLevel.ordinal(); i >= 0; i--) {
resultReceiver = createDataRetrieverFor(SailingDataRetrievalLevels.values()[i], resultReceiver, filterSelection, functionProvider);
}
return (Processor<DataSourceType>) resultReceiver;
return (Processor<RacingEventService>) resultReceiver;
}
@SuppressWarnings("unchecked")
@@ -103,4 +104,38 @@ public final class SailingDataRetrieverFactory {
return criteria != null ? criteria : new NonFilteringFilterCriteria<BaseDataType>();
}
/**
* Creates a retrieval processor without filter for the given retrieval level and result receivers.<br>
* The input type of the result receivers has to match the result type of the created retrieval processor for the given retrievel level or a {@link ClassCastException} can be thrown.
* For example, if the retrieval Level is {@link SailingDataRetrievalLevels#TrackedRace} the input must be {@link HasTrackedRaceContext}.
*/
@SuppressWarnings("unchecked")
public static Processor<?> createRetrievalProcessorWithoutFilter(SailingDataRetrievalLevels retrievalLevel,
Collection<Processor<?>> retrievalResultReceivers) throws ClassCastException {
ThreadPoolExecutor executor = DataMiningActivator.getExecutor();
switch (retrievalLevel) {
case GPSFix:
Collection<Processor<HasGPSFixContext>> gpsFixSpecificResultReceivers = (Collection<Processor<HasGPSFixContext>>)(Collection<?>) retrievalResultReceivers;
return new GPSFixRetrievalProcessor(executor, gpsFixSpecificResultReceivers);
case LeaderboardGroup:
Collection<Processor<LeaderboardGroup>> leaderboardGroupSpecificResultReceivers = (Collection<Processor<LeaderboardGroup>>)(Collection<?>) retrievalResultReceivers;
return new LeaderboardGroupRetrievalProcessor(executor, leaderboardGroupSpecificResultReceivers);
case RegattaLeaderboard:
Collection<Processor<RegattaLeaderboard>> regattaLeaderboardSpecificResultReceivers = (Collection<Processor<RegattaLeaderboard>>)(Collection<?>) retrievalResultReceivers;
return new RegattaLeaderboardFilteringRetrievalProcessor(executor, regattaLeaderboardSpecificResultReceivers, new NonFilteringFilterCriteria<RegattaLeaderboard>());
case TrackedLeg:
Collection<Processor<HasTrackedLegContext>> trackedLegSpecificResultReceivers = (Collection<Processor<HasTrackedLegContext>>)(Collection<?>) retrievalResultReceivers;
return new TrackedLegFilteringRetrievalProcessor(executor, trackedLegSpecificResultReceivers, new NonFilteringFilterCriteria<HasTrackedLegContext>());
case TrackedLegOfCompetitor:
Collection<Processor<HasTrackedLegOfCompetitorContext>> trackedLegOfCompetitorSpecificResultReceivers = (Collection<Processor<HasTrackedLegOfCompetitorContext>>)(Collection<?>) retrievalResultReceivers;
return new TrackedLegOfCompetitorFilteringRetrievalProcessor(executor, trackedLegOfCompetitorSpecificResultReceivers, new NonFilteringFilterCriteria<HasTrackedLegOfCompetitorContext>());
case TrackedRace:
Collection<Processor<HasTrackedRaceContext>> trackedRaceSpecificResultReceivers = (Collection<Processor<HasTrackedRaceContext>>)(Collection<?>) retrievalResultReceivers;
return new TrackedRaceFilteringRetrievalProcessor(executor, trackedRaceSpecificResultReceivers, new NonFilteringFilterCriteria<HasTrackedRaceContext>());
}
throw new IllegalArgumentException("No data retriever implemented for the given data retrieval level '"
+ retrievalLevel + "'");
}
}
@@ -16,7 +16,7 @@ public interface DataMiningService extends RemoteService {
Collection<FunctionDTO> getDimensionsFor(FunctionDTO statisticToCalculate, String localeInfoName);
QueryResult<Set<Object>> getDimensionValuesFor(Collection<FunctionDTO> dimensions);
QueryResult<Set<Object>> getDimensionValuesFor(Collection<FunctionDTO> dimensions) throws Exception;
<ResultType extends Number> QueryResult<ResultType> runQuery(QueryDefinition queryDefinition) throws Exception;
@@ -22,7 +22,6 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SelectionChangeEvent.Handler;
import com.sap.sailing.gwt.ui.client.ErrorReporter;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent;
@@ -38,6 +37,7 @@ import com.sap.sse.datamining.shared.QueryDefinition;
import com.sap.sse.datamining.shared.QueryResult;
import com.sap.sse.datamining.shared.components.AggregatorType;
import com.sap.sse.datamining.shared.dto.FunctionDTO;
import com.sap.sse.datamining.shared.impl.GenericGroupKey;
public class RefreshingSelectionTablesPanel implements SelectionProvider<RefreshingSelectionTablesSettings>,
StatisticChangedListener {
@@ -55,7 +55,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
private RefreshingSelectionTablesSettings settings;
private Timer timer;
private Map<FunctionDTO, SelectionTable<?>> tablesMappedByDimension;
private Map<GenericGroupKey<FunctionDTO>, SelectionTable<?>> tablesMappedByDimensionAsKeys;
private Set<SelectionChangedListener> listeners;
private FunctionDTO currentStatisticToCalculate;
@@ -69,7 +69,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
listeners = new HashSet<SelectionChangedListener>();
currentStatisticToCalculate = null;
tablesMappedByDimension = new HashMap<FunctionDTO, SelectionTable<?>>();
tablesMappedByDimensionAsKeys = new HashMap<GenericGroupKey<FunctionDTO>, SelectionTable<?>>();
tablesPanel = new HorizontalPanel();
@@ -93,7 +93,6 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
}
});
updateTables();
doLayout(Window.getClientWidth(), Window.getClientHeight());
statisticProvider.addStatisticChangedListener(this);
}
@@ -114,24 +113,41 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
}
@Override
public void onSuccess(Collection<FunctionDTO> dimensions) {
Collection<FunctionDTO> dimensionsToBeRemoved = new HashSet<>(tablesMappedByDimension.keySet());
dimensionsToBeRemoved.removeAll(dimensions);
for (FunctionDTO dimensionToBeRemoved : dimensionsToBeRemoved) {
tablesMappedByDimension.remove(dimensionToBeRemoved);
Collection<GenericGroupKey<FunctionDTO>> dimensionsAsKeys = new HashSet<>();
for (FunctionDTO dimension : dimensions) {
dimensionsAsKeys.add(new GenericGroupKey<FunctionDTO>(dimension));
}
for (FunctionDTO dimension : dimensions) {
if (!tablesMappedByDimension.containsKey(dimension)) {
SelectionTable<?> table = new SelectionTable<>(dimension);
tablesMappedByDimension.put(table.getDimension(), table);
Collection<GenericGroupKey<FunctionDTO>> dimensionTablesToBeRemoved = new HashSet<>(tablesMappedByDimensionAsKeys.keySet());
dimensionTablesToBeRemoved.removeAll(dimensionsAsKeys);
for (GenericGroupKey<FunctionDTO> dimensionToBeRemoved : dimensionTablesToBeRemoved) {
tablesMappedByDimensionAsKeys.remove(dimensionToBeRemoved);
}
for (GenericGroupKey<FunctionDTO> dimensionAsKey : dimensionsAsKeys) {
if (!tablesMappedByDimensionAsKeys.containsKey(dimensionAsKey)) {
SelectionTable<?> table = new SelectionTable<>(dimensionAsKey.getValue());
table.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
notifySelectionChanged();
}
});
tablesMappedByDimensionAsKeys.put(dimensionAsKey, table);
}
}
List<FunctionDTO> sortedDimensions = new ArrayList<>(tablesMappedByDimension.keySet());
Collections.sort(sortedDimensions);
List<GenericGroupKey<FunctionDTO>> sortedDimensions = new ArrayList<>(tablesMappedByDimensionAsKeys.keySet());
Collections.sort(sortedDimensions, new Comparator<GenericGroupKey<FunctionDTO>>() {
@Override
public int compare(GenericGroupKey<FunctionDTO> k1, GenericGroupKey<FunctionDTO> k2) {
return k1.getValue().compareTo(k2.getValue());
}
});
tablesPanel.clear();
for (FunctionDTO dimension : sortedDimensions) {
tablesPanel.add(tablesMappedByDimension.get(dimension));
for (GenericGroupKey<FunctionDTO> dimension : sortedDimensions) {
tablesPanel.add(tablesMappedByDimensionAsKeys.get(dimension));
}
updateTables();
@@ -147,7 +163,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
tablesPanel.setWidth(absoluteWidth + "px");
tablesPanel.setHeight(absoluteHeight + "px");
Collection<SelectionTable<?>> tables = tablesMappedByDimension.values();
Collection<SelectionTable<?>> tables = tablesMappedByDimensionAsKeys.values();
for (SelectionTable<?> table : tables) {
table.setWidth((absoluteWidth / tables.size()) + "px");
table.setHeight(absoluteHeight + "px");
@@ -155,8 +171,11 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
}
private void updateTables() {
//It's necessary to create a new Collection for the dimensions, since using the key set directly results in a serialization error
Collection<FunctionDTO> dimensions = new HashSet<>(tablesMappedByDimension.keySet());
Collection<FunctionDTO> dimensions = new HashSet<>();
for (GenericGroupKey<FunctionDTO> dimensionAsKey : tablesMappedByDimensionAsKeys.keySet()) {
dimensions.add(dimensionAsKey.getValue());
}
dataMiningService.getDimensionValuesFor(dimensions, new AsyncCallback<QueryResult<Set<Object>>>() {
@Override
public void onFailure(Throwable caught) {
@@ -173,7 +192,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
return o1.toString().compareTo(o2.toString());
}
});
boolean currentTableContentChanged = tablesMappedByDimension.get(resultEntry.getKey()).updateContent(sortedDimensionValues);
boolean currentTableContentChanged = tablesMappedByDimensionAsKeys.get(resultEntry.getKey()).updateContent(sortedDimensionValues);
if (!tableContentChanged) {
tableContentChanged = currentTableContentChanged;
}
@@ -194,14 +213,6 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
@Override
public void addSelectionChangedListener(SelectionChangedListener listener) {
listeners.add(listener);
for (SelectionTable<?> table : tablesMappedByDimension.values()) {
table.addSelectionChangeHandler(new Handler() {
@Override
public void onSelectionChange(SelectionChangeEvent event) {
notifySelectionChanged();
}
});
}
}
private void notifySelectionChanged() {
@@ -213,7 +224,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
@Override
public Map<FunctionDTO, Collection<? extends Serializable>> getFilterSelection() {
Map<FunctionDTO, Collection<? extends Serializable>> selection = new HashMap<>();
for (SelectionTable<?> table : tablesMappedByDimension.values()) {
for (SelectionTable<?> table : tablesMappedByDimensionAsKeys.values()) {
Collection<? extends Serializable> specificSelection = table.getSelectionAsValues();
if (!specificSelection.isEmpty()) {
selection.put(table.getDimension(), specificSelection);
@@ -225,14 +236,14 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider<Refresh
@Override
public void applySelection(QueryDefinition queryDefinition) {
for (Entry<FunctionDTO, Iterable<? extends Serializable>> selectionEntry : queryDefinition.getFilterSelection().entrySet()) {
SelectionTable<?> selectionTable = tablesMappedByDimension.get(selectionEntry.getKey());
SelectionTable<?> selectionTable = tablesMappedByDimensionAsKeys.get(selectionEntry.getKey());
selectionTable.setSelection((Iterable<?>) selectionEntry.getValue());
}
}
@Override
public void clearSelection() {
for (SelectionTable<?> table : tablesMappedByDimension.values()) {
for (SelectionTable<?> table : tablesMappedByDimensionAsKeys.values()) {
table.clearSelection();
}
}
@@ -90,9 +90,9 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM
}
@Override
public QueryResult<Set<Object>> getDimensionValuesFor(Collection<FunctionDTO> dimensions) {
// TODO Auto-generated method stub
return null;
public QueryResult<Set<Object>> getDimensionValuesFor(Collection<FunctionDTO> dimensions) throws Exception {
Query<Set<Object>> dimensionValuesQuery = DataMiningFactory.createDimensionValuesQuery(getRacingEventService(), dimensions, getDataMiningServer().getFunctionProvider());
return dimensionValuesQuery.run();
}
@Override
@@ -17,6 +17,10 @@ public class GenericGroupKey<T> extends AbstractGroupKey {
public GenericGroupKey(T value) {
this.value = value;
}
public T getValue() {
return value;
}
@Override
public boolean hasSubKey() {
@@ -0,0 +1,34 @@
package com.sap.sse.datamining.shared.impl;
import com.sap.sse.datamining.shared.AdditionalResultData;
import com.sap.sse.datamining.shared.Unit;
public class NullAdditionalResultData implements AdditionalResultData {
private static final long serialVersionUID = -8129840449690994767L;
@Override
public int getRetrievedDataAmount() {
return 0;
}
@Override
public double getCalculationTimeInSeconds() {
return 0;
}
@Override
public String getResultSignifier() {
return "";
}
@Override
public Unit getUnit() {
return Unit.None;
}
@Override
public int getValueDecimals() {
return 0;
}
}
@@ -20,6 +20,10 @@ public class QueryResultImpl<AggregatedType> implements QueryResult<AggregatedTy
@Deprecated
QueryResultImpl() { }
public QueryResultImpl(Map<GroupKey, AggregatedType> results) {
this(results, new NullAdditionalResultData());
}
public QueryResultImpl(Map<GroupKey, AggregatedType> results, AdditionalResultData additionalData) {
this.results = new HashMap<GroupKey, AggregatedType>(results);
this.additionalData = additionalData;
@@ -6,7 +6,6 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -71,7 +70,7 @@ public class TestDimensionsValuesQuery {
}
private Query<Set<Object>> createDimensionsValuesQuery() {
return new ProcessorQuery<Set<Object>, Collection<Test_Regatta>>(ConcurrencyTestsUtil.getExecutor(), dataSource, ConcurrencyTestsUtil.getTestStringMessagesWithProductiveMessages(), Locale.ENGLISH) {
return new ProcessorQuery<Set<Object>, Collection<Test_Regatta>>(ConcurrencyTestsUtil.getExecutor(), dataSource) {
@Override
protected Processor<Collection<Test_Regatta>> createFirstProcessor() {
Collection<Processor<Map<GroupKey, Set<Object>>>> collectorResultReceivers = Arrays.asList(/*query*/ this.getResultReceiver());
@@ -128,13 +127,13 @@ public class TestDimensionsValuesQuery {
@SuppressWarnings("unchecked")
private <DataType> Collection<Processor<DataType>> createGroupingExtractorsForDimensions(
Collection<Processor<GroupedDataEntry<Object>>> extractionResultReceivers, Collection<Function<?>> dimensions) {
Collection<Processor<DataType>> legGroupers = new ArrayList<>();
Collection<Processor<DataType>> groupingExtractors = new ArrayList<>();
for (Function<?> dimension : dimensions) {
Processor<GroupedDataEntry<DataType>> dimensionValueExtractor = new ParallelGroupedElementsValueExtractionProcessor<DataType, Object>(ConcurrencyTestsUtil.getExecutor(), extractionResultReceivers, (Function<Object>) dimension);
Processor<DataType> byDimensionGrouper = new ParallelByDimensionGroupingProcessor<>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(dimensionValueExtractor), dimension);
legGroupers.add(byDimensionGrouper);
groupingExtractors.add(byDimensionGrouper);
}
return legGroupers;
return groupingExtractors;
}
private Map<GroupKey, Set<Object>> buildExpectedResultData() {
@@ -1,9 +1,11 @@
package com.sap.sse.datamining.factories;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import com.sap.sse.datamining.components.Processor;
@@ -11,8 +13,10 @@ import com.sap.sse.datamining.functions.Function;
import com.sap.sse.datamining.impl.DataMiningActivator;
import com.sap.sse.datamining.impl.ProcessorQuery;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
import com.sap.sse.datamining.impl.components.ParallelByDimensionGroupingProcessor;
import com.sap.sse.datamining.impl.components.ParallelGroupedElementsValueExtractionProcessor;
import com.sap.sse.datamining.impl.components.ParallelMultiDimensionsValueNestingGroupingProcessor;
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDataCollectingAsSetProcessor;
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDoubleDataAverageAggregationProcessor;
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDoubleDataMedianAggregationProcessor;
import com.sap.sse.datamining.impl.components.aggregators.ParallelGroupedDoubleDataSumAggregationProcessor;
@@ -53,6 +57,16 @@ public class ProcessorFactory {
throw new IllegalArgumentException("No aggregation processor implemented for the aggregation type '" + aggregatorType + "'");
}
}
/**
* Creates a collecting processor with the given ProcessorQuery as result receiver, that stores all received grouped
* data in a Set.<br />
* The {@link DataMiningActivator} will be used to get the missing objects for the construction (like the executor).
*/
public static Processor<GroupedDataEntry<Object>> createGroupedDataCollectingAsSetProcessor(ProcessorQuery<Set<Object>, ?> query) {
Collection<Processor<Map<GroupKey, Set<Object>>>> resultReceivers = Arrays.asList(query.getResultReceiver());
return new ParallelGroupedDataCollectingAsSetProcessor<>(DataMiningActivator.getExecutor(), resultReceivers);
}
/**
* Creates an extraction processor with the given aggregation processor as result receiver.<br />
@@ -93,4 +107,24 @@ public class ProcessorFactory {
return new ParallelMultiDimensionsValueNestingGroupingProcessor<>(DataMiningActivator.getExecutor(), resultReceivers, dimensionsToGroupBy);
}
/**
* Creates a dimension grouping processor followed by a function value extraction processor for each given dimension.<br>
* The {@link DataMiningActivator} will be used to get the missing objects for the construction (like
* the executor).
*/
@SuppressWarnings("unchecked")
public static <DataType> Collection<Processor<?>> createGroupingExtractorsForDimensions(
Processor<GroupedDataEntry<Object>> valueCollector, Collection<Function<?>> dimensions) {
Collection<Processor<GroupedDataEntry<Object>>> extractionResultReceivers = new ArrayList<>();
extractionResultReceivers.add(valueCollector);
Collection<Processor<?>> groupingExtractors = new ArrayList<>();
for (Function<?> dimension : dimensions) {
Processor<GroupedDataEntry<DataType>> dimensionValueExtractor = new ParallelGroupedElementsValueExtractionProcessor<DataType, Object>(DataMiningActivator.getExecutor(), extractionResultReceivers, (Function<Object>) dimension);
Processor<DataType> byDimensionGrouper = new ParallelByDimensionGroupingProcessor<>(DataMiningActivator.getExecutor(), Arrays.asList(dimensionValueExtractor), dimension);
groupingExtractors.add(byDimensionGrouper);
}
return groupingExtractors;
}
}
@@ -8,6 +8,7 @@ import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReentrantLock;
@@ -39,7 +40,18 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
private final Object monitorObject = new Object();
private boolean workIsDone = false;
private boolean processorTimedOut = false;
/**
* Creates a query that returns a result without any additional data (like the calculation time or the retrieved data amount).<br>
* This is useful for non user specific queries, like retrieving the dimension values.
*/
public ProcessorQuery(ThreadPoolExecutor executor, DataSourceType dataSource) {
this(executor, dataSource, null, null);
}
/**
* Creates a query that returns a result with additional data.
*/
public ProcessorQuery(Executor executor, DataSourceType dataSource, DataMiningStringMessages stringMessages, Locale locale) {
this.executor = executor;
this.dataSource = dataSource;
@@ -49,7 +61,7 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
resultReceiver = new ProcessResultReceiver();
firstProcessor = createFirstProcessor();
}
protected abstract Processor<DataSourceType> createFirstProcessor();
@Override
@@ -102,7 +114,12 @@ public abstract class ProcessorQuery<AggregatedType, DataSourceType> implements
AdditionalResultDataBuilder additionalDataBuilder = new OverwritingResultDataBuilder();
additionalDataBuilder = firstProcessor.getAdditionalResultData(additionalDataBuilder);
Map<GroupKey, AggregatedType> results = resultReceiver.getResult();
return new QueryResultImpl<>(results, additionalDataBuilder.build(calculationTimeInNanos, stringMessages, locale));
if (stringMessages != null && locale != null) {
return new QueryResultImpl<>(results, additionalDataBuilder.build(calculationTimeInNanos, stringMessages, locale));
} else {
return new QueryResultImpl<>(results);
}
}
private void logOccuredFailures() {