From dd4fa0c310673f07b2009fbca0b85d3235d9b074 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Wed, 26 Mar 2014 17:04:06 +0100 Subject: [PATCH 001/114] Implemented a CompoundFunction This can be used for the user specific functions and to implement the transitive dimensions. --- ...boardGroupFilteringRetrievalProcessor.java | 40 +++-- .../data/LeaderboardGroupWithContext.java | 10 ++ ...boardGroupFilteringRetrievalProcessor.java | 14 +- .../data/LeaderboardGroupWithContextImpl.java | 19 ++ .../gwt/ui/server/DataMiningServiceImpl.java | 3 +- .../datamining/impl/TestProcessorQuery.java | 6 +- ...stAbstractFilteringRetrievalProcessor.java | 6 +- .../impl/function/TestCompoundFunction.java | 70 ++++++++ .../function/TestFunctionDTOConstruction.java | 19 +- .../impl/function/TestFunctionProvider.java | 5 +- .../test_classes/ContainerElement.java | 10 ++ .../test_classes/ContainerElementImpl.java | 16 ++ .../test_classes/MarkedContainer.java | 10 ++ .../test_classes/MarkedContainerImpl.java | 16 ++ .../factories/FunctionDTOFactory.java | 52 ++++++ .../datamining/factories/FunctionFactory.java | 14 ++ .../sse/datamining/functions/Function.java | 19 +- .../AbstractFilteringRetrievalProcessor.java | 21 ++- .../impl/functions/CompoundFunction.java | 162 ++++++++++++++++++ .../functions/FunctionDTOFilterCriteria.java | 3 +- .../functions/MethodWrappingFunction.java | 69 +++----- 21 files changed, 481 insertions(+), 103 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java create mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java create mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java create mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java create mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java create mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java index b39b8004344..168a93419ab 100644 --- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java @@ -16,6 +16,10 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; +import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; +import com.sap.sailing.datamining.impl.data.HasLeaderboardGroupContextImpl; +import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContextImpl; import com.sap.sailing.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; @@ -30,16 +34,17 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { private RacingEventService service; private Processor retriever; - private Collection retrievedGroups; + private Collection retrievedGroups; @Before public void initializeComponents() { service = mock(RacingEventService.class); stub(service.getLeaderboardGroups()).toReturn(getGroupsInService()); - - Processor receiver = new Processor() { + + retrievedGroups = new HashSet<>(); + Processor receiver = new Processor() { @Override - public void onElement(LeaderboardGroup element) { + public void onElement(LeaderboardGroupWithContext element) { retrievedGroups.add(element); } @Override @@ -54,10 +59,10 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { } }; - FilterCriteria criteria = new FilterCriteria() { + FilterCriteria criteria = new FilterCriteria() { @Override - public boolean matches(LeaderboardGroup element) { - String name = element.getName(); + public boolean matches(LeaderboardGroupWithContext element) { + String name = element.getLeaderboardGroupName(); return name == "LG1" || name == "LG2" || name == "LG3"; } }; @@ -80,18 +85,23 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { retriever.onElement(service); retriever.finish(); - Collection expectedGroups = getExpectedRetrievedGroups(); + Collection expectedGroups = getExpectedRetrievedGroups(); assertThat(retrievedGroups, is(expectedGroups)); } - private Collection getExpectedRetrievedGroups() { - Collection groups = new HashSet<>(); - groups.add(new LeaderboardGroupImpl("LG1", "", false, new ArrayList())); - groups.add(new LeaderboardGroupImpl("LG2", "", false, new ArrayList())); - groups.add(new LeaderboardGroupImpl("LG3", "", false, new ArrayList())); - groups.add(new LeaderboardGroupImpl("LG4", "", false, new ArrayList())); - groups.add(new LeaderboardGroupImpl("LG5", "", false, new ArrayList())); + private Collection getExpectedRetrievedGroups() { + Collection groups = new HashSet<>(); + groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG1", "", false, new ArrayList()))); + groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG2", "", false, new ArrayList()))); + groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG3", "", false, new ArrayList()))); + groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG4", "", false, new ArrayList()))); + groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG5", "", false, new ArrayList()))); return groups; } + private LeaderboardGroupWithContext groupToGroupWithContext(LeaderboardGroupImpl leaderboardGroup) { + HasLeaderboardGroupContext context = new HasLeaderboardGroupContextImpl(leaderboardGroup); + return new LeaderboardGroupWithContextImpl(context); + } + } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java new file mode 100644 index 00000000000..9ff5a9abeed --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java @@ -0,0 +1,10 @@ +package com.sap.sailing.datamining.data; + +import com.sap.sse.datamining.shared.annotations.Dimension; + +public interface LeaderboardGroupWithContext { + + @Dimension(messageKey="leaderboardGroup") + public String getLeaderboardGroupName(); + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java index 1e8ac564adf..0e804362392 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java @@ -3,6 +3,10 @@ package com.sap.sailing.datamining.impl.components; import java.util.Collection; import java.util.concurrent.ExecutorService; +import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; +import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; +import com.sap.sailing.datamining.impl.data.HasLeaderboardGroupContextImpl; +import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContextImpl; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.components.FilterCriteria; @@ -10,10 +14,10 @@ import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.AbstractFilteringRetrievalProcessor; public class LeaderboardGroupFilteringRetrievalProcessor extends - AbstractFilteringRetrievalProcessor { + AbstractFilteringRetrievalProcessor { public LeaderboardGroupFilteringRetrievalProcessor(ExecutorService executor, - Collection> resultReceivers, FilterCriteria criteria) { + Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers, criteria); } @@ -22,4 +26,10 @@ public class LeaderboardGroupFilteringRetrievalProcessor extends return element.getLeaderboardGroups().values(); } + @Override + protected LeaderboardGroupWithContext contextifyElement(LeaderboardGroup partialElement) { + HasLeaderboardGroupContext context = new HasLeaderboardGroupContextImpl(partialElement); + return new LeaderboardGroupWithContextImpl(context); + } + } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java new file mode 100644 index 00000000000..4ec855711ea --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java @@ -0,0 +1,19 @@ +package com.sap.sailing.datamining.impl.data; + +import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; +import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; + +public class LeaderboardGroupWithContextImpl implements LeaderboardGroupWithContext { + + private HasLeaderboardGroupContext context; + + public LeaderboardGroupWithContextImpl(HasLeaderboardGroupContext context) { + this.context = context; + } + + @Override + public String getLeaderboardGroupName() { + return context.getLeaderboardGroup().getName(); + } + +} diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java index 6b48e20db24..701f33c69ee 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java @@ -16,6 +16,7 @@ import com.sap.sailing.gwt.ui.datamining.client.DataMiningService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.DataMiningServer; import com.sap.sse.datamining.Query; +import com.sap.sse.datamining.factories.FunctionDTOFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.shared.DataMiningSerializationDummy; import com.sap.sse.datamining.shared.QueryResult; @@ -79,7 +80,7 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM private Collection functionsAsFunctionDTOs(Collection> functions) { Collection functionDTOs = new ArrayList(); for (Function function : functions) { - functionDTOs.add(function.asDTO()); + functionDTOs.add(FunctionDTOFactory.createFunctionDTO(function)); } return functionDTOs; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java index f3e9e24fb30..08eed173375 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java @@ -122,11 +122,15 @@ public class TestProcessorQuery { return element.getValue() >= 10; } }; - Processor> filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Number>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(lengthGrouper), retrievalFilterCriteria) { + Processor> filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Number, Number>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(lengthGrouper), retrievalFilterCriteria) { @Override protected Iterable retrieveData(Iterable element) { return element; } + @Override + protected Number contextifyElement(Number partialElement) { + return partialElement; + } }; query.setFirstProcessor(filteringRetrievalProcessor); diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java index b27f636411a..d725a4e7770 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java @@ -74,11 +74,15 @@ public class TestAbstractFilteringRetrievalProcessor { return element >= 0; } }; - filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Integer>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(resultReceiver), filterCriteria) { + filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Integer, Integer>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(resultReceiver), filterCriteria) { @Override protected Iterable retrieveData(Iterable element) { return element; } + @Override + protected Integer contextifyElement(Integer partialElement) { + return partialElement; + } }; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java new file mode 100644 index 00000000000..d6f3ca1e02b --- /dev/null +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java @@ -0,0 +1,70 @@ +package com.sap.sse.datamining.impl.function; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import org.junit.Before; +import org.junit.Test; + +import com.sap.sse.datamining.factories.FunctionFactory; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.impl.functions.CompoundFunction; +import com.sap.sse.datamining.shared.Unit; +import com.sap.sse.datamining.test.function.test_classes.ContainerElement; +import com.sap.sse.datamining.test.function.test_classes.ContainerElementImpl; +import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; +import com.sap.sse.datamining.test.function.test_classes.MarkedContainerImpl; +import com.sap.sse.datamining.test.util.TestsUtil; + +public class TestCompoundFunction { + + private Function getContainerElementFunction; + private Function getNameFunction; + + private Function compoundFunction; + + @Before + public void initializeCompoundFunction() throws ClassCastException, NoSuchMethodException, SecurityException { + List> functions = new ArrayList<>(); + getContainerElementFunction = FunctionFactory.createMethodWrappingFunction(MarkedContainer.class.getMethod("getContainerElement", new Class[0])); + functions.add(getContainerElementFunction); + getNameFunction = FunctionFactory.createMethodWrappingFunction(ContainerElement.class.getMethod("getName", new Class[0])); + functions.add(getNameFunction); + + compoundFunction = FunctionFactory.createCompoundFunction("TestCompoundFunction", functions); + } + + @Test(expected=IllegalArgumentException.class) + public void testConstruction() { + List> functions = new ArrayList<>(); + functions.add(getContainerElementFunction); + new CompoundFunction("IllegalCompoundFunction", functions, String.class); + } + + @Test + public void testInitialValues() { + assertThat(compoundFunction.isDimension(), is(true)); + //This is a workaround, because the assertion, that to types are equal checks for an instance of the given class instead. + assertThat("The actual declaring class did'nt match the expected one.", + compoundFunction.getDeclaringClass().equals(MarkedContainer.class), is(true)); + assertThat(compoundFunction.getSimpleName(), is("TestCompoundFunction")); + assertThat(compoundFunction.getLocalizedName(Locale.ENGLISH, TestsUtil.getTestStringMessages()), is("TestCompoundFunction")); + assertThat(compoundFunction.getResultUnit(), is(Unit.None)); + assertThat(compoundFunction.getResultDecimals(), is(0)); + } + + @Test + public void testInvocation() { + String containerElementName = "TestElement"; + ContainerElement element = new ContainerElementImpl(containerElementName); + MarkedContainer container = new MarkedContainerImpl(element); + + String result = compoundFunction.tryToInvoke(container); + assertThat(result, is(containerElementName)); + } + +} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java index 39b384bcda9..846aa9235ba 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java @@ -11,6 +11,7 @@ import java.util.Locale; import org.junit.Before; import org.junit.Test; +import com.sap.sse.datamining.factories.FunctionDTOFactory; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.i18n.DataMiningStringMessages; @@ -43,9 +44,9 @@ public class TestFunctionDTOConstruction { Function dimension = FunctionFactory.createMethodWrappingFunction(dimensionMethod); FunctionDTO expectedDimensionDTO = createExpectedDimensionDTO(); - assertThat(dimension.asDTO(), is(expectedDimensionDTO)); - assertThat(dimension.asDTO(Locale.ENGLISH, stringMessages), is(expectedDimensionDTO)); - assertThat(dimension.asDTO(Locale.GERMAN, stringMessages), is(expectedDimensionDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(dimension), is(expectedDimensionDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(dimension, Locale.ENGLISH, stringMessages), is(expectedDimensionDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(dimension, Locale.GERMAN, stringMessages), is(expectedDimensionDTO)); } public FunctionDTOImpl createExpectedDimensionDTO() { @@ -65,8 +66,8 @@ public class TestFunctionDTOConstruction { Function sideEffectFreeValue = FunctionFactory.createMethodWrappingFunction(sideEffectFreeValueMethod); FunctionDTO expectedDTO = createExpectedNullarySideEffectFreeValueDTO(); - assertThat(sideEffectFreeValue.asDTO(Locale.ENGLISH, stringMessages), is(expectedDTO)); - assertThat(sideEffectFreeValue.asDTO(Locale.GERMAN, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(sideEffectFreeValue, Locale.ENGLISH, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(sideEffectFreeValue, Locale.GERMAN, stringMessages), is(expectedDTO)); } private FunctionDTO createExpectedNullarySideEffectFreeValueDTO() { @@ -86,8 +87,8 @@ public class TestFunctionDTOConstruction { Function externalLibraryFunction = FunctionFactory.createMethodWrappingFunction(externalLibraryMethod); FunctionDTO expectedDTO = createExpectedExternalLibraryFunctionDTO(); - assertThat(externalLibraryFunction.asDTO(Locale.ENGLISH, stringMessages), is(expectedDTO)); - assertThat(externalLibraryFunction.asDTO(Locale.GERMAN, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(externalLibraryFunction, Locale.ENGLISH, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(externalLibraryFunction, Locale.GERMAN, stringMessages), is(expectedDTO)); } private FunctionDTO createExpectedExternalLibraryFunctionDTO() { @@ -107,8 +108,8 @@ public class TestFunctionDTOConstruction { Function increment = FunctionFactory.createMethodWrappingFunction(incrementMethod); FunctionDTO expectedDTO = createFunctionDTOWithParameters(); - assertThat(increment.asDTO(Locale.ENGLISH, stringMessages), is(expectedDTO)); - assertThat(increment.asDTO(Locale.GERMAN, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(increment, Locale.ENGLISH, stringMessages), is(expectedDTO)); + assertThat(FunctionDTOFactory.createFunctionDTO(increment, Locale.GERMAN, stringMessages), is(expectedDTO)); } private FunctionDTO createFunctionDTOWithParameters() { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java index 33f3e27d566..c660e577e40 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java @@ -12,6 +12,7 @@ import java.util.Locale; import org.junit.Before; import org.junit.Test; +import com.sap.sse.datamining.factories.FunctionDTOFactory; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionProvider; @@ -91,7 +92,7 @@ public class TestFunctionProvider { public void testGetFunctionForDTO() { Method getRegattaNameMethod = FunctionTestsUtil.getMethodFromClass(DataTypeWithContext.class, "getRegattaName"); Function getRegattaName = FunctionFactory.createMethodWrappingFunction(getRegattaNameMethod); - FunctionDTO getRegattaNameDTO = getRegattaName.asDTO(Locale.ENGLISH, stringMessages); + FunctionDTO getRegattaNameDTO = FunctionDTOFactory.createFunctionDTO(getRegattaName, Locale.ENGLISH, stringMessages); FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); @SuppressWarnings("unchecked") // Hamcrest requires type matching of actual and expected type, so the Functions have to be specific (without ) @@ -103,7 +104,7 @@ public class TestFunctionProvider { public void testGetFunctionForUnregisteredDTO() { Method incrementMethod = FunctionTestsUtil.getMethodFromClass(SimpleClassWithMarkedMethods.class, "increment", int.class); Function increment = FunctionFactory.createMethodWrappingFunction(incrementMethod); - FunctionDTO incrementDTO = increment.asDTO(Locale.ENGLISH, stringMessages); + FunctionDTO incrementDTO = FunctionDTOFactory.createFunctionDTO(increment, Locale.ENGLISH, stringMessages); FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); assertThat(functionProvider.getFunctionFor(incrementDTO), is(nullValue())); diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java new file mode 100644 index 00000000000..6bbe7b13431 --- /dev/null +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java @@ -0,0 +1,10 @@ +package com.sap.sse.datamining.test.function.test_classes; + +import com.sap.sse.datamining.shared.annotations.Dimension; + +public interface ContainerElement { + + @Dimension(messageKey="name") + public String getName(); + +} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java new file mode 100644 index 00000000000..5f347d772f3 --- /dev/null +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java @@ -0,0 +1,16 @@ +package com.sap.sse.datamining.test.function.test_classes; + +public class ContainerElementImpl implements ContainerElement { + + private String name; + + public ContainerElementImpl(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + +} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java new file mode 100644 index 00000000000..5fb7228115e --- /dev/null +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java @@ -0,0 +1,10 @@ +package com.sap.sse.datamining.test.function.test_classes; + +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + +public interface MarkedContainer { + + @SideEffectFreeValue(messageKey="containerElement") + public ContainerElement getContainerElement(); + +} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java new file mode 100644 index 00000000000..dbbe831adb8 --- /dev/null +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java @@ -0,0 +1,16 @@ +package com.sap.sse.datamining.test.function.test_classes; + +public class MarkedContainerImpl implements MarkedContainer { + + private ContainerElement containerElement; + + public MarkedContainerImpl(ContainerElement containerElement) { + this.containerElement = containerElement; + } + + @Override + public ContainerElement getContainerElement() { + return containerElement; + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java new file mode 100644 index 00000000000..956196c8adc --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java @@ -0,0 +1,52 @@ +package com.sap.sse.datamining.factories; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.i18n.DataMiningStringMessages; +import com.sap.sse.datamining.shared.annotations.Dimension; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; +import com.sap.sse.datamining.shared.dto.FunctionDTO; +import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; + +public class FunctionDTOFactory { + + /** + * Creates the corresponding DTO for the given function, with the functions simple name as display name. + */ + public static FunctionDTO createFunctionDTO(Function function) { + return createFunctionDTO(function, function.getSimpleName()); + } + + /** + * Creates the corresponding DTO for the given function, with the retrieved string message for the given locale and the + * contained message key as display name. The message key is provided with the {@link Dimension} or {@link SideEffectFreeValue} + * annotation.
+ * If the function has no message key, the function name is used as display name. + */ + public static FunctionDTO createFunctionDTO(Function function, Locale locale, DataMiningStringMessages stringMessages) { + return createFunctionDTO(function, function.getLocalizedName(locale, stringMessages)); + } + + private static FunctionDTO createFunctionDTO(Function function, String displayName) { + String functionName = function.getSimpleName(); + String sourceTypeName = function.getDeclaringClass().getSimpleName(); + String returnTypeName = function.getReturnType().getSimpleName(); + List parameterTypeNames = getParameterTypeNames(function); + return new FunctionDTOImpl(functionName, sourceTypeName, returnTypeName, parameterTypeNames, displayName, function.isDimension()); + } + + private static List getParameterTypeNames(Function function) { + List parameterTypeNames = new ArrayList<>(); + for (Class parameterType : function.getParameters()) { + parameterTypeNames.add(parameterType.getSimpleName()); + } + return parameterTypeNames; + } + + + private FunctionDTOFactory() { } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java index 395faf20b7b..7aa7676f9a6 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java @@ -1,7 +1,10 @@ package com.sap.sse.datamining.factories; import java.lang.reflect.Method; +import java.util.List; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.impl.functions.CompoundFunction; import com.sap.sse.datamining.impl.functions.MethodWrappingFunction; public class FunctionFactory { @@ -19,4 +22,15 @@ public class FunctionFactory { return new MethodWrappingFunction(method, (Class) method.getReturnType()); } + /** + * Creates a {@link CompoundFunction} for the given functions.
+ * Throws a {@link ClassCastException}, if the return type of the last function doesn't match the generic ReturnType parameter. + * + * @throws ClassCastException + */ + @SuppressWarnings("unchecked") + public static Function createCompoundFunction(String name, List> functions) throws ClassCastException { + return new CompoundFunction(name, functions, (Class) functions.get(functions.size() - 1).getReturnType()); + } + } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java index e21354e9ead..140615a1e2a 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java @@ -5,17 +5,17 @@ import java.util.Locale; import com.sap.sse.datamining.i18n.DataMiningStringMessages; import com.sap.sse.datamining.shared.Unit; -import com.sap.sse.datamining.shared.annotations.Dimension; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; -import com.sap.sse.datamining.shared.dto.FunctionDTO; public interface Function { public Class getDeclaringClass(); public Iterable> getParameters(); + public Class getReturnType(); public boolean isDimension(); + public String getSimpleName(); + public String getLocalizedName(Locale locale, DataMiningStringMessages stringMessages); /** @@ -33,19 +33,6 @@ public interface Function { * {@link IllegalAccessException} or {@link IllegalArgumentException} was thrown. */ public ReturnType tryToInvoke(Object instance, Object... parameters); - - /** - * Creates the corresponding DTO for this function, with the function name as display name. - */ - public FunctionDTO asDTO(); - - /** - * Creates the corresponding DTO for this function, with the retrieved string message for the given locale and the - * contained message key. The message key is provided with the {@link Dimension} or {@link SideEffectFreeValue} - * annotation.
- * If the function has no message key, the function name is used as display name. - */ - public FunctionDTO asDTO(Locale locale, DataMiningStringMessages stringMessages); public Unit getResultUnit(); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java index 884173cfb71..276241f42c1 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java @@ -10,10 +10,10 @@ import com.sap.sse.datamining.AdditionalResultDataBuilder; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; -public abstract class AbstractFilteringRetrievalProcessor - extends AbstractPartitioningParallelProcessor { +public abstract class AbstractFilteringRetrievalProcessor + extends AbstractPartitioningParallelProcessor { - private final FilterCriteria criteria; + private final FilterCriteria criteria; private Lock retrievedDataAmountLock; private int retrievedDataAmount; @@ -22,7 +22,7 @@ public abstract class AbstractFilteringRetrievalProcessor private int filteredDataAmount; public AbstractFilteringRetrievalProcessor(ExecutorService executor, - Collection> resultReceivers, FilterCriteria criteria) { + Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers); this.criteria = criteria; retrievedDataAmountLock = new ReentrantLock(); @@ -37,20 +37,23 @@ public abstract class AbstractFilteringRetrievalProcessor protected abstract Iterable retrieveData(InputType element); @Override - protected Callable createInstruction(final ResultType partialElement) { - return new Callable() { + protected Callable createInstruction(final ResultType partialElement) { + return new Callable() { @Override - public ResultType call() throws Exception { + public ResultTypeWithContext call() throws Exception { incrementRetrievedDataAmount(); - if (criteria.matches(partialElement)) { + ResultTypeWithContext elementWithContext = contextifyElement(partialElement); + if (criteria.matches(elementWithContext)) { incrementFilteredDataAmount(); - return partialElement; + return elementWithContext; } return createInvalidResult(); } }; } + protected abstract ResultTypeWithContext contextifyElement(ResultType partialElement); + private void incrementRetrievedDataAmount() { retrievedDataAmountLock.lock(); try { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java new file mode 100644 index 00000000000..54647856dfe --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java @@ -0,0 +1,162 @@ +package com.sap.sse.datamining.impl.functions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.i18n.DataMiningStringMessages; +import com.sap.sse.datamining.shared.Unit; + +public class CompoundFunction extends AbstractFunction { + + private static final String METHOD_CHAIN_CONNECTOR = " -> "; + + private String name; + private ArrayList> functions; + + public CompoundFunction(String name, List> functions, Class returnType) throws IllegalArgumentException { + super(isLastFunctionADimension(functions)); + checkThatReturnTypesMatch(functions, returnType); + + this.name = name; + this.functions = new ArrayList<>(functions); + } + + private static boolean isLastFunctionADimension(List> functions) { + return functions.get(functions.size() - 1).isDimension(); + } + + private void checkThatReturnTypesMatch(List> functions, Class returnType) { + Class lastFunctionReturnType = functions.get(functions.size() - 1).getReturnType(); + if (!lastFunctionReturnType.equals(returnType)) { + throw new IllegalArgumentException("The method return type " + lastFunctionReturnType.getName() + + " and expected return type " + returnType.getName() + " don't match"); + } + } + + @Override + public Class getDeclaringClass() { + return getFirstFunction().getDeclaringClass(); + } + + @Override + public Iterable> getParameters() { + return getFirstFunction().getParameters(); + } + + @SuppressWarnings("unchecked") // The cast has to work. The types were checked in the constructor. + @Override + public Class getReturnType() { + return (Class) getLastFunction().getReturnType(); + } + + @Override + public String getSimpleName() { + if (name != null && name.length() > 0) { + return name; + } + + return buildSimpleNameChain(); + } + + private String buildSimpleNameChain() { + Iterator> functionsIterator = functions.iterator(); + StringBuilder builder = new StringBuilder(functionsIterator.next().getSimpleName()); + while (functionsIterator.hasNext()) { + Function function = functionsIterator.next(); + builder.append(METHOD_CHAIN_CONNECTOR + function.getSimpleName()); + } + return builder.toString(); + } + + @Override + public String getLocalizedName(Locale locale, DataMiningStringMessages stringMessages) { + if (name != null && name.length() > 0) { + return name; + } + + return buildLocalizedNameChain(locale, stringMessages); + } + + private String buildLocalizedNameChain(Locale locale, DataMiningStringMessages stringMessages) { + Iterator> functionsIterator = functions.iterator(); + StringBuilder builder = new StringBuilder(functionsIterator.next().getLocalizedName(locale, stringMessages)); + while (functionsIterator.hasNext()) { + Function function = functionsIterator.next(); + builder.append(METHOD_CHAIN_CONNECTOR + function.getLocalizedName(locale, stringMessages)); + } + return builder.toString(); + } + + @Override + public ReturnType tryToInvoke(Object instance) { + return tryToInvoke(instance, new Object[0]); + } + + @SuppressWarnings("unchecked") // The cast has to work. The types were checked in the constructor. + @Override + public ReturnType tryToInvoke(Object instance, Object... parameters) { + Iterator> functionsIterator = functions.iterator(); + Object result = functionsIterator.next().tryToInvoke(instance, parameters); + while (functionsIterator.hasNext()) { + Function function = (Function) functionsIterator.next(); + result = function.tryToInvoke(result); + if (result == null) { + return null; + } + } + return (ReturnType) result; + } + + @Override + public Unit getResultUnit() { + return getLastFunction().getResultUnit(); + } + + @Override + public int getResultDecimals() { + return getLastFunction().getResultDecimals(); + } + + private Function getFirstFunction() { + return functions.get(0); + } + + private Function getLastFunction() { + return functions.get(functions.size() - 1); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((functions == null) ? 0 : functions.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CompoundFunction other = (CompoundFunction) obj; + if (functions == null) { + if (other.functions != null) + return false; + } else if (!functions.equals(other.functions)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + return true; + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java index dcfc6d6f71d..c8f6e28f053 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java @@ -1,6 +1,7 @@ package com.sap.sse.datamining.impl.functions; import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.factories.FunctionDTOFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -14,7 +15,7 @@ public class FunctionDTOFilterCriteria implements FilterCriteria> { @Override public boolean matches(Function function) { - FunctionDTO functionDTO = function.asDTO(); + FunctionDTO functionDTO = FunctionDTOFactory.createFunctionDTO(function); return functionDTOToMatch.equals(functionDTO); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java index 8ef5e900fab..dd221e63865 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java @@ -2,9 +2,7 @@ package com.sap.sse.datamining.impl.functions; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Locale; import java.util.logging.Level; @@ -12,16 +10,12 @@ import com.sap.sse.datamining.i18n.DataMiningStringMessages; import com.sap.sse.datamining.shared.Unit; import com.sap.sse.datamining.shared.annotations.Dimension; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; -import com.sap.sse.datamining.shared.dto.FunctionDTO; -import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; public class MethodWrappingFunction extends AbstractFunction { - private Method method; - - private String messageKey; - private int resultDecimals; - private Unit resultUnit; + private final Method method; + private Class returnType; + private AdditionalFunctionData additionalData; /** * Throws an {@link IllegalArgumentException}, if the return type of the method and the given returnType @@ -32,6 +26,7 @@ public class MethodWrappingFunction extends AbstractFunction extends AbstractFunction extends AbstractFunction getReturnType() { + return returnType; + } + @Override public ReturnType tryToInvoke(Object instance) { return tryToInvoke(instance, new Object[0]); @@ -87,50 +85,29 @@ public class MethodWrappingFunction extends AbstractFunction parameterTypeNames = getParameterTypeNames(); - return new FunctionDTOImpl(functionName, sourceTypeName, returnTypeName, parameterTypeNames, displayName, isDimension()); - } - - private List getParameterTypeNames() { - List parameterTypeNames = new ArrayList<>(); - for (Class parameterType : method.getParameterTypes()) { - parameterTypeNames.add(parameterType.getSimpleName()); - } - return parameterTypeNames; + private String getMethodName() { + return method.getName(); } @Override From 009a19708c4ea33a21660c558c0383a7d7f6ce57 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Wed, 26 Mar 2014 18:27:20 +0100 Subject: [PATCH 002/114] Implemented a method in the function provider to get transitive dimensions --- .../impl/function/TestCompoundFunction.java | 2 +- .../impl/function/TestFunctionProvider.java | 14 +++++++++++ .../factories/FunctionDTOFactory.java | 2 +- .../sse/datamining/functions/Function.java | 2 +- .../functions/FunctionProvider.java | 12 ++++++++++ .../impl/functions/CompoundFunction.java | 4 ++-- .../DeclaringTypeOrParameterTypeCriteria.java | 2 +- .../functions/MethodWrappingFunction.java | 4 ++-- .../functions/RegistryFunctionsProvider.java | 23 +++++++++++++++++++ .../functions/SimpleFunctionRegistry.java | 6 ++--- 10 files changed, 60 insertions(+), 11 deletions(-) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java index d6f3ca1e02b..29e285a2128 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java @@ -50,7 +50,7 @@ public class TestCompoundFunction { assertThat(compoundFunction.isDimension(), is(true)); //This is a workaround, because the assertion, that to types are equal checks for an instance of the given class instead. assertThat("The actual declaring class did'nt match the expected one.", - compoundFunction.getDeclaringClass().equals(MarkedContainer.class), is(true)); + compoundFunction.getDeclaringType().equals(MarkedContainer.class), is(true)); assertThat(compoundFunction.getSimpleName(), is("TestCompoundFunction")); assertThat(compoundFunction.getLocalizedName(Locale.ENGLISH, TestsUtil.getTestStringMessages()), is("TestCompoundFunction")); assertThat(compoundFunction.getResultUnit(), is(Unit.None)); diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java index c660e577e40..86e7ba73266 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java @@ -24,11 +24,13 @@ import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionR import com.sap.sse.datamining.impl.functions.RegistryFunctionsProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.shared.dto.FunctionDTO; +import com.sap.sse.datamining.test.function.test_classes.ContainerElement; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextProcessor; import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.TestsUtil; @@ -48,6 +50,8 @@ public class TestFunctionProvider { classesToScan.add(DataTypeWithContext.class); classesToScan.add(DataTypeWithContextProcessor.class); classesToScan.add(ExtendingInterface.class); + classesToScan.add(MarkedContainer.class); + classesToScan.add(ContainerElement.class); ParallelFunctionRetriever markedFunctionRetriever = new PartitioningParallelMarkedFunctionRetriever(classesToScan, FunctionTestsUtil.getExecutor()); functionRegistry.registerFunctionsRetrievedBy(markedFunctionRetriever); @@ -115,5 +119,15 @@ public class TestFunctionProvider { FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); assertThat(functionProvider.getFunctionFor(null), is(nullValue())); } + + @Test + public void testGetTransitiveDimension() throws ClassCastException, NoSuchMethodException, SecurityException { + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); + + Collection> expectedDimensions = new HashSet<>(); + expectedDimensions.add(FunctionFactory.createMethodWrappingFunction(ContainerElement.class.getMethod("getName", + new Class[0]))); + assertThat(functionProvider.getTransitiveDimensionsFor(MarkedContainer.class, 1), is(expectedDimensions)); + } } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java index 956196c8adc..9e234952022 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionDTOFactory.java @@ -32,7 +32,7 @@ public class FunctionDTOFactory { private static FunctionDTO createFunctionDTO(Function function, String displayName) { String functionName = function.getSimpleName(); - String sourceTypeName = function.getDeclaringClass().getSimpleName(); + String sourceTypeName = function.getDeclaringType().getSimpleName(); String returnTypeName = function.getReturnType().getSimpleName(); List parameterTypeNames = getParameterTypeNames(function); return new FunctionDTOImpl(functionName, sourceTypeName, returnTypeName, parameterTypeNames, displayName, function.isDimension()); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java index 140615a1e2a..f717899c341 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/Function.java @@ -8,7 +8,7 @@ import com.sap.sse.datamining.shared.Unit; public interface Function { - public Class getDeclaringClass(); + public Class getDeclaringType(); public Iterable> getParameters(); public Class getReturnType(); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java index 55f6dffab4a..39439799d60 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java @@ -8,6 +8,18 @@ public interface FunctionProvider { public Collection> getDimensionsFor(Class dataType); + /** + * Collects all dimensions for the given data type, where transitive dimensions will also be + * collected. A transitive dimension is a dimension, that can be reached with functions of the + * given data type.
+ * The depth defines the maximum amount of functions that can be between the data type and the + * collected dimensions. A depth of 0 would collect only the dimensions of the given data type. + * @param dataType + * @param depth + * @return + */ + public Collection> getTransitiveDimensionsFor(Class dataType, int depth); + public Collection> getFunctionsFor(Class sourceType); /** diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java index 54647856dfe..7fc0ad2cb05 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/CompoundFunction.java @@ -37,8 +37,8 @@ public class CompoundFunction extends AbstractFunction { } @Override - public Class getDeclaringClass() { - return getFirstFunction().getDeclaringClass(); + public Class getDeclaringType() { + return getFirstFunction().getDeclaringType(); } @Override diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java index 72cd7f54535..cfb6fa2aadf 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java @@ -65,7 +65,7 @@ public class DeclaringTypeOrParameterTypeCriteria implements FilterCriteria function, Class expectingType) { - return function.getDeclaringClass().equals(expectingType); + return function.getDeclaringType().equals(expectingType); } } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java index dd221e63865..bace0946761 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodWrappingFunction.java @@ -53,7 +53,7 @@ public class MethodWrappingFunction extends AbstractFunction getDeclaringClass() { + public Class getDeclaringType() { return method.getDeclaringClass(); } @@ -112,7 +112,7 @@ public class MethodWrappingFunction extends AbstractFunction> getTransitiveDimensionsFor(Class dataType, int depth) { + Collection> dimensions = new HashSet<>(); + + Collection> typesToCheck = new HashSet<>(); + Collection> typesToAdd = new HashSet<>(); + typesToCheck.add(dataType); + for (int i = 0; i <= depth; i++) { + for (Class type : typesToCheck) { + for (Function function : getFunctionsFor(type)) { + if (function.isDimension()) { + dimensions.add(function); + } + typesToAdd.add(function.getReturnType()); + } + } + typesToCheck.clear(); + typesToCheck.addAll(typesToAdd); + typesToAdd.clear(); + } + return dimensions; + } + @Override public Collection> getFunctionsFor(Class sourceType) { return filterForDeclaringType(functionRegistry.getAllRegisteredFunctions(), sourceType); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index 675f22b5ca7..6240ad441e9 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -62,10 +62,10 @@ public class SimpleFunctionRegistry implements FunctionRegistry { } private void putFunctionIntoMap(Function function) { - if (!registeredFunctionsMappedByDeclaringClass.containsKey(function.getDeclaringClass())) { - registeredFunctionsMappedByDeclaringClass.put(function.getDeclaringClass(), new HashSet>()); + if (!registeredFunctionsMappedByDeclaringClass.containsKey(function.getDeclaringType())) { + registeredFunctionsMappedByDeclaringClass.put(function.getDeclaringType(), new HashSet>()); } - registeredFunctionsMappedByDeclaringClass.get(function.getDeclaringClass()).add(function); + registeredFunctionsMappedByDeclaringClass.get(function.getDeclaringType()).add(function); } @Override From b3ac8b2cafa97fe1131b5f1e793b4df887409d89 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Wed, 26 Mar 2014 18:50:24 +0100 Subject: [PATCH 003/114] Changed the dimension handling of the SimpleFunctionRegistry --- ...stSimpleFunctionRegistryRegistrations.java | 8 +-- .../functions/FunctionRegistry.java | 5 +- .../functions/RegistryFunctionsProvider.java | 4 +- .../functions/SimpleFunctionRegistry.java | 60 ++++++++++++------- 4 files changed, 46 insertions(+), 31 deletions(-) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java index 0d7da633a77..50b2fcd3340 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java @@ -33,8 +33,8 @@ public class TestSimpleFunctionRegistryRegistrations { Set> expectedRegisteredFunctionsAsSet = new HashSet<>(); expectedRegisteredFunctionsAsSet.add(FunctionFactory.createMethodWrappingFunction(dimension)); Iterable> expectedRegisteredFunctions = expectedRegisteredFunctionsAsSet; - assertThat(registry.getAllRegisteredFunctions(), is(expectedRegisteredFunctions)); - assertThat(registry.getRegisteredFunctionsOf(SimpleClassWithMarkedMethods.class), is(expectedRegisteredFunctions)); + assertThat(registry.getAllFunctions(), is(expectedRegisteredFunctions)); + assertThat(registry.getFunctionsOf(SimpleClassWithMarkedMethods.class), is(expectedRegisteredFunctions)); } @Test @@ -46,7 +46,7 @@ public class TestSimpleFunctionRegistryRegistrations { expectedRegisteredFunctionsAsSet.addAll(FunctionTestsUtil.getMarkedMethodsOfSimpleClassWithMarkedMethod()); expectedRegisteredFunctionsAsSet.addAll(FunctionTestsUtil.getMethodsOfExternalLibraryClass()); Iterable> expectedRegisteredFunctions = expectedRegisteredFunctionsAsSet; - assertThat(registry.getAllRegisteredFunctions(), is(expectedRegisteredFunctions)); + assertThat(registry.getAllFunctions(), is(expectedRegisteredFunctions)); } private void registerMethodsOfTestClassesViaFunctionRetrieversTo(FunctionRegistry registry) { @@ -73,7 +73,7 @@ public class TestSimpleFunctionRegistryRegistrations { Set> expectedRegisteredFunctionsAsSet = new HashSet<>(); expectedRegisteredFunctionsAsSet.add(FunctionFactory.createMethodWrappingFunction(dimension)); Iterable> expectedRegisteredFunctions = expectedRegisteredFunctionsAsSet; - assertThat(registry.getAllRegisteredFunctions(), is(expectedRegisteredFunctions)); + assertThat(registry.getAllFunctions(), is(expectedRegisteredFunctions)); } } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java index 147051180b4..5cce1e875d4 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java @@ -10,8 +10,9 @@ public interface FunctionRegistry { public void registerFunctionsRetrievedBy(ParallelFunctionRetriever functionRetriever); public void registerAll(Iterable> functions); - public Collection> getAllRegisteredFunctions(); - public Iterable> getRegisteredFunctionsOf(Class declaringClass); + public Collection> getAllFunctions(); + public Iterable> getFunctionsOf(Class declaringClass); public Collection> getAllDimensions(); + public Iterable> getDimensionsOf(Class declaringClass); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java index f8436f24640..4b4bbafd2c3 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java @@ -60,7 +60,7 @@ public class RegistryFunctionsProvider implements FunctionProvider { @Override public Collection> getFunctionsFor(Class sourceType) { - return filterForDeclaringType(functionRegistry.getAllRegisteredFunctions(), sourceType); + return filterForDeclaringType(functionRegistry.getAllFunctions(), sourceType); } private Collection> filterForDeclaringType(Collection> functions, Class sourceType) { @@ -96,7 +96,7 @@ public class RegistryFunctionsProvider implements FunctionProvider { FilterCriteria> functionDTOFilterCriteria = new FunctionDTOFilterCriteria(functionDTO); ParallelFilter> functionMatchesDTOFilter = createFilterForCriteria(functionDTOFilterCriteria); - Collection> functionsMatchingDTO = executeFilter(functionMatchesDTOFilter, functionRegistry.getAllRegisteredFunctions()); + Collection> functionsMatchingDTO = executeFilter(functionMatchesDTOFilter, functionRegistry.getAllFunctions()); if (moreThanOneFunctionMatchedDTO(functionsMatchingDTO)) { logThatMoreThanOneFunctionMatchedDTO(functionDTO, functionsMatchingDTO); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index 6240ad441e9..e1b6e34ad91 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -19,12 +19,12 @@ public class SimpleFunctionRegistry implements FunctionRegistry { private static final Logger LOGGER = Logger.getLogger(SimpleFunctionRegistry.class.getName()); - private final Map, Collection>> registeredFunctionsMappedByDeclaringClass; - private final Collection> dimensions; + private final Map, Collection>> functionsMappedByDeclaringClass; + private final Map, Collection>> dimensionsMappedByDeclaringClass; public SimpleFunctionRegistry() { - registeredFunctionsMappedByDeclaringClass = new HashMap<>(); - dimensions = new HashSet<>(); + functionsMappedByDeclaringClass = new HashMap<>(); + dimensionsMappedByDeclaringClass = new HashMap<>(); } @Override @@ -52,39 +52,53 @@ public class SimpleFunctionRegistry implements FunctionRegistry { @Override public void register(Function function) { putFunctionIntoMap(function); - addToDimensionsIfFunctionIsADimension(function); - } - - private void addToDimensionsIfFunctionIsADimension(Function function) { - if (function.isDimension()) { - dimensions.add(function); - } + putToDimensionsIfFunctionIsADimension(function); } private void putFunctionIntoMap(Function function) { - if (!registeredFunctionsMappedByDeclaringClass.containsKey(function.getDeclaringType())) { - registeredFunctionsMappedByDeclaringClass.put(function.getDeclaringType(), new HashSet>()); + Class key = function.getDeclaringType(); + if (!functionsMappedByDeclaringClass.containsKey(key)) { + functionsMappedByDeclaringClass.put(key, new HashSet>()); + } + functionsMappedByDeclaringClass.get(key).add(function); + } + + private void putToDimensionsIfFunctionIsADimension(Function function) { + if (function.isDimension()) { + Class key = function.getDeclaringType(); + if (!dimensionsMappedByDeclaringClass.containsKey(key)) { + dimensionsMappedByDeclaringClass.put(key, new HashSet>()); + } + dimensionsMappedByDeclaringClass.get(key).add(function); } - registeredFunctionsMappedByDeclaringClass.get(function.getDeclaringType()).add(function); } @Override - public Collection> getAllRegisteredFunctions() { - Set> registeredMethods = new HashSet<>(); - for (Collection> registeredMethodsOfClass : registeredFunctionsMappedByDeclaringClass.values()) { - registeredMethods.addAll(registeredMethodsOfClass); - } - return registeredMethods; + public Collection> getAllFunctions() { + return collectAllFunctionsIn(functionsMappedByDeclaringClass); } @Override - public Iterable> getRegisteredFunctionsOf(Class declaringClass) { - return registeredFunctionsMappedByDeclaringClass.get(declaringClass); + public Iterable> getFunctionsOf(Class declaringClass) { + return functionsMappedByDeclaringClass.get(declaringClass); } @Override public Collection> getAllDimensions() { - return dimensions; + return collectAllFunctionsIn(dimensionsMappedByDeclaringClass); + } + + @Override + public Iterable> getDimensionsOf(Class declaringClass) { + return dimensionsMappedByDeclaringClass.get(declaringClass); + } + + private Collection> collectAllFunctionsIn(Map, Collection>> functionsMap) { + Set> registeredMethods = new HashSet<>(); + for (Collection> registeredMethodsOfClass : functionsMap.values()) { + registeredMethods.addAll(registeredMethodsOfClass); + } + return registeredMethods; } } From 2d19686a269de1465dd8234c8d39cf47f7d9e7e6 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Wed, 26 Mar 2014 19:01:15 +0100 Subject: [PATCH 004/114] Cleaned the algorithm to get the transitive dimensions --- .../components/ParallelFilteringProcessor.java | 2 +- .../functions/RegistryFunctionsProvider.java | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/ParallelFilteringProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/ParallelFilteringProcessor.java index 00dac0750ad..7aed1a294ec 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/ParallelFilteringProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/ParallelFilteringProcessor.java @@ -26,9 +26,9 @@ public class ParallelFilteringProcessor extends AbstractSimpleParalle @Override public InputType call() throws Exception { if (filterCriteria.matches(element)) { + increaseFilteredDataAmount(); return element; } else { - increaseFilteredDataAmount(); return ParallelFilteringProcessor.super.createInvalidResult(); } } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java index 4b4bbafd2c3..759729e914b 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java @@ -44,12 +44,8 @@ public class RegistryFunctionsProvider implements FunctionProvider { typesToCheck.add(dataType); for (int i = 0; i <= depth; i++) { for (Class type : typesToCheck) { - for (Function function : getFunctionsFor(type)) { - if (function.isDimension()) { - dimensions.add(function); - } - typesToAdd.add(function.getReturnType()); - } + dimensions.addAll(getDimensionsFor(type)); + typesToAdd.addAll(getReturnTypesOfFunctionsFor(type)); } typesToCheck.clear(); typesToCheck.addAll(typesToAdd); @@ -58,6 +54,14 @@ public class RegistryFunctionsProvider implements FunctionProvider { return dimensions; } + private Collection> getReturnTypesOfFunctionsFor(Class type) { + Collection> returnTypes = new HashSet<>(); + for (Function function : getFunctionsFor(type)) { + returnTypes.add(function.getReturnType()); + } + return returnTypes; + } + @Override public Collection> getFunctionsFor(Class sourceType) { return filterForDeclaringType(functionRegistry.getAllFunctions(), sourceType); From 40d0b0898606691fce1df1e44457924c4676113d Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 27 Mar 2014 16:36:48 +0100 Subject: [PATCH 005/114] Improved the query logging --- .../src/com/sap/sse/datamining/impl/ProcessorQuery.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java index 1fa7ae28943..65f4d3c2b4c 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java @@ -72,6 +72,7 @@ public class ProcessorQuery implements Query processQuery(long timeoutInMillis) throws InterruptedException, TimeoutException { + processorTimedOut = false; final long startTime = System.nanoTime(); executor.execute(new Runnable() { @Override @@ -80,7 +81,11 @@ public class ProcessorQuery implements Query implements Query Date: Thu, 27 Mar 2014 17:19:10 +0100 Subject: [PATCH 006/114] Cleaned DataMiningActivator and ClassesWithFunctionsService --- ...DataMiningClassesWithFunctionsService.java | 18 +---- .../ClassesWithFunctionsService.java | 9 +-- .../datamining/impl/DataMiningActivator.java | 76 +++++++++++-------- 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java index ddc69a317a8..29c67938a58 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java @@ -1,34 +1,24 @@ package com.sap.sailing.datamining.impl.data; -import java.util.Collection; import java.util.HashSet; +import java.util.Set; import com.sap.sailing.datamining.data.GPSFixWithContext; import com.sap.sailing.datamining.data.TrackedLegOfCompetitorWithContext; import com.sap.sse.datamining.functions.ClassesWithFunctionsService; public class DataMiningClassesWithFunctionsService implements ClassesWithFunctionsService { - - @Override - public boolean hasInternalClassesWithMarkedMethods() { - return true; - } @Override - public Collection> getInternalClassesWithMarkedMethods() { - Collection> internalClasses = new HashSet<>(); + public Set> getInternalClassesWithMarkedMethods() { + Set> internalClasses = new HashSet<>(); internalClasses.add(GPSFixWithContext.class); internalClasses.add(TrackedLegOfCompetitorWithContext.class); return internalClasses; } - - @Override - public boolean hasExternalLibraryClasses() { - return false; - } @Override - public Collection> getExternalLibraryClasses() { + public Set> getExternalLibraryClasses() { return new HashSet<>(); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ClassesWithFunctionsService.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ClassesWithFunctionsService.java index 04a3b25fb03..5df69f11559 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ClassesWithFunctionsService.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ClassesWithFunctionsService.java @@ -1,13 +1,10 @@ package com.sap.sse.datamining.functions; -import java.util.Collection; +import java.util.Set; public interface ClassesWithFunctionsService { - public boolean hasInternalClassesWithMarkedMethods(); - public Collection> getInternalClassesWithMarkedMethods(); - - public boolean hasExternalLibraryClasses(); - public Collection> getExternalLibraryClasses(); + public Set> getInternalClassesWithMarkedMethods(); + public Set> getExternalLibraryClasses(); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java index 969d5ba55ae..2aa18d54d57 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java @@ -1,6 +1,9 @@ package com.sap.sse.datamining.impl; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -29,6 +32,7 @@ public class DataMiningActivator implements BundleActivator { private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3); private static BundleContext context; + private static Collection> serviceReferences; private static DataMiningServer dataMiningServer; private static DataMiningStringMessages stringMessages; @@ -37,6 +41,7 @@ public class DataMiningActivator implements BundleActivator { @Override public void start(BundleContext context) throws Exception { DataMiningActivator.context = context; + serviceReferences = getAllClassesWithMarkedMethodsServices(); stringMessages = DataMiningStringMessages.Util.getDefaultStringMessages(); executor = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, @@ -55,65 +60,70 @@ public class DataMiningActivator implements BundleActivator { private FunctionRegistry createAndBuildFunctionRegistry() { FunctionRegistry functionRegistry = new SimpleFunctionRegistry(); - for (ServiceReference serviceReference : getAllClassesWithMarkedMethodsServices()) { - registerServiceTo(serviceReference, functionRegistry); + + Set> internalClassesWithMarkedMethods = new HashSet<>(); + Set> externalLibraryClasses = new HashSet<>(); + for (ServiceReference serviceReference : serviceReferences) { + ClassesWithFunctionsService service = context.getService(serviceReference); + + Set> internalClassesWithMarkedMethodsToAdd = service.getInternalClassesWithMarkedMethods(); + if (internalClassesWithMarkedMethodsToAdd != null) { + internalClassesWithMarkedMethods.addAll(internalClassesWithMarkedMethodsToAdd); + } + + Set> externalLibraryClassesToAdd = service.getExternalLibraryClasses(); + if (externalLibraryClassesToAdd != null) { + externalLibraryClasses.addAll(externalLibraryClassesToAdd); + } } + + registerFunctions(internalClassesWithMarkedMethods, externalLibraryClasses, functionRegistry); return functionRegistry; } - private ServiceReference[] getAllClassesWithMarkedMethodsServices() { + private Collection> getAllClassesWithMarkedMethodsServices() { try { ServiceReference[] serviceReferences = context.getServiceReferences(ClassesWithFunctionsService.class.getName(), null); if (serviceReferences != null) { - return serviceReferences; + return castServiceReferences(serviceReferences); } } catch (InvalidSyntaxException e) { LOGGER.log(Level.SEVERE, "Error getting the service references. Data mining won't work.", e); } LOGGER.log(Level.SEVERE, "There were no " + ClassesWithFunctionsService.class.getName() + "-Services registered. Data mining won't work."); - return new ServiceReference[0]; + return new ArrayList<>(); } - @SuppressWarnings("unchecked") - private void registerServiceTo(ServiceReference serviceReference, FunctionRegistry functionRegistry) { - try { - ServiceReference specificServiceReference = (ServiceReference) serviceReference; - registerSpecificServiceTo(context.getService(specificServiceReference), functionRegistry); - } catch (ClassCastException exception) { - String serviceName = context.getService(serviceReference).getClass().getName(); - LOGGER.log(Level.WARNING, "Couldn't register the service '" + serviceName + "' to the function registry." - + " Data mining functionalities will be restricted.", exception); - return; + private Collection> castServiceReferences(ServiceReference[] serviceReferences) { + Collection> specificServiceReferences = new ArrayList<>(); + for (ServiceReference serviceReference : serviceReferences) { + try { + @SuppressWarnings("unchecked") // This is necessary, because you can't use instanceof with specific generics + ServiceReference specificServiceReference = (ServiceReference) serviceReference; + specificServiceReferences.add(specificServiceReference); + } catch (ClassCastException exception) { + String serviceName = context.getService(serviceReference).getClass().getName(); + LOGGER.log(Level.WARNING, "Couldn't register the service '" + serviceName + "' to the function registry." + + " Data mining functionalities will be restricted.", exception); + } } + return specificServiceReferences; } - private void registerSpecificServiceTo(ClassesWithFunctionsService service, FunctionRegistry functionRegistry) { - if (service.hasInternalClassesWithMarkedMethods()) { - registerInternalMarkedFunctionsTo(service, functionRegistry); - } - if (service.hasExternalLibraryClasses()) { - registerExternalLibraryFunctionsTo(service, functionRegistry); - } - } - - public void registerInternalMarkedFunctionsTo(ClassesWithFunctionsService service, FunctionRegistry functionRegistry) { - Collection> internalClasses = service.getInternalClassesWithMarkedMethods(); + private void registerFunctions(Set> internalClassesWithMarkedMethods, + Set> externalLibraryClasses, FunctionRegistry functionRegistry) { ParallelFunctionRetriever internalMarkedFunctionsRetriever = new PartitioningParallelMarkedFunctionRetriever( - internalClasses, getExecutor()); + internalClassesWithMarkedMethods, getExecutor()); functionRegistry.registerFunctionsRetrievedBy(internalMarkedFunctionsRetriever); - } - public void registerExternalLibraryFunctionsTo(ClassesWithFunctionsService service, - FunctionRegistry functionRegistry) { - Collection> externalClasses = service.getExternalLibraryClasses(); ParallelFunctionRetriever externalLibraryFunctionsRetriever = new PartitionParallelExternalFunctionRetriever( - externalClasses, getExecutor()); + externalLibraryClasses, getExecutor()); functionRegistry.registerFunctionsRetrievedBy(externalLibraryFunctionsRetriever); } @Override public void stop(BundleContext context) throws Exception { - for (ServiceReference serviceReference : getAllClassesWithMarkedMethodsServices()) { + for (ServiceReference serviceReference : serviceReferences) { context.ungetService(serviceReference); } } From e31a0d6c95da77fecca04300cce6887d09ab6165 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 27 Mar 2014 17:41:52 +0100 Subject: [PATCH 007/114] Implemented processors for the function retrieval --- .../functions/FunctionRetrievalProcessor.java | 9 ++++ .../ExternalFunctionRetrievalProcessor.java | 22 ++++++++ .../FilteringFunctionRetrievalProcessor.java | 54 +++++++++++++++++++ .../FilteringFunctionRetrievalWorker.java | 6 +-- .../InternalFunctionRetrievalProcessor.java | 27 ++++++++++ 5 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRetrievalProcessor.java new file mode 100644 index 00000000000..8b8b5b09a6d --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRetrievalProcessor.java @@ -0,0 +1,9 @@ +package com.sap.sse.datamining.functions; + +import java.util.Collection; + +import com.sap.sse.datamining.components.Processor; + +public interface FunctionRetrievalProcessor extends Processor>> { + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java new file mode 100644 index 00000000000..b241ff7f0a4 --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java @@ -0,0 +1,22 @@ +package com.sap.sse.datamining.impl.functions; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.functions.Function; + +public class ExternalFunctionRetrievalProcessor extends FilteringFunctionRetrievalProcessor { + + public ExternalFunctionRetrievalProcessor(ExecutorService executor, + Collection>>> resultReceivers) { + super(executor, resultReceivers, createFunctionFilter()); + } + + private static FilterCriteria createFunctionFilter() { + return new MethodIsCorrectExternalFunctionFilterCriteria(); + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java new file mode 100644 index 00000000000..b4e1aa3f64d --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java @@ -0,0 +1,54 @@ +package com.sap.sse.datamining.impl.functions; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashSet; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.AdditionalResultDataBuilder; +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.factories.FunctionFactory; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.functions.FunctionRetrievalProcessor; +import com.sap.sse.datamining.impl.components.AbstractPartitioningParallelProcessor; + +public class FilteringFunctionRetrievalProcessor extends + AbstractPartitioningParallelProcessor>, Class, Collection>> implements + FunctionRetrievalProcessor { + + private FilterCriteria functionFilter; + + public FilteringFunctionRetrievalProcessor(ExecutorService executor, + Collection>>> resultReceivers, FilterCriteria functionFilter) { + super(executor, resultReceivers); + this.functionFilter = functionFilter; + } + + @Override + protected Callable>> createInstruction(final Class partialElement) { + return new Callable>>() { + @Override + public Collection> call() throws Exception { + Collection> functions = new HashSet<>(); + for (Method method : partialElement.getMethods()) { + if (functionFilter.matches(method)) { + functions.add(FunctionFactory.createMethodWrappingFunction(method)); + } + } + return functions; + } + }; + } + + @Override + protected Iterable> partitionElement(Collection> element) { + return element; + } + + @Override + protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) { + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java index 79f603d079b..c1fe2df5bbc 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java @@ -9,8 +9,8 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.impl.workers.AbstractComponentWorker; -public class FilteringFunctionRetrievalWorker extends AbstractComponentWorker>> - implements FunctionRetrievalWorker { +public class FilteringFunctionRetrievalWorker extends AbstractComponentWorker>> implements + FunctionRetrievalWorker { private Iterable> classesToScan; private FilterCriteria filter; @@ -38,7 +38,7 @@ public class FilteringFunctionRetrievalWorker extends AbstractComponentWorker> classesToScan) { this.classesToScan = classesToScan; } - + public void setFilter(FilterCriteria filterCriteria) { this.filter = filterCriteria; } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java new file mode 100644 index 00000000000..47b602437c9 --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java @@ -0,0 +1,27 @@ +package com.sap.sse.datamining.impl.functions; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.impl.criterias.CompoundFilterCriteria; +import com.sap.sse.datamining.impl.criterias.OrCompoundFilterCriteria; + +public class InternalFunctionRetrievalProcessor extends FilteringFunctionRetrievalProcessor { + + public InternalFunctionRetrievalProcessor(ExecutorService executor, + Collection>>> resultReceivers) { + super(executor, resultReceivers, createFilterCriteria()); + } + + private static FilterCriteria createFilterCriteria() { + CompoundFilterCriteria compoundFilterCriteria = new OrCompoundFilterCriteria<>(); + compoundFilterCriteria.addCriteria(new MethodIsCorrectDimensionFilterCriteria()); + compoundFilterCriteria.addCriteria(new MethodIsCorrectSideEffectFreeValueFilterCriteria()); + return compoundFilterCriteria; + } + +} From df43564aaa1252534bda52828563d52c1d713329 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 27 Mar 2014 18:27:14 +0100 Subject: [PATCH 008/114] Removed the deprecated function retrievers and adjusted the DataMiningActivator and the tests --- .../impl/function/TestFunctionProvider.java | 30 +++---- .../impl/function/TestFunctionRetrievers.java | 84 ------------------- .../TestSimpleFunctionRegistryAccess.java | 24 +++--- ...stSimpleFunctionRegistryRegistrations.java | 28 +++---- .../functions/FunctionRegistry.java | 3 +- .../functions/ParallelFunctionRetriever.java | 7 -- .../datamining/impl/DataMiningActivator.java | 22 +---- ...PartitioningParallelFunctionRetriever.java | 76 ----------------- .../FilteringFunctionRetrievalWorker.java | 46 ---------- .../functions/FunctionRetrievalWorker.java | 43 ---------- ...tionParallelExternalFunctionRetriever.java | 17 ---- ...ioningParallelMarkedFunctionRetriever.java | 17 ---- .../functions/SimpleFunctionRegistry.java | 72 ++++++++++++++-- 13 files changed, 105 insertions(+), 364 deletions(-) delete mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionRetrievers.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ParallelFunctionRetriever.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/AbstractPartitioningParallelFunctionRetriever.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionRetrievalWorker.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitionParallelExternalFunctionRetriever.java delete mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitioningParallelMarkedFunctionRetriever.java diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java index 86e7ba73266..3d242765b72 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java @@ -17,10 +17,7 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; import com.sap.sse.datamining.i18n.DataMiningStringMessages; -import com.sap.sse.datamining.impl.functions.PartitionParallelExternalFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionRetriever; import com.sap.sse.datamining.impl.functions.RegistryFunctionsProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -32,6 +29,7 @@ import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.TestsUtil; @@ -43,22 +41,20 @@ public class TestFunctionProvider { @Before public void initializeFunctionRegistry() { - functionRegistry = new SimpleFunctionRegistry(); + functionRegistry = new SimpleFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); - Collection> classesToScan = new HashSet<>(); - classesToScan.add(SimpleClassWithMarkedMethods.class); - classesToScan.add(DataTypeWithContext.class); - classesToScan.add(DataTypeWithContextProcessor.class); - classesToScan.add(ExtendingInterface.class); - classesToScan.add(MarkedContainer.class); - classesToScan.add(ContainerElement.class); - ParallelFunctionRetriever markedFunctionRetriever = new PartitioningParallelMarkedFunctionRetriever(classesToScan, FunctionTestsUtil.getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(markedFunctionRetriever); + Collection> internalClassesToScan = new HashSet<>(); + internalClassesToScan.add(SimpleClassWithMarkedMethods.class); + internalClassesToScan.add(DataTypeWithContext.class); + internalClassesToScan.add(DataTypeWithContextProcessor.class); + internalClassesToScan.add(ExtendingInterface.class); + internalClassesToScan.add(MarkedContainer.class); + internalClassesToScan.add(ContainerElement.class); + functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesToScan); - Collection> externalClasses = new HashSet<>(); - externalClasses.add(ExternalLibraryClass.class); - ParallelFunctionRetriever externalFunctionRetriever = new PartitionParallelExternalFunctionRetriever(externalClasses, FunctionTestsUtil.getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(externalFunctionRetriever); + Collection> externalClassesToScan = new HashSet<>(); + externalClassesToScan.add(ExternalLibraryClass.class); + functionRegistry.registerAllWithExternalFunctionPolicy(externalClassesToScan); } @Test diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionRetrievers.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionRetrievers.java deleted file mode 100644 index 976d8cd9fd0..00000000000 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionRetrievers.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.sap.sse.datamining.impl.function; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.concurrent.ExecutionException; - -import org.junit.Test; - -import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; -import com.sap.sse.datamining.impl.functions.FunctionRetrievalWorker; -import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionRetriever; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; -import com.sap.sse.datamining.test.util.FunctionTestsUtil; -import com.sap.sse.datamining.test.util.OpenDataReceiver; - -public class TestFunctionRetrievers { - - @Test - public void testMarkedFunctionRetrievalWorker() { - Collection> classesToScan = new ArrayList<>(); - classesToScan.add(SimpleClassWithMarkedMethods.class); - OpenDataReceiver>> receiver = new OpenDataReceiver<>(); - - FunctionRetrievalWorker worker = FunctionRetrievalWorker.Util.createMarkedFunctionRetrievalWorker(classesToScan, receiver); - - Collection> expectedFunctions = FunctionTestsUtil.getMarkedMethodsOfSimpleClassWithMarkedMethod(); - worker.run(); - assertThat(receiver.result, is(expectedFunctions)); - } - - @Test - public void testExternalFunctionRetrievalWorker() { - Collection> classesToScan = new ArrayList<>(); - classesToScan.add(ExternalLibraryClass.class); - OpenDataReceiver>> receiver = new OpenDataReceiver<>(); - - FunctionRetrievalWorker worker = FunctionRetrievalWorker.Util.createExternalFunctionRetrievalWorker(classesToScan, receiver); - - Collection> expectedFunctions = FunctionTestsUtil.getMethodsOfExternalLibraryClass(); - worker.run(); - assertThat(receiver.result, is(expectedFunctions)); - } - - @Test - public void testFunctionRetrievalWithManyClassesToScan() { - Collection> classesToScan = getManyClassesToScan(); - classesToScan.add(SimpleClassWithMarkedMethods.class); - assertThat("Not enough classes to scan for this test.", classesToScan.size() >= getMaximumWorkerAmount(), is(true)); - - ParallelFunctionRetriever functionRetriever = new PartitioningParallelMarkedFunctionRetriever(classesToScan , FunctionTestsUtil.getExecutor()); - - Collection> expectedFunctions = FunctionTestsUtil.getMarkedMethodsOfSimpleClassWithMarkedMethod(); - try { - Collection> retrievedFunctions = new HashSet<>(functionRetriever.start(null).get()); - assertThat(retrievedFunctions, is(expectedFunctions)); - } catch (InterruptedException | ExecutionException e) { - fail("Error during the function retrieving"); - } - } - - private int getMaximumWorkerAmount() { - return (int) (FunctionTestsUtil.getExecutor().getCorePoolSize() * 0.5); - } - - private Collection> getManyClassesToScan() { - Collection> classesToScan = new ArrayList<>(); - classesToScan.add(Math.class); - classesToScan.add(Integer.class); - classesToScan.add(String.class); - classesToScan.add(Double.class); - classesToScan.add(Long.class); - classesToScan.add(Float.class); - classesToScan.add(ExternalLibraryClass.class); - return classesToScan; - } - -} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java index bece3ce3d32..2607ce2715d 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java @@ -11,14 +11,12 @@ import org.junit.Test; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitionParallelExternalFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionRetriever; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextProcessor; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; public class TestSimpleFunctionRegistryAccess { @@ -27,19 +25,17 @@ public class TestSimpleFunctionRegistryAccess { @Before public void initializeTheFunctionRegistry() { - functionRegistry = new SimpleFunctionRegistry(); + functionRegistry = new SimpleFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); - Collection> classesToScan = new HashSet<>(); - classesToScan.add(SimpleClassWithMarkedMethods.class); - classesToScan.add(DataTypeWithContext.class); - classesToScan.add(DataTypeWithContextProcessor.class); - ParallelFunctionRetriever markedFunctionRetriever = new PartitioningParallelMarkedFunctionRetriever(classesToScan, FunctionTestsUtil.getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(markedFunctionRetriever); + Collection> internalClassesToScan = new HashSet<>(); + internalClassesToScan.add(SimpleClassWithMarkedMethods.class); + internalClassesToScan.add(DataTypeWithContext.class); + internalClassesToScan.add(DataTypeWithContextProcessor.class); + functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesToScan); - Collection> externalClasses = new HashSet<>(); - externalClasses.add(ExternalLibraryClass.class); - ParallelFunctionRetriever externalFunctionRetriever = new PartitionParallelExternalFunctionRetriever(externalClasses, FunctionTestsUtil.getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(externalFunctionRetriever); + Collection> externalClassesToScan = new HashSet<>(); + externalClassesToScan.add(ExternalLibraryClass.class); + functionRegistry.registerAllWithExternalFunctionPolicy(externalClassesToScan); } @Test diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java index 50b2fcd3340..93af22a13c5 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java @@ -13,12 +13,10 @@ import org.junit.Test; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitionParallelExternalFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionRetriever; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; public class TestSimpleFunctionRegistryRegistrations { @@ -27,7 +25,7 @@ public class TestSimpleFunctionRegistryRegistrations { public void testSimpleRegistration() { Method dimension = FunctionTestsUtil.getMethodFromSimpleClassWithMarkedMethod("dimension"); - FunctionRegistry registry = new SimpleFunctionRegistry(); + FunctionRegistry registry = new SimpleFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); registry.register(dimension); Set> expectedRegisteredFunctionsAsSet = new HashSet<>(); @@ -39,8 +37,8 @@ public class TestSimpleFunctionRegistryRegistrations { @Test public void testRegistrationByFunctionRetrievers() { - FunctionRegistry registry = new SimpleFunctionRegistry(); - registerMethodsOfTestClassesViaFunctionRetrieversTo(registry); + FunctionRegistry registry = new SimpleFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); + registerMethodsOfTestClasses(registry); Set> expectedRegisteredFunctionsAsSet = new HashSet<>(); expectedRegisteredFunctionsAsSet.addAll(FunctionTestsUtil.getMarkedMethodsOfSimpleClassWithMarkedMethod()); @@ -49,23 +47,21 @@ public class TestSimpleFunctionRegistryRegistrations { assertThat(registry.getAllFunctions(), is(expectedRegisteredFunctions)); } - private void registerMethodsOfTestClassesViaFunctionRetrieversTo(FunctionRegistry registry) { - Collection> classesToScan = new HashSet<>(); - classesToScan.add(SimpleClassWithMarkedMethods.class); - ParallelFunctionRetriever markedFunctionRetriever = new PartitioningParallelMarkedFunctionRetriever(classesToScan, FunctionTestsUtil.getExecutor()); - registry.registerFunctionsRetrievedBy(markedFunctionRetriever); + private void registerMethodsOfTestClasses(FunctionRegistry registry) { + Collection> internalClassesToScan = new HashSet<>(); + internalClassesToScan.add(SimpleClassWithMarkedMethods.class); + registry.registerAllWithInternalFunctionPolicy(internalClassesToScan); - Collection> externalClasses = new HashSet<>(); - externalClasses.add(ExternalLibraryClass.class); - ParallelFunctionRetriever externalFunctionRetriever = new PartitionParallelExternalFunctionRetriever(externalClasses, FunctionTestsUtil.getExecutor()); - registry.registerFunctionsRetrievedBy(externalFunctionRetriever); + Collection> externalClassesToScan = new HashSet<>(); + externalClassesToScan.add(ExternalLibraryClass.class); + registry.registerAllWithExternalFunctionPolicy(externalClassesToScan); } @Test public void testTheMultipleRegistrationOfTheSameFunction() { Method dimension = FunctionTestsUtil.getMethodFromSimpleClassWithMarkedMethod("dimension"); - FunctionRegistry registry = new SimpleFunctionRegistry(); + FunctionRegistry registry = new SimpleFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); registry.register(dimension); registry.register(dimension); registry.register(dimension); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java index 5cce1e875d4..35f46138657 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java @@ -7,8 +7,9 @@ public interface FunctionRegistry { public void register(Method method); public void register(Function function); - public void registerFunctionsRetrievedBy(ParallelFunctionRetriever functionRetriever); public void registerAll(Iterable> functions); + public void registerAllWithInternalFunctionPolicy(Collection> classesToScan); + public void registerAllWithExternalFunctionPolicy(Collection> externalClassesToScan); public Collection> getAllFunctions(); public Iterable> getFunctionsOf(Class declaringClass); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ParallelFunctionRetriever.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ParallelFunctionRetriever.java deleted file mode 100644 index 5ac44d0de81..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/ParallelFunctionRetriever.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.sap.sse.datamining.functions; - -import com.sap.sse.datamining.components.ParallelDataRetriever; - -public interface ParallelFunctionRetriever extends ParallelDataRetriever> { - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java index 2aa18d54d57..1244de8cec0 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java @@ -19,10 +19,7 @@ import com.sap.sse.datamining.DataMiningServer; import com.sap.sse.datamining.functions.ClassesWithFunctionsService; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; import com.sap.sse.datamining.i18n.DataMiningStringMessages; -import com.sap.sse.datamining.impl.functions.PartitionParallelExternalFunctionRetriever; -import com.sap.sse.datamining.impl.functions.PartitioningParallelMarkedFunctionRetriever; import com.sap.sse.datamining.impl.functions.RegistryFunctionsProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; @@ -32,7 +29,7 @@ public class DataMiningActivator implements BundleActivator { private static final int THREAD_POOL_SIZE = Math.max(Runtime.getRuntime().availableProcessors(), 3); private static BundleContext context; - private static Collection> serviceReferences; + private static Collection> serviceReferences; private static DataMiningServer dataMiningServer; private static DataMiningStringMessages stringMessages; @@ -42,7 +39,6 @@ public class DataMiningActivator implements BundleActivator { public void start(BundleContext context) throws Exception { DataMiningActivator.context = context; serviceReferences = getAllClassesWithMarkedMethodsServices(); - stringMessages = DataMiningStringMessages.Util.getDefaultStringMessages(); executor = new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue()); @@ -59,7 +55,7 @@ public class DataMiningActivator implements BundleActivator { } private FunctionRegistry createAndBuildFunctionRegistry() { - FunctionRegistry functionRegistry = new SimpleFunctionRegistry(); + FunctionRegistry functionRegistry = new SimpleFunctionRegistry(getExecutor()); Set> internalClassesWithMarkedMethods = new HashSet<>(); Set> externalLibraryClasses = new HashSet<>(); @@ -77,7 +73,8 @@ public class DataMiningActivator implements BundleActivator { } } - registerFunctions(internalClassesWithMarkedMethods, externalLibraryClasses, functionRegistry); + functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesWithMarkedMethods); + functionRegistry.registerAllWithExternalFunctionPolicy(externalLibraryClasses); return functionRegistry; } @@ -110,17 +107,6 @@ public class DataMiningActivator implements BundleActivator { return specificServiceReferences; } - private void registerFunctions(Set> internalClassesWithMarkedMethods, - Set> externalLibraryClasses, FunctionRegistry functionRegistry) { - ParallelFunctionRetriever internalMarkedFunctionsRetriever = new PartitioningParallelMarkedFunctionRetriever( - internalClassesWithMarkedMethods, getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(internalMarkedFunctionsRetriever); - - ParallelFunctionRetriever externalLibraryFunctionsRetriever = new PartitionParallelExternalFunctionRetriever( - externalLibraryClasses, getExecutor()); - functionRegistry.registerFunctionsRetrievedBy(externalLibraryFunctionsRetriever); - } - @Override public void stop(BundleContext context) throws Exception { for (ServiceReference serviceReference : serviceReferences) { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/AbstractPartitioningParallelFunctionRetriever.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/AbstractPartitioningParallelFunctionRetriever.java deleted file mode 100644 index 84a930c9181..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/AbstractPartitioningParallelFunctionRetriever.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.sap.sse.datamining.impl.functions; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ThreadPoolExecutor; - -import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; -import com.sap.sse.datamining.impl.components.deprecated.AbstractParallelComponent; -import com.sap.sse.datamining.workers.ComponentWorker; - -public abstract class AbstractPartitioningParallelFunctionRetriever - extends AbstractParallelComponent>> - implements ParallelFunctionRetriever { - - private List> classesToScan; - - public AbstractPartitioningParallelFunctionRetriever(Collection> classesToScan, ThreadPoolExecutor executor) { - super(executor); - this.classesToScan = new ArrayList<>(classesToScan); - } - - @Override - protected void setUpWorkersFor(Void data) { - final int workerAmount = calculateMaximumAmountOfWorkers(); - if (workerAmount >= classesToScan.size()) { - simpleWorkerSetUp(); - } else { - final int partitionSize = calculatePartitionSize(workerAmount); - partitioningWorkerSetUp(partitionSize); - } - } - - public int calculatePartitionSize(final int workerAmount) { - return (int) Math.ceil((double) classesToScan.size() / workerAmount); - } - - public int calculateMaximumAmountOfWorkers() { - return (int) (getExecutor().getCorePoolSize() * 0.5); - } - - private void simpleWorkerSetUp() { - for (Class classToScan : classesToScan) { - addWorker(createWorker(classToScan)); - } - } - - private ComponentWorker>> createWorker(Class classToScan) { - Collection> classToScanAsCollection = new HashSet<>(); - classToScanAsCollection.add(classToScan); - return createWorker(classToScanAsCollection); - } - - private void partitioningWorkerSetUp(int partitionSize) { - for (int i = 0; i < classesToScan.size(); i += partitionSize) { - List> partition = classesToScan.subList(i, i + Math.min(partitionSize, classesToScan.size() - i)); - addWorker(createWorker(partition)); - } - } - - protected abstract FunctionRetrievalWorker createWorker(Iterable> classesToScan); - - @Override - protected Collection> finalizeData() { - Collection> data = new HashSet<>(); - for (Collection> results : getResults()) { - data.addAll(results); - } - return Collections.unmodifiableCollection(new CopyOnWriteArrayList>(data)); - } - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java deleted file mode 100644 index c1fe2df5bbc..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalWorker.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.sap.sse.datamining.impl.functions; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashSet; - -import com.sap.sse.datamining.components.FilterCriteria; -import com.sap.sse.datamining.factories.FunctionFactory; -import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.impl.workers.AbstractComponentWorker; - -public class FilteringFunctionRetrievalWorker extends AbstractComponentWorker>> implements - FunctionRetrievalWorker { - - private Iterable> classesToScan; - private FilterCriteria filter; - - @Override - protected Collection> doWork() { - Collection> functions = new HashSet<>(); - for (Class classToScan : classesToScan) { - functions.addAll(getFilteredMethodsFrom(classToScan)); - } - return functions; - } - - private Collection> getFilteredMethodsFrom(Class classToScan) { - Collection> functions = new HashSet<>(); - for (Method method : classToScan.getMethods()) { - if (filter != null && filter.matches(method)) { - functions.add(FunctionFactory.createMethodWrappingFunction(method)); - } - } - return functions; - } - - @Override - public void setSource(Iterable> classesToScan) { - this.classesToScan = classesToScan; - } - - public void setFilter(FilterCriteria filterCriteria) { - this.filter = filterCriteria; - } - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionRetrievalWorker.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionRetrievalWorker.java deleted file mode 100644 index cbb82d76534..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionRetrievalWorker.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.sap.sse.datamining.impl.functions; - -import java.lang.reflect.Method; -import java.util.Collection; - -import com.sap.sse.datamining.components.FilterCriteria; -import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.impl.criterias.CompoundFilterCriteria; -import com.sap.sse.datamining.impl.criterias.OrCompoundFilterCriteria; -import com.sap.sse.datamining.workers.DataRetrievalWorker; -import com.sap.sse.datamining.workers.WorkReceiver; - -public interface FunctionRetrievalWorker extends DataRetrievalWorker>, Function> { - - public static final class Util { - - public static FunctionRetrievalWorker createMarkedFunctionRetrievalWorker(Iterable> classesToScan, WorkReceiver>> receiver) { - FilteringFunctionRetrievalWorker worker = new FilteringFunctionRetrievalWorker(); - worker.setSource(classesToScan); - worker.setReceiver(receiver); - - CompoundFilterCriteria filterCriteria = new OrCompoundFilterCriteria<>(); - filterCriteria.addCriteria(new MethodIsCorrectDimensionFilterCriteria()); - filterCriteria.addCriteria(new MethodIsCorrectSideEffectFreeValueFilterCriteria()); - worker.setFilter(filterCriteria); - - return worker; - } - - public static FunctionRetrievalWorker createExternalFunctionRetrievalWorker(Iterable> classesToScan, WorkReceiver>> receiver) { - FilteringFunctionRetrievalWorker worker = new FilteringFunctionRetrievalWorker(); - worker.setSource(classesToScan); - worker.setReceiver(receiver); - - FilterCriteria filterCriteria = new MethodIsCorrectExternalFunctionFilterCriteria(); - worker.setFilter(filterCriteria); - - return worker; - } - - } - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitionParallelExternalFunctionRetriever.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitionParallelExternalFunctionRetriever.java deleted file mode 100644 index 33ff624a669..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitionParallelExternalFunctionRetriever.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sap.sse.datamining.impl.functions; - -import java.util.Collection; -import java.util.concurrent.ThreadPoolExecutor; - -public class PartitionParallelExternalFunctionRetriever extends AbstractPartitioningParallelFunctionRetriever { - - public PartitionParallelExternalFunctionRetriever(Collection> externalClasses, ThreadPoolExecutor executor) { - super(externalClasses, executor); - } - - @Override - protected FunctionRetrievalWorker createWorker(Iterable> classesToScan) { - return FunctionRetrievalWorker.Util.createExternalFunctionRetrievalWorker(classesToScan, this); - } - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitioningParallelMarkedFunctionRetriever.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitioningParallelMarkedFunctionRetriever.java deleted file mode 100644 index 5fe3965d9af..00000000000 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/PartitioningParallelMarkedFunctionRetriever.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.sap.sse.datamining.impl.functions; - -import java.util.Collection; -import java.util.concurrent.ThreadPoolExecutor; - -public class PartitioningParallelMarkedFunctionRetriever extends AbstractPartitioningParallelFunctionRetriever { - - public PartitioningParallelMarkedFunctionRetriever(Collection> classesToScan, ThreadPoolExecutor executor) { - super(classesToScan, executor); - } - - @Override - protected FunctionRetrievalWorker createWorker(Iterable> classesToScan) { - return FunctionRetrievalWorker.Util.createMarkedFunctionRetrievalWorker(classesToScan, this); - } - -} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index e1b6e34ad91..25c57d574cf 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -1,39 +1,62 @@ package com.sap.sse.datamining.impl.functions; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; +import com.sap.sse.datamining.AdditionalResultDataBuilder; +import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.functions.ParallelFunctionRetriever; +import com.sap.sse.datamining.functions.FunctionRetrievalProcessor; public class SimpleFunctionRegistry implements FunctionRegistry { private static final Logger LOGGER = Logger.getLogger(SimpleFunctionRegistry.class.getName()); + + private final ExecutorService executor; + private final Processor>> functionsReceiver; private final Map, Collection>> functionsMappedByDeclaringClass; private final Map, Collection>> dimensionsMappedByDeclaringClass; - public SimpleFunctionRegistry() { + public SimpleFunctionRegistry(ExecutorService executor) { + this.executor = executor; + functionsReceiver = new FunctionsReceiver(); + functionsMappedByDeclaringClass = new HashMap<>(); dimensionsMappedByDeclaringClass = new HashMap<>(); } @Override - public void registerFunctionsRetrievedBy(ParallelFunctionRetriever functionRetriever) { + public void registerAllWithInternalFunctionPolicy(Collection> internalClassesToScan) { + FunctionRetrievalProcessor internalFunctionsRetriever = new InternalFunctionRetrievalProcessor(executor, Arrays.asList(functionsReceiver)); + internalFunctionsRetriever.onElement(internalClassesToScan); try { - Collection> functions = functionRetriever.start(null).get(); - registerAll(functions); - } catch (InterruptedException | ExecutionException exception) { - LOGGER.log(Level.SEVERE, "Error during the function retrieving. Data-Mining may not work.", exception); + internalFunctionsRetriever.finish(); + } catch (InterruptedException exception) { + LOGGER.log(Level.SEVERE, "The functions retrieval got interrupted. Data-Mining won't work!", exception); + } + } + + @Override + public void registerAllWithExternalFunctionPolicy(Collection> externalClassesToScan) { + FunctionRetrievalProcessor externalFunctionsRetriever = new ExternalFunctionRetrievalProcessor(executor, Arrays.asList(functionsReceiver)); + externalFunctionsRetriever.onElement(externalClassesToScan); + try { + externalFunctionsRetriever.finish(); + } catch (InterruptedException exception) { + LOGGER.log(Level.SEVERE, "The functions retrieval got interrupted. Data-Mining won't work!", exception); } } @@ -100,5 +123,38 @@ public class SimpleFunctionRegistry implements FunctionRegistry { } return registeredMethods; } + + private class FunctionsReceiver implements Processor>> { + + private final Lock functionsRegistrationLock; + + public FunctionsReceiver() { + functionsRegistrationLock = new ReentrantLock(); + } + + @Override + public void onElement(Collection> element) { + functionsRegistrationLock.lock(); + try { + SimpleFunctionRegistry.this.registerAll(element); + } finally { + functionsRegistrationLock.unlock(); + } + } + + @Override + public void finish() throws InterruptedException { + } + + @Override + public void abort() { + } + + @Override + public AdditionalResultDataBuilder getAdditionalResultData(AdditionalResultDataBuilder additionalDataBuilder) { + return additionalDataBuilder; + } + + } } From 2a85dd66e77026bf3cf30d6c3064ff9b0e56d93f Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 28 Mar 2014 19:01:24 +0100 Subject: [PATCH 009/114] Cleaned and adjusted the FunctionProviders to the new concept --- ...tDeclaringTypeOrParameterTypeCriteria.java | 4 +- .../impl/function/TestFunctionProvider.java | 26 ++--- .../TestSimpleFunctionRegistryAccess.java | 6 +- .../DataTypeWithContextProcessor.java | 12 -- .../test/util/FunctionTestsUtil.java | 2 - .../functions/FunctionProvider.java | 4 +- .../functions/FunctionRegistry.java | 4 +- .../datamining/impl/DataMiningActivator.java | 2 +- .../AbstractSimpleParallelProcessor.java | 4 +- ... => FunctionMatchesDTOFilterCriteria.java} | 4 +- ...ava => IsDeclaringTypeFilterCriteria.java} | 16 +-- .../functions/RegistryFunctionsProvider.java | 106 ++++++++++++------ .../functions/SimpleFunctionRegistry.java | 22 ++-- 13 files changed, 107 insertions(+), 105 deletions(-) delete mode 100644 java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextProcessor.java rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{FunctionDTOFilterCriteria.java => FunctionMatchesDTOFilterCriteria.java} (78%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{DeclaringTypeOrParameterTypeCriteria.java => IsDeclaringTypeFilterCriteria.java} (77%) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java index 96c30fbe048..832c9a25af0 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java @@ -9,7 +9,7 @@ import org.junit.Test; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.impl.functions.DeclaringTypeOrParameterTypeCriteria; +import com.sap.sse.datamining.impl.functions.IsDeclaringTypeFilterCriteria; import com.sap.sse.datamining.test.function.test_classes.DataTypeInterface; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; @@ -36,7 +36,7 @@ public class TestDeclaringTypeOrParameterTypeCriteria { @Test public void testMatchingTypeWithBigHierarchy() { - FilterCriteria> criteria = new DeclaringTypeOrParameterTypeCriteria(DataTypeWithContextImpl.class); + FilterCriteria> criteria = new IsDeclaringTypeFilterCriteria(DataTypeWithContextImpl.class); assertThat(criteria.matches(getSpeedInKnotsValue), is(true)); assertThat(criteria.matches(getRaceNameLengthValue), is(true)); diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java index 3d242765b72..b9889e472a4 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java @@ -24,7 +24,6 @@ import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.test.function.test_classes.ContainerElement; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextProcessor; import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; @@ -46,7 +45,6 @@ public class TestFunctionProvider { Collection> internalClassesToScan = new HashSet<>(); internalClassesToScan.add(SimpleClassWithMarkedMethods.class); internalClassesToScan.add(DataTypeWithContext.class); - internalClassesToScan.add(DataTypeWithContextProcessor.class); internalClassesToScan.add(ExtendingInterface.class); internalClassesToScan.add(MarkedContainer.class); internalClassesToScan.add(ContainerElement.class); @@ -59,10 +57,9 @@ public class TestFunctionProvider { @Test public void testGetDimensionsForType() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); Collection> expectedDimensions = FunctionTestsUtil.getDimensionsFor(DataTypeWithContext.class); - Collection> providedDimensions = new HashSet<>(functionProvider.getDimensionsFor(DataTypeWithContext.class)); assertThat(providedDimensions, is(expectedDimensions)); @@ -72,18 +69,13 @@ public class TestFunctionProvider { @Test public void testGetFunctionsForType() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); - Method getRegattaAndRaceName = FunctionTestsUtil.getMethodFromClass(DataTypeWithContextProcessor.class, "getRegattaAndRaceName", DataTypeWithContext.class); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); Collection> expectedFunctions = FunctionTestsUtil.getMarkedMethodsOfDataTypeWithContextAndItsSupertypes(); - expectedFunctions.add(FunctionFactory.createMethodWrappingFunction(getRegattaAndRaceName)); - Collection> providedFunctions = new HashSet<>(functionProvider.getFunctionsFor(DataTypeWithContext.class)); assertThat(providedFunctions, is(expectedFunctions)); expectedFunctions = FunctionTestsUtil.getMarkedMethodsOfDataTypeWithContextImplAndItsSupertypes(); - expectedFunctions.add(FunctionFactory.createMethodWrappingFunction(getRegattaAndRaceName)); - providedFunctions = new HashSet<>(functionProvider.getFunctionsFor(DataTypeWithContextImpl.class)); assertThat(providedFunctions, is(expectedFunctions)); } @@ -94,9 +86,9 @@ public class TestFunctionProvider { Function getRegattaName = FunctionFactory.createMethodWrappingFunction(getRegattaNameMethod); FunctionDTO getRegattaNameDTO = FunctionDTOFactory.createFunctionDTO(getRegattaName, Locale.ENGLISH, stringMessages); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); @SuppressWarnings("unchecked") // Hamcrest requires type matching of actual and expected type, so the Functions have to be specific (without ) - Function providedFunction = (Function) functionProvider.getFunctionFor(getRegattaNameDTO); + Function providedFunction = (Function) functionProvider.getFunctionForDTO(getRegattaNameDTO); assertThat(providedFunction, is(getRegattaName)); } @@ -106,19 +98,19 @@ public class TestFunctionProvider { Function increment = FunctionFactory.createMethodWrappingFunction(incrementMethod); FunctionDTO incrementDTO = FunctionDTOFactory.createFunctionDTO(increment, Locale.ENGLISH, stringMessages); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); - assertThat(functionProvider.getFunctionFor(incrementDTO), is(nullValue())); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + assertThat(functionProvider.getFunctionForDTO(incrementDTO), is(nullValue())); } @Test public void testGetFunctionForNullDTO() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); - assertThat(functionProvider.getFunctionFor(null), is(nullValue())); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + assertThat(functionProvider.getFunctionForDTO(null), is(nullValue())); } @Test public void testGetTransitiveDimension() throws ClassCastException, NoSuchMethodException, SecurityException { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, FunctionTestsUtil.getExecutor()); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); Collection> expectedDimensions = new HashSet<>(); expectedDimensions.add(FunctionFactory.createMethodWrappingFunction(ContainerElement.class.getMethod("getName", diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java index 2607ce2715d..155816aae7c 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java @@ -13,7 +13,6 @@ import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextProcessor; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; @@ -30,7 +29,6 @@ public class TestSimpleFunctionRegistryAccess { Collection> internalClassesToScan = new HashSet<>(); internalClassesToScan.add(SimpleClassWithMarkedMethods.class); internalClassesToScan.add(DataTypeWithContext.class); - internalClassesToScan.add(DataTypeWithContextProcessor.class); functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesToScan); Collection> externalClassesToScan = new HashSet<>(); @@ -42,8 +40,8 @@ public class TestSimpleFunctionRegistryAccess { public void testGetAllDimensions() { Collection> modifiableExpectedDimensions = FunctionTestsUtil.getDimensionsFor(DataTypeWithContext.class); modifiableExpectedDimensions.addAll(FunctionTestsUtil.getDimensionsFor(SimpleClassWithMarkedMethods.class)); - Iterable> expectedDimensions = modifiableExpectedDimensions; - assertThat(functionRegistry.getAllDimensions(), is(expectedDimensions)); + Collection> expectedDimensions = modifiableExpectedDimensions; + assertThat(functionRegistry.getAllDimensions(), is(expectedDimensions)); } } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextProcessor.java deleted file mode 100644 index f8fdd19999d..00000000000 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextProcessor.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.sap.sse.datamining.test.function.test_classes; - -import com.sap.sse.datamining.shared.annotations.Dimension; - -public class DataTypeWithContextProcessor { - - @Dimension(messageKey="regattaAndRaceName") - public String getRegattaAndRaceName(DataTypeWithContext dataEntry) { - return dataEntry.getRegattaName() + " - " + dataEntry.getRaceName(); - } - -} diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java index 41fc7c9cfad..be07a232021 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java @@ -12,7 +12,6 @@ import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.test.function.test_classes.DataTypeInterface; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextProcessor; import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; @@ -90,7 +89,6 @@ public class FunctionTestsUtil extends ConcurrencyTestsUtil { dimensions.add(FunctionFactory.createMethodWrappingFunction(getMethodFromClass(DataTypeWithContext.class, "getRegattaName"))); dimensions.add(FunctionFactory.createMethodWrappingFunction(getMethodFromClass(DataTypeWithContext.class, "getRaceName"))); dimensions.add(FunctionFactory.createMethodWrappingFunction(getMethodFromClass(DataTypeWithContext.class, "getLegNumber"))); - dimensions.add(FunctionFactory.createMethodWrappingFunction(getMethodFromClass(DataTypeWithContextProcessor.class, "getRegattaAndRaceName", DataTypeWithContext.class))); return dimensions; } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java index 39439799d60..805b2867863 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionProvider.java @@ -6,7 +6,7 @@ import com.sap.sse.datamining.shared.dto.FunctionDTO; public interface FunctionProvider { - public Collection> getDimensionsFor(Class dataType); + public Collection> getDimensionsFor(Class sourceType); /** * Collects all dimensions for the given data type, where transitive dimensions will also be @@ -25,6 +25,6 @@ public interface FunctionProvider { /** * @return The first function, that matches the given DTO or null */ - public Function getFunctionFor(FunctionDTO functionDTO); + public Function getFunctionForDTO(FunctionDTO functionDTO); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java index 35f46138657..ca915ba56ce 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/functions/FunctionRegistry.java @@ -12,8 +12,8 @@ public interface FunctionRegistry { public void registerAllWithExternalFunctionPolicy(Collection> externalClassesToScan); public Collection> getAllFunctions(); - public Iterable> getFunctionsOf(Class declaringClass); + public Collection> getFunctionsOf(Class declaringClass); public Collection> getAllDimensions(); - public Iterable> getDimensionsOf(Class declaringClass); + public Collection> getDimensionsOf(Class declaringClass); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java index 1244de8cec0..5f3cbb51c21 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java @@ -44,7 +44,7 @@ public class DataMiningActivator implements BundleActivator { new LinkedBlockingQueue()); FunctionRegistry functionRegistry = createAndBuildFunctionRegistry(); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry, getExecutor()); + FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); dataMiningServer = new DataMiningServerImpl(functionRegistry, functionProvider); registerDataMiningServer(); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleParallelProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleParallelProcessor.java index d8d6e443863..2a85e549a0f 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleParallelProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleParallelProcessor.java @@ -1,7 +1,7 @@ package com.sap.sse.datamining.impl.components; +import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; @@ -16,7 +16,7 @@ public abstract class AbstractSimpleParallelProcessor @Override protected Iterable partitionElement(InputType element) { - return Collections.singleton(element); + return Arrays.asList(element); } //Redefinition of the method to set the parameter name to element instead of partial element. diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java similarity index 78% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java index c8f6e28f053..c39d7de5729 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionDTOFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java @@ -5,11 +5,11 @@ import com.sap.sse.datamining.factories.FunctionDTOFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.shared.dto.FunctionDTO; -public class FunctionDTOFilterCriteria implements FilterCriteria> { +public class FunctionMatchesDTOFilterCriteria implements FilterCriteria> { private FunctionDTO functionDTOToMatch; - public FunctionDTOFilterCriteria(FunctionDTO functionDTOToMatch) { + public FunctionMatchesDTOFilterCriteria(FunctionDTO functionDTOToMatch) { this.functionDTOToMatch = functionDTOToMatch; } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java similarity index 77% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java index cfb6fa2aadf..7504eef90ef 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/DeclaringTypeOrParameterTypeCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java @@ -7,11 +7,11 @@ import java.util.HashSet; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.functions.Function; -public class DeclaringTypeOrParameterTypeCriteria implements FilterCriteria> { +public class IsDeclaringTypeFilterCriteria implements FilterCriteria> { private final Collection> expectingTypes; - public DeclaringTypeOrParameterTypeCriteria(Class expectingType) { + public IsDeclaringTypeFilterCriteria(Class expectingType) { this.expectingTypes = getSupertypesOf(expectingType); this.expectingTypes.add(expectingType); } @@ -47,17 +47,7 @@ public class DeclaringTypeOrParameterTypeCriteria implements FilterCriteria function) { for (Class expectingType : expectingTypes) { - if (isDeclaringTypeMatching(function, expectingType) || - isAParameterTypeMatching(function, expectingType)) { - return true; - } - } - return false; - } - - private boolean isAParameterTypeMatching(Function function, Class expectingType) { - for (Class parameterType : function.getParameters()) { - if (parameterType.equals(expectingType)) { + if (isDeclaringTypeMatching(function, expectingType)) { return true; } } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java index 759729e914b..aec5b2ec773 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java @@ -1,38 +1,25 @@ package com.sap.sse.datamining.impl.functions; +import java.util.Arrays; import java.util.Collection; import java.util.HashSet; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ThreadPoolExecutor; import java.util.logging.Level; import java.util.logging.Logger; import com.sap.sse.datamining.components.FilterCriteria; -import com.sap.sse.datamining.components.ParallelFilter; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; -import com.sap.sse.datamining.impl.components.deprecated.PartitioningParallelFilter; -import com.sap.sse.datamining.impl.workers.builders.FilterByCriteriaBuilder; import com.sap.sse.datamining.shared.dto.FunctionDTO; -import com.sap.sse.datamining.workers.FiltrationWorker; -import com.sap.sse.datamining.workers.WorkerBuilder; public class RegistryFunctionsProvider implements FunctionProvider { private static final Logger LOGGER = Logger.getLogger(RegistryFunctionsProvider.class.getName()); private FunctionRegistry functionRegistry; - private ThreadPoolExecutor executor; - public RegistryFunctionsProvider(FunctionRegistry functionRegistry, ThreadPoolExecutor executor) { + public RegistryFunctionsProvider(FunctionRegistry functionRegistry) { this.functionRegistry = functionRegistry; - this.executor = executor; - } - - @Override - public Collection> getDimensionsFor(Class dataType) { - return filterForDeclaringType(functionRegistry.getAllDimensions(), dataType); } @Override @@ -62,45 +49,81 @@ public class RegistryFunctionsProvider implements FunctionProvider { return returnTypes; } + @Override + public Collection> getDimensionsFor(Class sourceType) { + Collection> typesToRetrieve = getSupertypesOf(sourceType); + typesToRetrieve.add(sourceType); + return getDimensionsFor(typesToRetrieve); + } + + private Collection> getDimensionsFor(Collection> typesToRetrieve) { + Collection> dimensions = new HashSet<>(); + for (Class typeToRetrieve : typesToRetrieve) { + dimensions.addAll(functionRegistry.getDimensionsOf(typeToRetrieve)); + } + return dimensions; + } + @Override public Collection> getFunctionsFor(Class sourceType) { - return filterForDeclaringType(functionRegistry.getAllFunctions(), sourceType); + Collection> typesToRetrieve = getSupertypesOf(sourceType); + typesToRetrieve.add(sourceType); + return getFunctionsFor(typesToRetrieve); } - private Collection> filterForDeclaringType(Collection> functions, Class sourceType) { - FilterCriteria> declaringTypeFilterCriteria = new DeclaringTypeOrParameterTypeCriteria(sourceType); - ParallelFilter> functionsForDeclaringTypeFilter = createFilterForCriteria(declaringTypeFilterCriteria); - - return executeFilter(functionsForDeclaringTypeFilter, functions); + private Collection> getFunctionsFor(Collection> typesToRetrieve) { + Collection> dimensions = new HashSet<>(); + for (Class typeToRetrieve : typesToRetrieve) { + dimensions.addAll(functionRegistry.getFunctionsOf(typeToRetrieve)); + } + return dimensions; } - private Collection> executeFilter(ParallelFilter> functionFilter, Collection> functionsToFilter) { - Collection> filteredFunctions = new HashSet<>(); + private Collection> getSupertypesOf(Class type) { + Collection> supertypes = new HashSet<>(); - try { - filteredFunctions = functionFilter.start(functionsToFilter).get(); - } catch (InterruptedException | ExecutionException exception) { - LOGGER.log(Level.SEVERE, "Error filtering the functions", exception); + supertypes.addAll(getInterfacesOf(type)); + if (isSuperclassValid(type)) { + supertypes.add(type.getSuperclass()); } - return filteredFunctions; + supertypes.addAll(getSupertypesOf(supertypes)); + return supertypes; } - private ParallelFilter> createFilterForCriteria(FilterCriteria> filterCriteria) { - WorkerBuilder>> workerBuilder = new FilterByCriteriaBuilder>(filterCriteria); - return new PartitioningParallelFilter<>(workerBuilder, executor); + private Collection> getInterfacesOf(Class type) { + return Arrays.asList(type.getInterfaces()); + } + + private boolean isSuperclassValid(Class subType) { + return subType.getSuperclass() != null && !subType.getSuperclass().equals(Object.class); + } + + private Collection> getSupertypesOf(Collection> types) { + Collection> supertypes = new HashSet<>(); + boolean supertypeAdded; + do { + Collection> supertypesToAdd = getSupertypesToAdd(types); + supertypeAdded = supertypes.addAll(supertypesToAdd); + } while (supertypeAdded); + return supertypes; + } + + private Collection> getSupertypesToAdd(Collection> types) { + Collection> supertypesToAdd = new HashSet<>(); + for (Class supertype : types) { + supertypesToAdd.addAll(getSupertypesOf(supertype)); + } + return supertypesToAdd; } @Override - public Function getFunctionFor(FunctionDTO functionDTO) { + public Function getFunctionForDTO(FunctionDTO functionDTO) { if (functionDTO == null) { return null; } - FilterCriteria> functionDTOFilterCriteria = new FunctionDTOFilterCriteria(functionDTO); - ParallelFilter> functionMatchesDTOFilter = createFilterForCriteria(functionDTOFilterCriteria); - - Collection> functionsMatchingDTO = executeFilter(functionMatchesDTOFilter, functionRegistry.getAllFunctions()); + Collection> functionsMatchingDTO = getFunctionsForDTO(functionDTO); if (moreThanOneFunctionMatchedDTO(functionsMatchingDTO)) { logThatMoreThanOneFunctionMatchedDTO(functionDTO, functionsMatchingDTO); } @@ -108,6 +131,17 @@ public class RegistryFunctionsProvider implements FunctionProvider { return getFunctionToReturn(functionsMatchingDTO); } + private Collection> getFunctionsForDTO(FunctionDTO functionDTO) { + Collection> functionsMatchingDTO = new HashSet<>(); + FilterCriteria> functionDTOFilterCriteria = new FunctionMatchesDTOFilterCriteria(functionDTO); + for (Function function : functionRegistry.getAllFunctions()) { + if (functionDTOFilterCriteria.matches(function)) { + functionsMatchingDTO.add(function); + } + } + return functionsMatchingDTO; + } + private boolean moreThanOneFunctionMatchedDTO(Collection> functionsMatchingDTO) { return functionsMatchingDTO.size() > 1; } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index 25c57d574cf..c623791fa6c 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -96,25 +96,27 @@ public class SimpleFunctionRegistry implements FunctionRegistry { } } + @Override + public Collection> getFunctionsOf(Class declaringClass) { + Collection> functions = functionsMappedByDeclaringClass.get(declaringClass); + return functions != null ? functions : new HashSet>(); + } + + @Override + public Collection> getDimensionsOf(Class declaringClass) { + Collection> dimensions = dimensionsMappedByDeclaringClass.get(declaringClass); + return dimensions != null ? dimensions : new HashSet>(); + } + @Override public Collection> getAllFunctions() { return collectAllFunctionsIn(functionsMappedByDeclaringClass); } - @Override - public Iterable> getFunctionsOf(Class declaringClass) { - return functionsMappedByDeclaringClass.get(declaringClass); - } - @Override public Collection> getAllDimensions() { return collectAllFunctionsIn(dimensionsMappedByDeclaringClass); } - - @Override - public Iterable> getDimensionsOf(Class declaringClass) { - return dimensionsMappedByDeclaringClass.get(declaringClass); - } private Collection> collectAllFunctionsIn(Map, Collection>> functionsMap) { Set> registeredMethods = new HashSet<>(); From 7ac58bda349c5f3d5a5c645ec96f2d4e6fdfb8e1 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 28 Mar 2014 19:04:33 +0100 Subject: [PATCH 010/114] Cleaned the data mining dependency to domain specific bundle --- java/com.sap.sse.datamining/META-INF/MANIFEST.MF | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/java/com.sap.sse.datamining/META-INF/MANIFEST.MF b/java/com.sap.sse.datamining/META-INF/MANIFEST.MF index 5c92692f649..9efd0c25a72 100644 --- a/java/com.sap.sse.datamining/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.datamining/META-INF/MANIFEST.MF @@ -33,6 +33,5 @@ Export-Package: com.sap.sse.datamining;uses:="com.sap.sse.datamining.functions,c com.sap.sse.datamining.impl.workers.extractors, com.sap.sse.datamining.impl.workers.retrievers, com.sap.sse.datamining.workers -Require-Bundle: com.sap.sse.datamining.shared;bundle-version="1.0.0", - com.sap.sailing.domain.common;bundle-version="1.0.0" +Require-Bundle: com.sap.sse.datamining.shared;bundle-version="1.0.0" Bundle-Activator: com.sap.sse.datamining.impl.DataMiningActivator From 5682b77b2714910a97fadbc846318b0f0ffcbafd Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sun, 30 Mar 2014 12:57:09 +0200 Subject: [PATCH 011/114] The RegistryFunctionProvider can now be used with multiple providers This will be useful, when users can create their own functions. These User-Functions will be stored in an user specific registry. --- .../impl/function/TestFunctionProvider.java | 14 ++++---- .../datamining/impl/DataMiningActivator.java | 4 +-- ...der.java => RegistryFunctionProvider.java} | 34 ++++++++++++------- 3 files changed, 31 insertions(+), 21 deletions(-) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{RegistryFunctionsProvider.java => RegistryFunctionProvider.java} (81%) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java index b9889e472a4..57adff12eb3 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java @@ -18,7 +18,7 @@ import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.i18n.DataMiningStringMessages; -import com.sap.sse.datamining.impl.functions.RegistryFunctionsProvider; +import com.sap.sse.datamining.impl.functions.RegistryFunctionProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.test.function.test_classes.ContainerElement; @@ -57,7 +57,7 @@ public class TestFunctionProvider { @Test public void testGetDimensionsForType() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); Collection> expectedDimensions = FunctionTestsUtil.getDimensionsFor(DataTypeWithContext.class); Collection> providedDimensions = new HashSet<>(functionProvider.getDimensionsFor(DataTypeWithContext.class)); @@ -69,7 +69,7 @@ public class TestFunctionProvider { @Test public void testGetFunctionsForType() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); Collection> expectedFunctions = FunctionTestsUtil.getMarkedMethodsOfDataTypeWithContextAndItsSupertypes(); Collection> providedFunctions = new HashSet<>(functionProvider.getFunctionsFor(DataTypeWithContext.class)); @@ -86,7 +86,7 @@ public class TestFunctionProvider { Function getRegattaName = FunctionFactory.createMethodWrappingFunction(getRegattaNameMethod); FunctionDTO getRegattaNameDTO = FunctionDTOFactory.createFunctionDTO(getRegattaName, Locale.ENGLISH, stringMessages); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); @SuppressWarnings("unchecked") // Hamcrest requires type matching of actual and expected type, so the Functions have to be specific (without ) Function providedFunction = (Function) functionProvider.getFunctionForDTO(getRegattaNameDTO); assertThat(providedFunction, is(getRegattaName)); @@ -98,19 +98,19 @@ public class TestFunctionProvider { Function increment = FunctionFactory.createMethodWrappingFunction(incrementMethod); FunctionDTO incrementDTO = FunctionDTOFactory.createFunctionDTO(increment, Locale.ENGLISH, stringMessages); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); assertThat(functionProvider.getFunctionForDTO(incrementDTO), is(nullValue())); } @Test public void testGetFunctionForNullDTO() { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); assertThat(functionProvider.getFunctionForDTO(null), is(nullValue())); } @Test public void testGetTransitiveDimension() throws ClassCastException, NoSuchMethodException, SecurityException { - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); Collection> expectedDimensions = new HashSet<>(); expectedDimensions.add(FunctionFactory.createMethodWrappingFunction(ContainerElement.class.getMethod("getName", diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java index 5f3cbb51c21..f28980198f4 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java @@ -20,7 +20,7 @@ import com.sap.sse.datamining.functions.ClassesWithFunctionsService; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.i18n.DataMiningStringMessages; -import com.sap.sse.datamining.impl.functions.RegistryFunctionsProvider; +import com.sap.sse.datamining.impl.functions.RegistryFunctionProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; public class DataMiningActivator implements BundleActivator { @@ -44,7 +44,7 @@ public class DataMiningActivator implements BundleActivator { new LinkedBlockingQueue()); FunctionRegistry functionRegistry = createAndBuildFunctionRegistry(); - FunctionProvider functionProvider = new RegistryFunctionsProvider(functionRegistry); + FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); dataMiningServer = new DataMiningServerImpl(functionRegistry, functionProvider); registerDataMiningServer(); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java similarity index 81% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java index aec5b2ec773..af97824487a 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionsProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java @@ -12,16 +12,20 @@ import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.shared.dto.FunctionDTO; -public class RegistryFunctionsProvider implements FunctionProvider { +public class RegistryFunctionProvider implements FunctionProvider { - private static final Logger LOGGER = Logger.getLogger(RegistryFunctionsProvider.class.getName()); + private static final Logger LOGGER = Logger.getLogger(RegistryFunctionProvider.class.getName()); - private FunctionRegistry functionRegistry; + private final Collection functionRegistries; - public RegistryFunctionsProvider(FunctionRegistry functionRegistry) { - this.functionRegistry = functionRegistry; + public RegistryFunctionProvider(FunctionRegistry... functionRegistry) { + this(Arrays.asList(functionRegistry)); } + public RegistryFunctionProvider(Collection functionRegistries) { + this.functionRegistries = new HashSet<>(functionRegistries); + } + @Override public Collection> getTransitiveDimensionsFor(Class dataType, int depth) { Collection> dimensions = new HashSet<>(); @@ -58,8 +62,10 @@ public class RegistryFunctionsProvider implements FunctionProvider { private Collection> getDimensionsFor(Collection> typesToRetrieve) { Collection> dimensions = new HashSet<>(); - for (Class typeToRetrieve : typesToRetrieve) { - dimensions.addAll(functionRegistry.getDimensionsOf(typeToRetrieve)); + for (FunctionRegistry functionRegistry : functionRegistries) { + for (Class typeToRetrieve : typesToRetrieve) { + dimensions.addAll(functionRegistry.getDimensionsOf(typeToRetrieve)); + } } return dimensions; } @@ -73,8 +79,10 @@ public class RegistryFunctionsProvider implements FunctionProvider { private Collection> getFunctionsFor(Collection> typesToRetrieve) { Collection> dimensions = new HashSet<>(); - for (Class typeToRetrieve : typesToRetrieve) { - dimensions.addAll(functionRegistry.getFunctionsOf(typeToRetrieve)); + for (FunctionRegistry functionRegistry : functionRegistries) { + for (Class typeToRetrieve : typesToRetrieve) { + dimensions.addAll(functionRegistry.getFunctionsOf(typeToRetrieve)); + } } return dimensions; } @@ -134,9 +142,11 @@ public class RegistryFunctionsProvider implements FunctionProvider { private Collection> getFunctionsForDTO(FunctionDTO functionDTO) { Collection> functionsMatchingDTO = new HashSet<>(); FilterCriteria> functionDTOFilterCriteria = new FunctionMatchesDTOFilterCriteria(functionDTO); - for (Function function : functionRegistry.getAllFunctions()) { - if (functionDTOFilterCriteria.matches(function)) { - functionsMatchingDTO.add(function); + for (FunctionRegistry functionRegistry : functionRegistries) { + for (Function function : functionRegistry.getAllFunctions()) { + if (functionDTOFilterCriteria.matches(function)) { + functionsMatchingDTO.add(function); + } } } return functionsMatchingDTO; From 62267515c462131f32248e684cd5b7323ac7ff5e Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sun, 30 Mar 2014 13:54:35 +0200 Subject: [PATCH 012/114] Added a lock for the result receiving of ProcessorQueries --- .../sap/sse/datamining/impl/ProcessorQuery.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java index 65f4d3c2b4c..2dac9b1ce5e 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java @@ -1,5 +1,6 @@ package com.sap.sse.datamining.impl; +import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Timer; @@ -7,6 +8,7 @@ import java.util.TimerTask; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -134,11 +136,22 @@ public class ProcessorQuery implements Query> { + private final ReentrantLock resultsLock; private Map results; + + public ProcessResultReceiver() { + resultsLock = new ReentrantLock(); + results = new HashMap<>(); + } @Override public void onElement(Map groupedAggregations) { - results = groupedAggregations; + resultsLock.lock(); + try { + results.putAll(groupedAggregations); + } finally { + resultsLock.unlock(); + } } @Override From 6fb6345ee93ab580745423394aa2001f28870a22 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 3 Apr 2014 17:34:55 +0200 Subject: [PATCH 013/114] Errors during the data mining are now forwarded and logged This improves the visibilities of failures, because they aren't hided by the multithreading anymore. --- .../datamining/impl/TestProcessorQuery.java | 3 +++ ...stAbstractFilteringRetrievalProcessor.java | 3 +++ ...estAbstractParallelProcessorFinishing.java | 2 ++ ...elProcessorWithManySimpleInstructions.java | 3 +++ .../components/TestAbstractProcessor.java | 3 +++ .../components/TestFilteringProcessors.java | 3 +++ .../TestParallelExtractionProcessor.java | 3 +++ ...llelMultiDimensionalGroupingProcessor.java | 2 ++ ...ctStoringParallelAggregationProcessor.java | 3 +++ ...stParallelDoubleAggregationProcessors.java | 3 +++ .../sse/datamining/components/Processor.java | 10 ++++++++ .../sse/datamining/impl/ProcessorQuery.java | 24 ++++++++++++++++++- ...AbstractPartitioningParallelProcessor.java | 9 ++++++- .../impl/components/AbstractProcessor.java | 7 ++++++ .../functions/SimpleFunctionRegistry.java | 13 ++++++++++ 15 files changed, 89 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java index 08eed173375..2d3c0451976 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java @@ -166,6 +166,9 @@ public class TestProcessorQuery { receivedElementOrFinished = true; } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { receivedElementOrFinished = true; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java index d725a4e7770..35b635ac1e3 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java @@ -57,6 +57,9 @@ public class TestAbstractFilteringRetrievalProcessor { } } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { } @Override diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorFinishing.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorFinishing.java index 4880e120dbc..3accc2294ea 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorFinishing.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorFinishing.java @@ -52,6 +52,8 @@ public class TestAbstractParallelProcessorFinishing { @Override public void onElement(Integer element) { } @Override + public void onFailure(Throwable failure) { } + @Override public void finish() throws InterruptedException { receiverWasToldToFinish = true; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorWithManySimpleInstructions.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorWithManySimpleInstructions.java index d1119adfaf5..67772320968 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorWithManySimpleInstructions.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractParallelProcessorWithManySimpleInstructions.java @@ -29,6 +29,9 @@ public class TestAbstractParallelProcessorWithManySimpleInstructions { incrementSum(element); } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { receiverWasToldToFinish = true; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractProcessor.java index 5d75ec01103..35cdb442fb9 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractProcessor.java @@ -24,6 +24,9 @@ public class TestAbstractProcessor { public void onElement(Integer element) { } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { receiverWasToldToFinish = true; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java index 83d839f68f2..05c52e65707 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java @@ -97,6 +97,9 @@ public class TestFilteringProcessors { receivedElements.put(element, elementAmount); } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { } @Override diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelExtractionProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelExtractionProcessor.java index ecaa1f4b73d..bca33a9eecf 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelExtractionProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelExtractionProcessor.java @@ -45,6 +45,9 @@ public class TestParallelExtractionProcessor { receivedValues.put(element.getKey(), element.getDataEntry()); } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { } @Override diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelMultiDimensionalGroupingProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelMultiDimensionalGroupingProcessor.java index 14090d8f29a..c7b322e89d1 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelMultiDimensionalGroupingProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestParallelMultiDimensionalGroupingProcessor.java @@ -37,6 +37,8 @@ public class TestParallelMultiDimensionalGroupingProcessor { groupedElement = element; } @Override + public void onFailure(Throwable failure) { } + @Override public void finish() throws InterruptedException { } @Override public void abort() { } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestAbstractStoringParallelAggregationProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestAbstractStoringParallelAggregationProcessor.java index 5f32b1ab7c0..15a12580009 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestAbstractStoringParallelAggregationProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestAbstractStoringParallelAggregationProcessor.java @@ -31,6 +31,9 @@ public class TestAbstractStoringParallelAggregationProcessor { receivedElement = element; } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { receiverWasToldToFinish = true; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestParallelDoubleAggregationProcessors.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestParallelDoubleAggregationProcessors.java index 3bd8c4c4289..3b5886d25f3 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestParallelDoubleAggregationProcessors.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/aggregators/TestParallelDoubleAggregationProcessors.java @@ -184,6 +184,9 @@ public class TestParallelDoubleAggregationProcessors { receivedAggregations = element; } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { } @Override diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/Processor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/Processor.java index ea41e69ecbd..8fec8591888 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/Processor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/Processor.java @@ -6,6 +6,16 @@ public interface Processor { public void onElement(InputType element); + /** + * This method handles the throwing of Throwables, so they don't get lost because of the + * multi-threading.
+ * The standard implementation would be a forwarding to the last processor, + * that collects the failures, until the processing is finished. Than the failures will be + * handled. + * @param failure + */ + void onFailure(Throwable failure); + /** * Tells this Processor, that there will be no incoming data.
* The called Processor will finish his work and call finish() on all subsequent processors. diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java index 2dac9b1ce5e..11df025ae51 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java @@ -1,6 +1,8 @@ package com.sap.sse.datamining.impl; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Timer; @@ -93,6 +95,8 @@ public class ProcessorQuery implements Query implements Query(results, additionalDataBuilder.build(calculationTimeInNanos, stringMessages, locale)); } + private void logOccuredFailures() { + for (Throwable failure : resultReceiver.getOccuredFailures()) { + LOGGER.log(Level.SEVERE, "An error occured during the processing of an instruction: ", failure); + } + } + private void waitTillWorkIsDone(long timeoutInMillis) throws InterruptedException, TimeoutException { setUpTimeoutTimer(timeoutInMillis); synchronized (monitorObject) { @@ -138,10 +148,12 @@ public class ProcessorQuery implements Query results; + private List occuredFailures; public ProcessResultReceiver() { resultsLock = new ReentrantLock(); results = new HashMap<>(); + occuredFailures = new ArrayList<>(); } @Override @@ -153,6 +165,11 @@ public class ProcessorQuery implements Query implements Query(); + occuredFailures = new ArrayList<>(); } public Map getResult() { return results; } + + public List getOccuredFailures() { + return occuredFailures; + } @Override public AdditionalResultDataBuilder getAdditionalResultData(AdditionalResultDataBuilder additionalDataBuilder) { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractPartitioningParallelProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractPartitioningParallelProcessor.java index 25306052935..ee80223fc66 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractPartitioningParallelProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractPartitioningParallelProcessor.java @@ -46,7 +46,7 @@ public abstract class AbstractPartitioningParallelProcessor partitionElement(InputType element); + @Override + public void onFailure(Throwable failure) { + for (Processor resultReceiver : resultReceivers) { + resultReceiver.onFailure(failure); + } + } + @Override public void finish() throws InterruptedException { sleepUntilAllInstructionsFinished(); diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractProcessor.java index a79825eebcf..8a5cfca4d80 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractProcessor.java @@ -20,6 +20,13 @@ public abstract class AbstractProcessor implements Proces ResultType result = processElement(element); forwardResultToTheReceivers(result); } + + @Override + public void onFailure(Throwable failure) { + for (Processor resultReceiver : resultReceivers) { + resultReceiver.onFailure(failure); + } + } private void forwardResultToTheReceivers(ResultType result) { for (Processor resultReceiver : resultReceivers) { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index c623791fa6c..03272caf8b4 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -1,10 +1,12 @@ package com.sap.sse.datamining.impl.functions; import java.lang.reflect.Method; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -129,9 +131,12 @@ public class SimpleFunctionRegistry implements FunctionRegistry { private class FunctionsReceiver implements Processor>> { private final Lock functionsRegistrationLock; + + private final List occuredFailures; public FunctionsReceiver() { functionsRegistrationLock = new ReentrantLock(); + occuredFailures = new ArrayList<>(); } @Override @@ -143,9 +148,17 @@ public class SimpleFunctionRegistry implements FunctionRegistry { functionsRegistrationLock.unlock(); } } + + @Override + public void onFailure(Throwable failure) { + occuredFailures.add(failure); + } @Override public void finish() throws InterruptedException { + for (Throwable failure : occuredFailures) { + LOGGER.log(Level.SEVERE, "An error occured during the processing of an instruction: ", failure); + } } @Override From 2d03bb6d400018f09d406d8520b1bb66be88cb19 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 3 Apr 2014 17:44:28 +0200 Subject: [PATCH 014/114] Fixed a missed error --- .../TestLeaderboardGroupFilteringRetrievalProcessor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java index 168a93419ab..5b9c3f81cfa 100644 --- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java @@ -48,6 +48,9 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { retrievedGroups.add(element); } @Override + public void onFailure(Throwable failure) { + } + @Override public void finish() throws InterruptedException { } @Override From 31b186c591f6b4b69546c73822768d48694d9827 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Tue, 29 Apr 2014 11:49:37 +0200 Subject: [PATCH 015/114] Cleaned the sailing data mining project --- .../sailing/datamining/factories/DataRetrieverFactory.java | 4 ++-- .../sap/sailing/datamining/factories/ExtractorFactory.java | 2 +- .../AbstractLeaderboardGroupDataRetrievalWorker.java | 2 +- .../GPSFixLeaderboardGroupDataRetrievalWorker.java | 4 ++-- .../GroupDividingParallelDataRetriever.java | 2 +- .../deprecated}/SpeedInKnotsExtractionWorker.java | 2 +- ...dLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java | 4 ++-- .../{ => deprecated}/DataRetrieverWorkerBuilder.java | 6 +++--- .../builders/{ => deprecated}/ExtractionWorkerBuilder.java | 4 ++-- .../components/AbstractFilteringRetrievalProcessor.java | 1 + 10 files changed, 16 insertions(+), 15 deletions(-) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/{ => deprecated}/AbstractLeaderboardGroupDataRetrievalWorker.java (98%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/{gps_fix => components/deprecated}/GPSFixLeaderboardGroupDataRetrievalWorker.java (94%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/{ => deprecated}/GroupDividingParallelDataRetriever.java (97%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/{workers => components/deprecated}/SpeedInKnotsExtractionWorker.java (84%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/{tracked_leg_of_competitor => components/deprecated}/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java (86%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/{ => deprecated}/DataRetrieverWorkerBuilder.java (78%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/{ => deprecated}/ExtractionWorkerBuilder.java (87%) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java index 1635da5fb2d..3b5e9ba1987 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java @@ -2,8 +2,8 @@ package com.sap.sailing.datamining.factories; import java.util.concurrent.ThreadPoolExecutor; -import com.sap.sailing.datamining.impl.components.GroupDividingParallelDataRetriever; -import com.sap.sailing.datamining.impl.workers.builders.DataRetrieverWorkerBuilder; +import com.sap.sailing.datamining.impl.components.deprecated.GroupDividingParallelDataRetriever; +import com.sap.sailing.datamining.impl.workers.builders.deprecated.DataRetrieverWorkerBuilder; import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.server.RacingEventService; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/ExtractorFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/ExtractorFactory.java index 3716ad2b970..98bfa6686ee 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/ExtractorFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/ExtractorFactory.java @@ -3,7 +3,7 @@ package com.sap.sailing.datamining.factories; import java.util.Locale; import java.util.concurrent.ThreadPoolExecutor; -import com.sap.sailing.datamining.impl.workers.builders.ExtractionWorkerBuilder; +import com.sap.sailing.datamining.impl.workers.builders.deprecated.ExtractionWorkerBuilder; import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sse.datamining.components.ParallelExtractor; import com.sap.sse.datamining.i18n.DataMiningStringMessages; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/AbstractLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java similarity index 98% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/AbstractLeaderboardGroupDataRetrievalWorker.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java index 8a5abc27ad4..c7f4c5b3752 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/AbstractLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java @@ -1,4 +1,4 @@ -package com.sap.sailing.datamining.impl.components; +package com.sap.sailing.datamining.impl.components.deprecated; import java.util.ArrayList; import java.util.Collection; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java similarity index 94% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixLeaderboardGroupDataRetrievalWorker.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java index 34a35a734a0..6b1bb97f045 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java @@ -1,4 +1,4 @@ -package com.sap.sailing.datamining.impl.gps_fix; +package com.sap.sailing.datamining.impl.components.deprecated; import java.util.ArrayList; import java.util.Collection; @@ -7,8 +7,8 @@ import java.util.List; import com.sap.sailing.datamining.data.HasGPSFixContext; import com.sap.sailing.datamining.data.GPSFixWithContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.datamining.impl.components.AbstractLeaderboardGroupDataRetrievalWorker; import com.sap.sailing.datamining.impl.data.HasGPSFixContextImpl; +import com.sap.sailing.datamining.impl.gps_fix.GPSFixWithContextImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.tracking.GPSFixMoving; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GroupDividingParallelDataRetriever.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GroupDividingParallelDataRetriever.java similarity index 97% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GroupDividingParallelDataRetriever.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GroupDividingParallelDataRetriever.java index 807a874be6a..603edaf75e0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GroupDividingParallelDataRetriever.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GroupDividingParallelDataRetriever.java @@ -1,4 +1,4 @@ -package com.sap.sailing.datamining.impl.components; +package com.sap.sailing.datamining.impl.components.deprecated; import java.util.ArrayList; import java.util.Collection; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/SpeedInKnotsExtractionWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/SpeedInKnotsExtractionWorker.java similarity index 84% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/SpeedInKnotsExtractionWorker.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/SpeedInKnotsExtractionWorker.java index cf130331d30..ae7ab9b6ae4 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/SpeedInKnotsExtractionWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/SpeedInKnotsExtractionWorker.java @@ -1,4 +1,4 @@ -package com.sap.sailing.datamining.impl.workers; +package com.sap.sailing.datamining.impl.components.deprecated; import com.sap.sailing.domain.base.Moving; import com.sap.sse.datamining.impl.workers.extractors.AbstractExtractionWorker; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java similarity index 86% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java index 6a700a65945..16839eb2cc3 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker.java @@ -1,11 +1,11 @@ -package com.sap.sailing.datamining.impl.tracked_leg_of_competitor; +package com.sap.sailing.datamining.impl.components.deprecated; import java.util.ArrayList; import java.util.Collection; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.data.TrackedLegOfCompetitorWithContext; -import com.sap.sailing.datamining.impl.components.AbstractLeaderboardGroupDataRetrievalWorker; +import com.sap.sailing.datamining.impl.tracked_leg_of_competitor.TrackedLegOfCompetitorWithContextImpl; import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/DataRetrieverWorkerBuilder.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/DataRetrieverWorkerBuilder.java similarity index 78% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/DataRetrieverWorkerBuilder.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/DataRetrieverWorkerBuilder.java index 7c34311185c..e0c5d0a5896 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/DataRetrieverWorkerBuilder.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/DataRetrieverWorkerBuilder.java @@ -1,7 +1,7 @@ -package com.sap.sailing.datamining.impl.workers.builders; +package com.sap.sailing.datamining.impl.workers.builders.deprecated; -import com.sap.sailing.datamining.impl.gps_fix.GPSFixLeaderboardGroupDataRetrievalWorker; -import com.sap.sailing.datamining.impl.tracked_leg_of_competitor.TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker; +import com.sap.sailing.datamining.impl.components.deprecated.GPSFixLeaderboardGroupDataRetrievalWorker; +import com.sap.sailing.datamining.impl.components.deprecated.TrackedLegOfCompetitorLeaderboardGroupDataRetrievalWorker; import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sse.datamining.workers.DataRetrievalWorker; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/ExtractionWorkerBuilder.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/ExtractionWorkerBuilder.java similarity index 87% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/ExtractionWorkerBuilder.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/ExtractionWorkerBuilder.java index f589cf1ec69..6e21a8e8a6a 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/ExtractionWorkerBuilder.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/workers/builders/deprecated/ExtractionWorkerBuilder.java @@ -1,7 +1,7 @@ -package com.sap.sailing.datamining.impl.workers.builders; +package com.sap.sailing.datamining.impl.workers.builders.deprecated; +import com.sap.sailing.datamining.impl.components.deprecated.SpeedInKnotsExtractionWorker; import com.sap.sailing.datamining.impl.tracked_leg_of_competitor.DistanceTraveledExtractionWorker; -import com.sap.sailing.datamining.impl.workers.SpeedInKnotsExtractionWorker; import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sse.datamining.workers.ExtractionWorker; import com.sap.sse.datamining.workers.WorkerBuilder; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java index 276241f42c1..cc501271891 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java @@ -29,6 +29,7 @@ public abstract class AbstractFilteringRetrievalProcessor partitionElement(InputType element) { return retrieveData(element); From 1b26dfa865b80ae8d2b60c30c35de924fa091b65 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Tue, 29 Apr 2014 15:21:52 +0200 Subject: [PATCH 016/114] Marked the side effect free values and dimensions of the domain model --- .../data/HasLeaderboardContext.java | 2 ++ .../data/HasLeaderboardGroupContext.java | 2 ++ .../datamining/data/HasTrackedLegContext.java | 4 +++ .../HasTrackedLegOfCompetitorContext.java | 2 ++ .../data/HasTrackedRaceContext.java | 28 +++++++++++++++++-- ...ctLeaderboardGroupDataRetrievalWorker.java | 2 +- .../impl/data/HasTrackedRaceContextImpl.java | 27 ++++++++++++++++-- .../impl/gps_fix/GPSFixWithContextImpl.java | 6 ++-- ...TrackedLegOfCompetitorWithContextImpl.java | 4 +-- .../META-INF/MANIFEST.MF | 1 + .../com/sap/sailing/domain/common/Named.java | 3 ++ .../META-INF/MANIFEST.MF | 3 +- .../src/com/sap/sailing/domain/base/Boat.java | 2 ++ .../sap/sailing/domain/base/Competitor.java | 3 ++ .../sap/sailing/domain/base/Nationality.java | 2 ++ .../sailing/domain/base/WithNationality.java | 3 ++ .../domain/base/impl/CompetitorImpl.java | 2 +- .../META-INF/MANIFEST.MF | 3 +- .../domain/tracking/TrackedRegatta.java | 1 + 19 files changed, 86 insertions(+), 14 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java index b2451294b7f..cb49be60fdc 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java @@ -1,9 +1,11 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasLeaderboardContext extends HasLeaderboardGroupContext { + @SideEffectFreeValue(messageKey="Leaderboard") public Leaderboard getLeaderboard(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java index cbdbcd23ab8..cecb0faf829 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java @@ -1,9 +1,11 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasLeaderboardGroupContext { + @SideEffectFreeValue(messageKey="LeaderboardGroup") public LeaderboardGroup getLeaderboardGroup(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegContext.java index c918082a020..ba1bf249c64 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegContext.java @@ -2,11 +2,15 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sse.datamining.shared.annotations.Dimension; public interface HasTrackedLegContext extends HasTrackedRaceContext { public TrackedLeg getTrackedLeg(); + + @Dimension(messageKey="LegType") public LegType getLegType(); + @Dimension(messageKey="LegNumber") public int getLegNumber(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index e1f836f5d13..48b9ef20a42 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -1,9 +1,11 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.base.Competitor; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasTrackedLegOfCompetitorContext extends HasTrackedLegContext { + @SideEffectFreeValue(messageKey="Competitor") public Competitor getCompetitor(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index b5301a27830..208062c8df7 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -1,14 +1,36 @@ package com.sap.sailing.datamining.data; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.TrackedRegatta; +import com.sap.sse.datamining.shared.annotations.Dimension; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasTrackedRaceContext extends HasLeaderboardContext { - - public CourseArea getCourseArea(); - public Fleet getFleet(); + + public TrackedRegatta getTrackedRegatta(); public TrackedRace getTrackedRace(); + + @SideEffectFreeValue(messageKey="Regatte") + public Regatta getRegatta(); + + @SideEffectFreeValue(messageKey="CourseArea") + public CourseArea getCourseArea(); + + @SideEffectFreeValue(messageKey="Fleet") + public Fleet getFleet(); + + @SideEffectFreeValue(messageKey="BoatClass") + public BoatClass getBoatClass(); + + @SideEffectFreeValue(messageKey="Race") + public RaceDefinition getRace(); + + @Dimension(messageKey="Year") public Integer getYear(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java index c7f4c5b3752..2f9efa48d50 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java @@ -68,7 +68,7 @@ public abstract class AbstractLeaderboardGroupDataRetrievalWorker for (Pair baseDataEntry : baseData) { TrackedLeg trackedLeg = baseDataEntry.getA(); HasTrackedLegContext trackedLegContext = baseDataEntry.getB(); - for (Competitor competitor : trackedLegContext.getTrackedRace().getRace().getCompetitors()) { + for (Competitor competitor : trackedLegContext.getRace().getCompetitors()) { TrackedLegOfCompetitor trackedLegOfCompetitor = trackedLeg.getTrackedLeg(competitor); HasTrackedLegOfCompetitorContext dataContext = new HasTrackedLegOfCompetitorContextImpl(trackedLegContext, competitor); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java index 1ee5f98c319..c4de522adde 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java @@ -4,12 +4,16 @@ import java.util.Calendar; import com.sap.sailing.datamining.data.HasLeaderboardContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; +import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sailing.domain.tracking.TrackedRegatta; public class HasTrackedRaceContextImpl extends HasLeaderboardContextImpl implements HasTrackedRaceContext { @@ -31,6 +35,20 @@ public class HasTrackedRaceContextImpl extends HasLeaderboardContextImpl impleme this.fleet = fleet; this.trackedRace = trackedRace; } + + @Override + public TrackedRegatta getTrackedRegatta() { + return getTrackedRace().getTrackedRegatta(); + } + + public TrackedRace getTrackedRace() { + return trackedRace; + } + + @Override + public Regatta getRegatta() { + return getTrackedRegatta().getRegatta(); + } @Override public CourseArea getCourseArea() { @@ -41,10 +59,15 @@ public class HasTrackedRaceContextImpl extends HasLeaderboardContextImpl impleme public Fleet getFleet() { return fleet; } + + @Override + public BoatClass getBoatClass() { + return getRegatta().getBoatClass(); + } @Override - public TrackedRace getTrackedRace() { - return trackedRace; + public RaceDefinition getRace() { + return getTrackedRace().getRace(); } @Override diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixWithContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixWithContextImpl.java index bd56ee9d4c1..f640ed72741 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixWithContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/gps_fix/GPSFixWithContextImpl.java @@ -44,12 +44,12 @@ public class GPSFixWithContextImpl extends GPSFixMovingImpl implements GPSFixWit @Override public String getRegattaName() { - return context.getTrackedRace().getTrackedRegatta().getRegatta().getName(); + return context.getRegatta().getName(); } @Override public String getRaceName() { - return context.getTrackedRace().getRace().getName(); + return context.getRace().getName(); } @Override @@ -69,7 +69,7 @@ public class GPSFixWithContextImpl extends GPSFixMovingImpl implements GPSFixWit @Override public String getBoatClassName() { - return context.getCompetitor().getBoat().getBoatClass().getName(); + return context.getBoatClass().getName(); } @Override diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorWithContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorWithContextImpl.java index f211553eab9..e5ec19032d8 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorWithContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/tracked_leg_of_competitor/TrackedLegOfCompetitorWithContextImpl.java @@ -20,12 +20,12 @@ public class TrackedLegOfCompetitorWithContextImpl implements TrackedLegOfCompet @Override public String getRegattaName() { - return context.getTrackedRace().getTrackedRegatta().getRegatta().getName(); + return context.getRegatta().getName(); } @Override public String getRaceName() { - return context.getTrackedRace().getRace().getName(); + return context.getRace().getName(); } @Override diff --git a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF index cf73d6c518b..054bb32a301 100755 --- a/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.common/META-INF/MANIFEST.MF @@ -16,3 +16,4 @@ Export-Package: com.sap.sailing.domain.common, com.sap.sailing.domain.common.racelog, com.sap.sailing.domain.common.racelog.utils, com.sap.sailing.domain.common.trackfiles +Require-Bundle: com.sap.sse.datamining.shared diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Named.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Named.java index 780b9b83cbd..7c42eb44aef 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Named.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Named.java @@ -2,6 +2,9 @@ package com.sap.sailing.domain.common; import java.io.Serializable; +import com.sap.sse.datamining.shared.annotations.Dimension; + public interface Named extends Serializable { + @Dimension(messageKey="Name") String getName(); } diff --git a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF index d4dca443728..f781c611ef6 100644 --- a/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain.shared.android/META-INF/MANIFEST.MF @@ -5,7 +5,8 @@ Bundle-SymbolicName: com.sap.sailing.domain.shared.android Bundle-Version: 1.0.0.qualifier Bundle-Vendor: SAP Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0" +Require-Bundle: com.sap.sailing.domain.common;bundle-version="1.0.0", + com.sap.sse.datamining.shared;bundle-version="1.0.0" Export-Package: com.sap.sailing.domain.base, com.sap.sailing.domain.base.configuration, com.sap.sailing.domain.base.configuration.impl, diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Boat.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Boat.java index cf3bad7fec3..3c278ceacc1 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Boat.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Boat.java @@ -1,9 +1,11 @@ package com.sap.sailing.domain.base; import com.sap.sailing.domain.common.Named; +import com.sap.sse.datamining.shared.annotations.Dimension; public interface Boat extends Named { BoatClass getBoatClass(); + @Dimension(messageKey="SailID") String getSailID(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Competitor.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Competitor.java index b078bf8162c..3800ee565e0 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Competitor.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Competitor.java @@ -3,10 +3,13 @@ package com.sap.sailing.domain.base; import com.sap.sailing.domain.common.Color; import com.sap.sailing.domain.common.Named; import com.sap.sailing.domain.common.WithID; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface Competitor extends Named, WithID, IsManagedBySharedDomainFactory { + @SideEffectFreeValue(messageKey="Team") Team getTeam(); + @SideEffectFreeValue(messageKey="Boat") Boat getBoat(); Color getColor(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Nationality.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Nationality.java index 90dd0488ad1..6f17bc453b3 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Nationality.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/Nationality.java @@ -2,8 +2,10 @@ package com.sap.sailing.domain.base; import com.sap.sailing.domain.common.CountryCode; import com.sap.sailing.domain.common.Named; +import com.sap.sse.datamining.shared.annotations.Dimension; public interface Nationality extends Named, WithImage, IsManagedBySharedDomainFactory { + @Dimension(messageKey="NationalityAcronym") String getThreeLetterIOCAcronym(); CountryCode getCountryCode(); diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/WithNationality.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/WithNationality.java index 11603d89d7c..14bce1a2a4f 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/WithNationality.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/WithNationality.java @@ -1,5 +1,8 @@ package com.sap.sailing.domain.base; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + public interface WithNationality { + @SideEffectFreeValue(messageKey="Nationality") Nationality getNationality(); } diff --git a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CompetitorImpl.java b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CompetitorImpl.java index 38ed945fc75..e26d769ebdf 100644 --- a/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CompetitorImpl.java +++ b/java/com.sap.sailing.domain.shared.android/src/com/sap/sailing/domain/base/impl/CompetitorImpl.java @@ -42,7 +42,7 @@ public class CompetitorImpl implements DynamicCompetitor { public Serializable getId() { return id; } - + @Override public DynamicTeam getTeam() { return team; diff --git a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF index 29e285ecbdc..ecc5b1a57c9 100755 --- a/java/com.sap.sailing.domain/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.domain/META-INF/MANIFEST.MF @@ -29,4 +29,5 @@ Require-Bundle: com.googlecode.java-diff-utils;bundle-version="1.3.0", com.sap.sailing.domain.shared.android;bundle-version="1.0.0", com.sap.sailing.domain.common, org.json.simple;bundle-version="1.1.0", - com.sap.sailing.geocoding + com.sap.sailing.geocoding, + com.sap.sse.datamining.shared;bundle-version="1.0.0" diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java index 078886cfd50..7a41af624be 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/tracking/TrackedRegatta.java @@ -7,6 +7,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.base.Sideline; +import com.sap.sailing.domain.base.impl.TrackedRaces; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.TimePoint; From 694d77514fa1047f1116ee4ecadce50402611493 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Tue, 29 Apr 2014 20:19:34 +0200 Subject: [PATCH 017/114] Introduced a new context hierarchy --- .../datamining/data/HasEventContext.java | 11 +++++ .../data/HasLeaderboardContext.java | 11 ----- .../data/HasLeaderboardGroupContext.java | 11 ----- .../data/HasTrackedRaceContext.java | 16 +------ .../data/HasTrackedRegattaContext.java | 19 ++++++++ .../impl/data/HasEventContextImpl.java | 19 ++++++++ .../impl/data/HasGPSFixContextImpl.java | 20 ++++----- .../impl/data/HasLeaderboardContextImpl.java | 21 --------- .../data/HasLeaderboardGroupContextImpl.java | 19 -------- .../impl/data/HasTrackedLegContextImpl.java | 15 +++---- .../HasTrackedLegOfCompetitorContextImpl.java | 21 +++++---- .../impl/data/HasTrackedRaceContextImpl.java | 45 ++++--------------- .../data/HasTrackedRegattaContextImpl.java | 38 ++++++++++++++++ .../data/LeaderboardGroupWithContextImpl.java | 19 -------- 14 files changed, 122 insertions(+), 163 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardContextImpl.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardGroupContextImpl.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java new file mode 100644 index 00000000000..c856b9a5d63 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java @@ -0,0 +1,11 @@ +package com.sap.sailing.datamining.data; + +import com.sap.sailing.domain.base.Event; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + +public interface HasEventContext { + + @SideEffectFreeValue(messageKey="Event") + public Event getEvent(); + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java deleted file mode 100644 index cb49be60fdc..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; - -public interface HasLeaderboardContext extends HasLeaderboardGroupContext { - - @SideEffectFreeValue(messageKey="Leaderboard") - public Leaderboard getLeaderboard(); - -} \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java deleted file mode 100644 index cecb0faf829..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasLeaderboardGroupContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; - -public interface HasLeaderboardGroupContext { - - @SideEffectFreeValue(messageKey="LeaderboardGroup") - public LeaderboardGroup getLeaderboardGroup(); - -} \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index 208062c8df7..8a21ee5a01e 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -1,32 +1,18 @@ package com.sap.sailing.datamining.data; -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; -import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.domain.tracking.TrackedRegatta; import com.sap.sse.datamining.shared.annotations.Dimension; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; -public interface HasTrackedRaceContext extends HasLeaderboardContext { +public interface HasTrackedRaceContext extends HasTrackedRegattaContext { - public TrackedRegatta getTrackedRegatta(); public TrackedRace getTrackedRace(); - - @SideEffectFreeValue(messageKey="Regatte") - public Regatta getRegatta(); - - @SideEffectFreeValue(messageKey="CourseArea") - public CourseArea getCourseArea(); @SideEffectFreeValue(messageKey="Fleet") public Fleet getFleet(); - @SideEffectFreeValue(messageKey="BoatClass") - public BoatClass getBoatClass(); - @SideEffectFreeValue(messageKey="Race") public RaceDefinition getRace(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java new file mode 100644 index 00000000000..945ed38eeec --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java @@ -0,0 +1,19 @@ +package com.sap.sailing.datamining.data; + +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + +public interface HasTrackedRegattaContext extends HasEventContext { + + @SideEffectFreeValue(messageKey="Regatta") + public Regatta getRegatta(); + + @SideEffectFreeValue(messageKey="CourseArea") + public CourseArea getCourseArea(); + + @SideEffectFreeValue(messageKey="BoatClass") + public BoatClass getBoatClass(); + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java new file mode 100644 index 00000000000..5f8b69271ef --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java @@ -0,0 +1,19 @@ +package com.sap.sailing.datamining.impl.data; + +import com.sap.sailing.datamining.data.HasEventContext; +import com.sap.sailing.domain.base.Event; + +public class HasEventContextImpl implements HasEventContext { + + private final Event event; + + public HasEventContextImpl(Event event) { + this.event = event; + } + + @Override + public Event getEvent() { + return event; + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java index a26e907ecf9..3336c570304 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java @@ -3,24 +3,22 @@ package com.sap.sailing.datamining.impl.data; import com.sap.sailing.datamining.data.HasGPSFixContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedRace; public class HasGPSFixContextImpl extends HasTrackedLegOfCompetitorContextImpl implements HasGPSFixContext { - - public HasGPSFixContextImpl(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard, CourseArea courseArea, - Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber, Competitor competitor) { - super(leaderboardGroup, leaderboard, courseArea, fleet, trackedRace, trackedLeg, legNumber, competitor); + + public HasGPSFixContextImpl(HasTrackedLegOfCompetitorContext legContext) { + this(legContext.getEvent(), legContext.getRegatta(), legContext.getFleet(), legContext.getTrackedRace(), + legContext.getTrackedLeg(), legContext.getLegNumber(), legContext.getCompetitor()); } - public HasGPSFixContextImpl(HasTrackedLegOfCompetitorContext baseContext) { - this(baseContext.getLeaderboardGroup(), baseContext.getLeaderboard(), baseContext.getCourseArea(), baseContext.getFleet(), - baseContext.getTrackedRace(), baseContext.getTrackedLeg(), baseContext.getLegNumber(), - baseContext.getCompetitor()); + public HasGPSFixContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, + TrackedLeg trackedLeg, int legNumber, Competitor competitor) { + super(event, regatta, fleet, trackedRace, trackedLeg, legNumber, competitor); } } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardContextImpl.java deleted file mode 100644 index f74221d0401..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardContextImpl.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.sap.sailing.datamining.impl.data; - -import com.sap.sailing.datamining.data.HasLeaderboardContext; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; - -public class HasLeaderboardContextImpl extends HasLeaderboardGroupContextImpl implements HasLeaderboardContext { - - private final Leaderboard leaderboard; - - public HasLeaderboardContextImpl(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard) { - super(leaderboardGroup); - this.leaderboard = leaderboard; - } - - @Override - public Leaderboard getLeaderboard() { - return leaderboard; - } - -} \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardGroupContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardGroupContextImpl.java deleted file mode 100644 index 355e29daa31..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasLeaderboardGroupContextImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.datamining.impl.data; - -import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; - -public class HasLeaderboardGroupContextImpl implements HasLeaderboardGroupContext { - - private final LeaderboardGroup leaderboardGroup; - - public HasLeaderboardGroupContextImpl(LeaderboardGroup leaderboardGroup) { - this.leaderboardGroup = leaderboardGroup; - } - - @Override - public LeaderboardGroup getLeaderboardGroup() { - return leaderboardGroup; - } - -} \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java index fc9d85ee03d..52e89b6e6b0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java @@ -2,14 +2,13 @@ package com.sap.sailing.datamining.impl.data; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; -import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.NoWindException; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.common.impl.MillisecondsTimePoint; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; @@ -22,14 +21,12 @@ public class HasTrackedLegContextImpl extends HasTrackedRaceContextImpl implemen private boolean legTypeHasBeenInitialized; public HasTrackedLegContextImpl(HasTrackedRaceContext trackedRaceContext, TrackedLeg trackedLeg, int legNumber) { - this(trackedRaceContext.getLeaderboardGroup(), trackedRaceContext.getLeaderboard(), trackedRaceContext - .getCourseArea(), trackedRaceContext.getFleet(), trackedRaceContext.getTrackedRace(), trackedLeg, - legNumber); + this(trackedRaceContext.getEvent(), trackedRaceContext.getRegatta(), trackedRaceContext.getFleet(), + trackedRaceContext.getTrackedRace(), trackedLeg, legNumber); } - public HasTrackedLegContextImpl(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard, CourseArea courseArea, Fleet fleet, - TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber) { - super(leaderboardGroup, leaderboard, courseArea, fleet, trackedRace); + public HasTrackedLegContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber) { + super(event, regatta, fleet, trackedRace); this.trackedLeg = trackedLeg; this.legNumber = legNumber; } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java index ec494b241b8..b036034e760 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java @@ -3,10 +3,9 @@ package com.sap.sailing.datamining.impl.data; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedRace; @@ -14,16 +13,16 @@ public class HasTrackedLegOfCompetitorContextImpl extends HasTrackedLegContextIm private final Competitor competitor; - public HasTrackedLegOfCompetitorContextImpl(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard, - CourseArea courseArea, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber, Competitor competitor) { - super(leaderboardGroup, leaderboard, courseArea, fleet, trackedRace, trackedLeg, legNumber); - this.competitor = competitor; + public HasTrackedLegOfCompetitorContextImpl(HasTrackedLegContext trackedLegContext, Competitor competitor) { + this(trackedLegContext.getEvent(), trackedLegContext.getRegatta(), trackedLegContext.getFleet(), + trackedLegContext.getTrackedRace(), trackedLegContext.getTrackedLeg(), + trackedLegContext.getLegNumber(), competitor); } - public HasTrackedLegOfCompetitorContextImpl(HasTrackedLegContext trackedLegContext, Competitor competitor) { - this(trackedLegContext.getLeaderboardGroup(), trackedLegContext.getLeaderboard(), trackedLegContext.getCourseArea(), - trackedLegContext.getFleet(), trackedLegContext.getTrackedRace(), trackedLegContext.getTrackedLeg(), trackedLegContext.getLegNumber(), - competitor); + public HasTrackedLegOfCompetitorContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, + TrackedLeg trackedLeg, int legNumber, Competitor competitor) { + super(event, regatta, fleet, trackedRace, trackedLeg, legNumber); + this.competitor = competitor; } @Override diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java index c4de522adde..de32235a0d6 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java @@ -2,57 +2,35 @@ package com.sap.sailing.datamining.impl.data; import java.util.Calendar; -import com.sap.sailing.datamining.data.HasLeaderboardContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.datamining.data.HasTrackedRegattaContext; +import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.TimePoint; -import com.sap.sailing.domain.leaderboard.Leaderboard; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.tracking.TrackedRace; -import com.sap.sailing.domain.tracking.TrackedRegatta; -public class HasTrackedRaceContextImpl extends HasLeaderboardContextImpl implements HasTrackedRaceContext { +public class HasTrackedRaceContextImpl extends HasTrackedRegattaContextImpl implements HasTrackedRaceContext { - private final CourseArea courseArea; private final Fleet fleet; private final TrackedRace trackedRace; private Integer year; private boolean yearHasBeenInitialized; - public HasTrackedRaceContextImpl(HasLeaderboardContext leaderboardContext, CourseArea courseArea, Fleet fleet, - TrackedRace trackedRace) { - this(leaderboardContext.getLeaderboardGroup(), leaderboardContext.getLeaderboard(), courseArea, fleet, trackedRace); + public HasTrackedRaceContextImpl(HasTrackedRegattaContext regattaContext, Fleet fleet, TrackedRace trackedRace) { + this(regattaContext.getEvent(), regattaContext.getRegatta(), fleet, trackedRace); } - public HasTrackedRaceContextImpl(LeaderboardGroup leaderboardGroup, Leaderboard leaderboard, CourseArea courseArea, - Fleet fleet, TrackedRace trackedRace) { - super(leaderboardGroup, leaderboard); - this.courseArea = courseArea; + public HasTrackedRaceContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace) { + super(event, regatta); this.fleet = fleet; this.trackedRace = trackedRace; } @Override - public TrackedRegatta getTrackedRegatta() { - return getTrackedRace().getTrackedRegatta(); - } - public TrackedRace getTrackedRace() { - return trackedRace; - } - - @Override - public Regatta getRegatta() { - return getTrackedRegatta().getRegatta(); - } - - @Override - public CourseArea getCourseArea() { - return courseArea; + return getTrackedRace(); } @Override @@ -60,14 +38,9 @@ public class HasTrackedRaceContextImpl extends HasLeaderboardContextImpl impleme return fleet; } - @Override - public BoatClass getBoatClass() { - return getRegatta().getBoatClass(); - } - @Override public RaceDefinition getRace() { - return getTrackedRace().getRace(); + return trackedRace.getRace(); } @Override diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java new file mode 100644 index 00000000000..75df0ba0e37 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java @@ -0,0 +1,38 @@ +package com.sap.sailing.datamining.impl.data; + +import com.sap.sailing.datamining.data.HasEventContext; +import com.sap.sailing.datamining.data.HasTrackedRegattaContext; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.base.Regatta; + +public class HasTrackedRegattaContextImpl extends HasEventContextImpl implements HasTrackedRegattaContext { + + private Regatta regatta; + + public HasTrackedRegattaContextImpl(HasEventContext eventContext, Regatta regatta) { + this(eventContext.getEvent(), regatta); + } + + public HasTrackedRegattaContextImpl(Event event, Regatta regatta) { + super(event); + this.regatta = regatta; + } + + @Override + public Regatta getRegatta() { + return regatta; + } + + @Override + public CourseArea getCourseArea() { + return getRegatta().getDefaultCourseArea(); + } + + @Override + public BoatClass getBoatClass() { + return getRegatta().getBoatClass(); + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java deleted file mode 100644 index 4ec855711ea..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/LeaderboardGroupWithContextImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.datamining.impl.data; - -import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; -import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; - -public class LeaderboardGroupWithContextImpl implements LeaderboardGroupWithContext { - - private HasLeaderboardGroupContext context; - - public LeaderboardGroupWithContextImpl(HasLeaderboardGroupContext context) { - this.context = context; - } - - @Override - public String getLeaderboardGroupName() { - return context.getLeaderboardGroup().getName(); - } - -} From 3bc5a4029ec9472163ae7b8c33f616e5364e98e0 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 17:54:31 +0200 Subject: [PATCH 018/114] Cleaned the context hierarchy Removed contexts for event and regatta, because an event or regatta can't be used as atomar data type (they don't have enough data to make serious queries possible). The highest context element is now the HasTrackedRaceContext. Early filtering will still be possible, when the query is working on RegattaLeaderboards, which will be the case for the standard case. --- ...boardGroupFilteringRetrievalProcessor.java | 2 +- .../datamining/data/HasEventContext.java | 11 ------ .../data/HasTrackedRaceContext.java | 18 ++++++++- .../data/HasTrackedRegattaContext.java | 19 ---------- .../impl/data/HasEventContextImpl.java | 19 ---------- .../impl/data/HasTrackedRaceContextImpl.java | 34 +++++++++++++---- .../data/HasTrackedRegattaContextImpl.java | 38 ------------------- 7 files changed, 45 insertions(+), 96 deletions(-) delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java index 5b9c3f81cfa..df0bc3bdf5a 100644 --- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java @@ -69,7 +69,7 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { return name == "LG1" || name == "LG2" || name == "LG3"; } }; - retriever = new LeaderboardGroupFilteringRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(receiver), criteria); + retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(receiver), criteria); } private Map getGroupsInService() { diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java deleted file mode 100644 index c856b9a5d63..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasEventContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.domain.base.Event; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; - -public interface HasEventContext { - - @SideEffectFreeValue(messageKey="Event") - public Event getEvent(); - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java index 8a21ee5a01e..eba54e8c845 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRaceContext.java @@ -1,15 +1,31 @@ package com.sap.sailing.datamining.data; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.CourseArea; +import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; +import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.datamining.shared.annotations.Dimension; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; -public interface HasTrackedRaceContext extends HasTrackedRegattaContext { +public interface HasTrackedRaceContext { public TrackedRace getTrackedRace(); + @SideEffectFreeValue(messageKey="Event") + public Event getEvent(); + + @SideEffectFreeValue(messageKey="Regatta") + public Regatta getRegatta(); + + @SideEffectFreeValue(messageKey="CourseArea") + public CourseArea getCourseArea(); + + @SideEffectFreeValue(messageKey="BoatClass") + public BoatClass getBoatClass(); + @SideEffectFreeValue(messageKey="Fleet") public Fleet getFleet(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java deleted file mode 100644 index 945ed38eeec..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedRegattaContext.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Regatta; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; - -public interface HasTrackedRegattaContext extends HasEventContext { - - @SideEffectFreeValue(messageKey="Regatta") - public Regatta getRegatta(); - - @SideEffectFreeValue(messageKey="CourseArea") - public CourseArea getCourseArea(); - - @SideEffectFreeValue(messageKey="BoatClass") - public BoatClass getBoatClass(); - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java deleted file mode 100644 index 5f8b69271ef..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasEventContextImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.sap.sailing.datamining.impl.data; - -import com.sap.sailing.datamining.data.HasEventContext; -import com.sap.sailing.domain.base.Event; - -public class HasEventContextImpl implements HasEventContext { - - private final Event event; - - public HasEventContextImpl(Event event) { - this.event = event; - } - - @Override - public Event getEvent() { - return event; - } - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java index de32235a0d6..c644ef69593 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java @@ -3,7 +3,8 @@ package com.sap.sailing.datamining.impl.data; import java.util.Calendar; import com.sap.sailing.datamining.data.HasTrackedRaceContext; -import com.sap.sailing.datamining.data.HasTrackedRegattaContext; +import com.sap.sailing.domain.base.BoatClass; +import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceDefinition; @@ -11,23 +12,42 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.tracking.TrackedRace; -public class HasTrackedRaceContextImpl extends HasTrackedRegattaContextImpl implements HasTrackedRaceContext { +public class HasTrackedRaceContextImpl implements HasTrackedRaceContext { + private final Event event; + private final Regatta regatta; private final Fleet fleet; private final TrackedRace trackedRace; private Integer year; private boolean yearHasBeenInitialized; - - public HasTrackedRaceContextImpl(HasTrackedRegattaContext regattaContext, Fleet fleet, TrackedRace trackedRace) { - this(regattaContext.getEvent(), regattaContext.getRegatta(), fleet, trackedRace); - } public HasTrackedRaceContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace) { - super(event, regatta); + this.event = event; + this.regatta = regatta; this.fleet = fleet; this.trackedRace = trackedRace; } + @Override + public Event getEvent() { + return event; + } + + @Override + public Regatta getRegatta() { + return regatta; + } + + @Override + public CourseArea getCourseArea() { + return getRegatta().getDefaultCourseArea(); + } + + @Override + public BoatClass getBoatClass() { + return getRegatta().getBoatClass(); + } + @Override public TrackedRace getTrackedRace() { return getTrackedRace(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java deleted file mode 100644 index 75df0ba0e37..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRegattaContextImpl.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.sap.sailing.datamining.impl.data; - -import com.sap.sailing.datamining.data.HasEventContext; -import com.sap.sailing.datamining.data.HasTrackedRegattaContext; -import com.sap.sailing.domain.base.BoatClass; -import com.sap.sailing.domain.base.CourseArea; -import com.sap.sailing.domain.base.Event; -import com.sap.sailing.domain.base.Regatta; - -public class HasTrackedRegattaContextImpl extends HasEventContextImpl implements HasTrackedRegattaContext { - - private Regatta regatta; - - public HasTrackedRegattaContextImpl(HasEventContext eventContext, Regatta regatta) { - this(eventContext.getEvent(), regatta); - } - - public HasTrackedRegattaContextImpl(Event event, Regatta regatta) { - super(event); - this.regatta = regatta; - } - - @Override - public Regatta getRegatta() { - return regatta; - } - - @Override - public CourseArea getCourseArea() { - return getRegatta().getDefaultCourseArea(); - } - - @Override - public BoatClass getBoatClass() { - return getRegatta().getBoatClass(); - } - -} From a382f59755a97f4a07b1cb24d8333b1440cfcdd8 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 17:55:10 +0200 Subject: [PATCH 019/114] Extended the abstract processor structure for retrieving data --- ...boardGroupFilteringRetrievalProcessor.java | 35 ----------- .../LeaderboardGroupRetrievalProcessor.java | 29 ++++++++++ .../AbstractFilteringRetrievalProcessor.java | 43 ++++---------- .../AbstractRetrievalProcessor.java | 58 +++++++++++++++++++ .../AbstractSimpleRetrievalProcessor.java | 20 +++++++ 5 files changed, 117 insertions(+), 68 deletions(-) delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleRetrievalProcessor.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java deleted file mode 100644 index 0e804362392..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupFilteringRetrievalProcessor.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.sap.sailing.datamining.impl.components; - -import java.util.Collection; -import java.util.concurrent.ExecutorService; - -import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; -import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; -import com.sap.sailing.datamining.impl.data.HasLeaderboardGroupContextImpl; -import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContextImpl; -import com.sap.sailing.domain.leaderboard.LeaderboardGroup; -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.impl.components.AbstractFilteringRetrievalProcessor; - -public class LeaderboardGroupFilteringRetrievalProcessor extends - AbstractFilteringRetrievalProcessor { - - public LeaderboardGroupFilteringRetrievalProcessor(ExecutorService executor, - Collection> resultReceivers, FilterCriteria criteria) { - super(executor, resultReceivers, criteria); - } - - @Override - protected Iterable retrieveData(RacingEventService element) { - return element.getLeaderboardGroups().values(); - } - - @Override - protected LeaderboardGroupWithContext contextifyElement(LeaderboardGroup partialElement) { - HasLeaderboardGroupContext context = new HasLeaderboardGroupContextImpl(partialElement); - return new LeaderboardGroupWithContextImpl(context); - } - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupRetrievalProcessor.java new file mode 100644 index 00000000000..7abeb279a55 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/LeaderboardGroupRetrievalProcessor.java @@ -0,0 +1,29 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.server.RacingEventService; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractRetrievalProcessor; + +public class LeaderboardGroupRetrievalProcessor extends + AbstractRetrievalProcessor { + + public LeaderboardGroupRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers) { + super(executor, resultReceivers); + } + + @Override + protected LeaderboardGroup convertWorkingToResultType(LeaderboardGroup partialElement) { + return partialElement; + } + + @Override + protected Iterable retrieveData(RacingEventService element) { + return element.getLeaderboardGroups().values(); + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java index cc501271891..9665e547dd8 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractFilteringRetrievalProcessor.java @@ -10,40 +10,28 @@ import com.sap.sse.datamining.AdditionalResultDataBuilder; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; -public abstract class AbstractFilteringRetrievalProcessor - extends AbstractPartitioningParallelProcessor { +public abstract class AbstractFilteringRetrievalProcessor + extends AbstractRetrievalProcessor { - private final FilterCriteria criteria; - - private Lock retrievedDataAmountLock; - private int retrievedDataAmount; + private final FilterCriteria criteria; private Lock filteredDataAmountLock; private int filteredDataAmount; public AbstractFilteringRetrievalProcessor(ExecutorService executor, - Collection> resultReceivers, FilterCriteria criteria) { + Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers); this.criteria = criteria; - retrievedDataAmountLock = new ReentrantLock(); filteredDataAmountLock = new ReentrantLock(); } - - // Override, to provide a better method name to the sub classes - @Override - protected Iterable partitionElement(InputType element) { - return retrieveData(element); - } - - protected abstract Iterable retrieveData(InputType element); @Override - protected Callable createInstruction(final ResultType partialElement) { - return new Callable() { + protected Callable createInstruction(final WorkingType partialElement) { + final Callable superInstruction = super.createInstruction(partialElement); + return new Callable() { @Override - public ResultTypeWithContext call() throws Exception { - incrementRetrievedDataAmount(); - ResultTypeWithContext elementWithContext = contextifyElement(partialElement); + public ResultType call() throws Exception { + ResultType elementWithContext = superInstruction.call(); if (criteria.matches(elementWithContext)) { incrementFilteredDataAmount(); return elementWithContext; @@ -53,17 +41,6 @@ public abstract class AbstractFilteringRetrievalProcessor extends + AbstractPartitioningParallelProcessor { + + private final Lock retrievedDataAmountLock; + private int retrievedDataAmount; + + public AbstractRetrievalProcessor(ExecutorService executor, Collection> resultReceivers) { + super(executor, resultReceivers); + retrievedDataAmountLock = new ReentrantLock(); + } + + @Override + protected Callable createInstruction(final WorkingType partialElement) { + return new Callable() { + @Override + public ResultType call() throws Exception { + incrementRetrievedDataAmount(); + return convertWorkingToResultType(partialElement); + } + }; + } + + protected abstract ResultType convertWorkingToResultType(WorkingType partialElement); + + // Override, to provide a better method name to the sub classes + @Override + protected Iterable partitionElement(InputType element) { + return retrieveData(element); + } + + protected abstract Iterable retrieveData(InputType element); + + private void incrementRetrievedDataAmount() { + retrievedDataAmountLock.lock(); + try { + retrievedDataAmount++; + } finally { + retrievedDataAmountLock.unlock(); + } + } + + @Override + protected void setAdditionalData(AdditionalResultDataBuilder additionalDataBuilder) { + additionalDataBuilder.setRetrievedDataAmount(retrievedDataAmount); + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleRetrievalProcessor.java new file mode 100644 index 00000000000..511f438e0f9 --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleRetrievalProcessor.java @@ -0,0 +1,20 @@ +package com.sap.sse.datamining.impl.components; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.components.Processor; + +public abstract class AbstractSimpleRetrievalProcessor extends + AbstractRetrievalProcessor { + + public AbstractSimpleRetrievalProcessor(ExecutorService executor, Collection> resultReceivers) { + super(executor, resultReceivers); + } + + @Override + protected ResultType convertWorkingToResultType(ResultType partialElement) { + return partialElement; + } + +} From 9aadec2ef256a0c4e50ae599c98cbd6f5e01e791 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 18:20:11 +0200 Subject: [PATCH 020/114] Adjusted the test for the LeaderboardGroupRetrievalProcessor --- ...stLeaderboardGroupRetrievalProcessor.java} | 43 ++++++------------- 1 file changed, 13 insertions(+), 30 deletions(-) rename java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/{TestLeaderboardGroupFilteringRetrievalProcessor.java => TestLeaderboardGroupRetrievalProcessor.java} (55%) diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java similarity index 55% rename from java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java rename to java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java index df0bc3bdf5a..d8bd0a07599 100644 --- a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/components/TestLeaderboardGroupRetrievalProcessor.java @@ -16,25 +16,20 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; -import com.sap.sailing.datamining.data.HasLeaderboardGroupContext; -import com.sap.sailing.datamining.data.LeaderboardGroupWithContext; -import com.sap.sailing.datamining.impl.data.HasLeaderboardGroupContextImpl; -import com.sap.sailing.datamining.impl.data.LeaderboardGroupWithContextImpl; import com.sap.sailing.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sailing.domain.leaderboard.Leaderboard; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.domain.leaderboard.impl.LeaderboardGroupImpl; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.AdditionalResultDataBuilder; -import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; -public class TestLeaderboardGroupFilteringRetrievalProcessor { +public class TestLeaderboardGroupRetrievalProcessor { private RacingEventService service; private Processor retriever; - private Collection retrievedGroups; + private Collection retrievedGroups; @Before public void initializeComponents() { @@ -42,9 +37,9 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { stub(service.getLeaderboardGroups()).toReturn(getGroupsInService()); retrievedGroups = new HashSet<>(); - Processor receiver = new Processor() { + Processor receiver = new Processor() { @Override - public void onElement(LeaderboardGroupWithContext element) { + public void onElement(LeaderboardGroup element) { retrievedGroups.add(element); } @Override @@ -62,14 +57,7 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { } }; - FilterCriteria criteria = new FilterCriteria() { - @Override - public boolean matches(LeaderboardGroupWithContext element) { - String name = element.getLeaderboardGroupName(); - return name == "LG1" || name == "LG2" || name == "LG3"; - } - }; - retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(receiver), criteria); + retriever = new LeaderboardGroupRetrievalProcessor(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(receiver)); } private Map getGroupsInService() { @@ -88,23 +76,18 @@ public class TestLeaderboardGroupFilteringRetrievalProcessor { retriever.onElement(service); retriever.finish(); - Collection expectedGroups = getExpectedRetrievedGroups(); + Collection expectedGroups = getExpectedRetrievedGroups(); assertThat(retrievedGroups, is(expectedGroups)); } - private Collection getExpectedRetrievedGroups() { - Collection groups = new HashSet<>(); - groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG1", "", false, new ArrayList()))); - groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG2", "", false, new ArrayList()))); - groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG3", "", false, new ArrayList()))); - groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG4", "", false, new ArrayList()))); - groups.add(groupToGroupWithContext(new LeaderboardGroupImpl("LG5", "", false, new ArrayList()))); + private Collection getExpectedRetrievedGroups() { + Collection groups = new HashSet<>(); + groups.add(new LeaderboardGroupImpl("LG1", "", false, new ArrayList())); + groups.add(new LeaderboardGroupImpl("LG2", "", false, new ArrayList())); + groups.add(new LeaderboardGroupImpl("LG3", "", false, new ArrayList())); + groups.add(new LeaderboardGroupImpl("LG4", "", false, new ArrayList())); + groups.add(new LeaderboardGroupImpl("LG5", "", false, new ArrayList())); return groups; } - private LeaderboardGroupWithContext groupToGroupWithContext(LeaderboardGroupImpl leaderboardGroup) { - HasLeaderboardGroupContext context = new HasLeaderboardGroupContextImpl(leaderboardGroup); - return new LeaderboardGroupWithContextImpl(context); - } - } From 5803bbed96b91c0f2478758742f807662d37786f Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 19:05:10 +0200 Subject: [PATCH 021/114] Implemented the retrieval till tracked races --- .../RegattaLeaderboardRetrievalProcessor.java | 33 ++++++++++++++ .../TrackedRaceRetrievalProcessor.java | 44 +++++++++++++++++++ ...ractSimpleFilteringRetrievalProcessor.java | 22 ++++++++++ 3 files changed, 99 insertions(+) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleFilteringRetrievalProcessor.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java new file mode 100644 index 00000000000..8bba1b7514f --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java @@ -0,0 +1,33 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.leaderboard.LeaderboardGroup; +import com.sap.sailing.domain.leaderboard.RegattaLeaderboard; +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; + +public class RegattaLeaderboardRetrievalProcessor extends + AbstractSimpleFilteringRetrievalProcessor { + + public RegattaLeaderboardRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, FilterCriteria criteria) { + super(executor, resultReceivers, criteria); + } + + @Override + protected Iterable retrieveData(LeaderboardGroup element) { + Collection regattaLeaderboards = new ArrayList<>(); + for (Leaderboard leaderboard : element.getLeaderboards()) { + if (leaderboard instanceof RegattaLeaderboard) { + regattaLeaderboards.add((RegattaLeaderboard) leaderboard); + } + } + return regattaLeaderboards; + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java new file mode 100644 index 00000000000..255463bf8dd --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java @@ -0,0 +1,44 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.datamining.data.HasTrackedRaceContext; +import com.sap.sailing.datamining.impl.data.HasTrackedRaceContextImpl; +import com.sap.sailing.domain.base.Event; +import com.sap.sailing.domain.base.Fleet; +import com.sap.sailing.domain.base.RaceColumn; +import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.leaderboard.Leaderboard; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; + +public class TrackedRaceRetrievalProcessor extends + AbstractSimpleFilteringRetrievalProcessor { + + public TrackedRaceRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, FilterCriteria criteria) { + super(executor, resultReceivers, criteria); + } + + @Override + protected Iterable retrieveData(Leaderboard element) { + Collection trackedRacesWithContext = new ArrayList<>(); + for (RaceColumn raceColumn : element.getRaceColumns()) { + for (Fleet fleet : raceColumn.getFleets()) { + TrackedRace trackedRace = raceColumn.getTrackedRace(fleet); + if (trackedRace != null) { + Regatta regatta = trackedRace.getTrackedRegatta().getRegatta(); + Event event = regatta.getEvent(); + HasTrackedRaceContext trackedRaceWithContext = new HasTrackedRaceContextImpl(event, regatta, fleet, trackedRace); + trackedRacesWithContext.add(trackedRaceWithContext); + } + } + } + return trackedRacesWithContext; + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleFilteringRetrievalProcessor.java new file mode 100644 index 00000000000..ae3443e2a0a --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/AbstractSimpleFilteringRetrievalProcessor.java @@ -0,0 +1,22 @@ +package com.sap.sse.datamining.impl.components; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; + +public abstract class AbstractSimpleFilteringRetrievalProcessor extends + AbstractFilteringRetrievalProcessor { + + public AbstractSimpleFilteringRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, FilterCriteria criteria) { + super(executor, resultReceivers, criteria); + } + + @Override + protected ResultType convertWorkingToResultType(ResultType partialElement) { + return partialElement; + } + +} From 98531afa8135a1bf9ae4670f1d121de47a294cc1 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 19:17:40 +0200 Subject: [PATCH 022/114] Implemented a rough retriever for tracked legs --- .../TrackedLegRetrievalProcessor.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java new file mode 100644 index 00000000000..7681b7e73bd --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java @@ -0,0 +1,32 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.datamining.data.HasTrackedLegContext; +import com.sap.sailing.datamining.impl.data.HasTrackedLegContextImpl; +import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sailing.domain.tracking.TrackedRace; +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; + +public class TrackedLegRetrievalProcessor extends + AbstractSimpleFilteringRetrievalProcessor { + + public TrackedLegRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, FilterCriteria criteria) { + super(executor, resultReceivers, criteria); + } + + @Override + protected Iterable retrieveData(TrackedRace element) { + int legNumber = 1; + for (TrackedLeg trackedLeg : element.getTrackedLegs()) { + //TODO find a way to push the previous context through the process chain + HasTrackedLegContext trackedLegWithContext = new HasTrackedLegContextImpl(trackedRaceContext, trackedLeg, legNumber); + } + return null; + } + +} From 1bc19d7fc87433aeb804952873575276969ff610 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 19:49:37 +0200 Subject: [PATCH 023/114] Implemented the retriever for tracked legs --- ...aderboardFilteringRetrievalProcessor.java} | 4 ++-- ...rackedLegFilteringRetrievalProcessor.java} | 21 +++++++++++-------- ...ackedRaceFilteringRetrievalProcessor.java} | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/{RegattaLeaderboardRetrievalProcessor.java => RegattaLeaderboardFilteringRetrievalProcessor.java} (89%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/{TrackedLegRetrievalProcessor.java => TrackedLegFilteringRetrievalProcessor.java} (51%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/{TrackedRaceRetrievalProcessor.java => TrackedRaceFilteringRetrievalProcessor.java} (93%) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardFilteringRetrievalProcessor.java similarity index 89% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardFilteringRetrievalProcessor.java index 8bba1b7514f..aec6c5ccd24 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/RegattaLeaderboardFilteringRetrievalProcessor.java @@ -11,10 +11,10 @@ import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; -public class RegattaLeaderboardRetrievalProcessor extends +public class RegattaLeaderboardFilteringRetrievalProcessor extends AbstractSimpleFilteringRetrievalProcessor { - public RegattaLeaderboardRetrievalProcessor(ExecutorService executor, + public RegattaLeaderboardFilteringRetrievalProcessor(ExecutorService executor, Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers, criteria); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java similarity index 51% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java index 7681b7e73bd..292101a4817 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java @@ -1,32 +1,35 @@ package com.sap.sailing.datamining.impl.components; +import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasTrackedLegContext; +import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.datamining.impl.data.HasTrackedLegContextImpl; import com.sap.sailing.domain.tracking.TrackedLeg; -import com.sap.sailing.domain.tracking.TrackedRace; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; -public class TrackedLegRetrievalProcessor extends - AbstractSimpleFilteringRetrievalProcessor { +public class TrackedLegFilteringRetrievalProcessor extends + AbstractSimpleFilteringRetrievalProcessor { - public TrackedLegRetrievalProcessor(ExecutorService executor, + public TrackedLegFilteringRetrievalProcessor(ExecutorService executor, Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers, criteria); } @Override - protected Iterable retrieveData(TrackedRace element) { + protected Iterable retrieveData(HasTrackedRaceContext element) { + Collection trackedLegsWithContext = new ArrayList<>(); int legNumber = 1; - for (TrackedLeg trackedLeg : element.getTrackedLegs()) { - //TODO find a way to push the previous context through the process chain - HasTrackedLegContext trackedLegWithContext = new HasTrackedLegContextImpl(trackedRaceContext, trackedLeg, legNumber); + for (TrackedLeg trackedLeg : element.getTrackedRace().getTrackedLegs()) { + HasTrackedLegContext trackedLegWithContext = new HasTrackedLegContextImpl(element, trackedLeg, legNumber); + trackedLegsWithContext.add(trackedLegWithContext); + legNumber++; } - return null; + return trackedLegsWithContext; } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java similarity index 93% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java index 255463bf8dd..04de3378a68 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java @@ -16,10 +16,10 @@ import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; -public class TrackedRaceRetrievalProcessor extends +public class TrackedRaceFilteringRetrievalProcessor extends AbstractSimpleFilteringRetrievalProcessor { - public TrackedRaceRetrievalProcessor(ExecutorService executor, + public TrackedRaceFilteringRetrievalProcessor(ExecutorService executor, Collection> resultReceivers, FilterCriteria criteria) { super(executor, resultReceivers, criteria); } From bf1386908ddd15a20f1caac56684ca40a9605f18 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 1 May 2014 20:16:32 +0200 Subject: [PATCH 024/114] Implemented the data retrieval chain (finally) --- .../datamining/data/HasGPSFixContext.java | 6 +++ .../HasTrackedLegOfCompetitorContext.java | 3 ++ .../components/GPSFixRetrievalProcessor.java | 42 +++++++++++++++++++ ...CompetitorFilteringRetrievalProcessor.java | 34 +++++++++++++++ .../impl/data/HasGPSFixContextImpl.java | 19 ++++++--- .../HasTrackedLegOfCompetitorContextImpl.java | 16 +++++-- 6 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasGPSFixContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasGPSFixContext.java index 475a425bfda..bdaad3464a2 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasGPSFixContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasGPSFixContext.java @@ -1,5 +1,11 @@ package com.sap.sailing.datamining.data; +import com.sap.sailing.domain.tracking.GPSFixMoving; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + public interface HasGPSFixContext extends HasTrackedLegOfCompetitorContext { + + @SideEffectFreeValue(messageKey="GPSFix") + public GPSFixMoving getGPSFix(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index 48b9ef20a42..f51929df0e2 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -1,9 +1,12 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasTrackedLegOfCompetitorContext extends HasTrackedLegContext { + + public TrackedLegOfCompetitor getTrackedLegOfCompetitor(); @SideEffectFreeValue(messageKey="Competitor") public Competitor getCompetitor(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java new file mode 100644 index 00000000000..18f62fbc048 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java @@ -0,0 +1,42 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.datamining.data.HasGPSFixContext; +import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; +import com.sap.sailing.datamining.impl.data.HasGPSFixContextImpl; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.tracking.GPSFixMoving; +import com.sap.sailing.domain.tracking.GPSFixTrack; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractSimpleRetrievalProcessor; + +public class GPSFixRetrievalProcessor extends AbstractSimpleRetrievalProcessor { + + public GPSFixRetrievalProcessor(ExecutorService executor, Collection> resultReceivers) { + super(executor, resultReceivers); + } + + @Override + protected Iterable retrieveData(HasTrackedLegOfCompetitorContext element) { + Collection gpsFixesWithContext = new ArrayList<>(); + GPSFixTrack competitorTrack = element.getTrackedRace().getTrack(element.getCompetitor()); + competitorTrack.lockForRead(); + try { + TrackedLegOfCompetitor trackedLegOfCompetitor = element.getTrackedLegOfCompetitor(); + if (trackedLegOfCompetitor.getStartTime() != null && trackedLegOfCompetitor.getFinishTime() != null) { + for (GPSFixMoving gpsFix : competitorTrack.getFixes(trackedLegOfCompetitor.getStartTime(), true, trackedLegOfCompetitor.getFinishTime(), true)) { + HasGPSFixContext gpsFixWithContext = new HasGPSFixContextImpl(element, gpsFix); + gpsFixesWithContext.add(gpsFixWithContext); + } + } + } finally { + competitorTrack.unlockAfterRead(); + } + return gpsFixesWithContext; + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java new file mode 100644 index 00000000000..668d1148e13 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java @@ -0,0 +1,34 @@ +package com.sap.sailing.datamining.impl.components; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.ExecutorService; + +import com.sap.sailing.datamining.data.HasTrackedLegContext; +import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; +import com.sap.sailing.datamining.impl.data.HasTrackedLegOfCompetitorContextImpl; +import com.sap.sailing.domain.base.Competitor; +import com.sap.sse.datamining.components.FilterCriteria; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; + +public class TrackedLegOfCompetitorFilteringRetrievalProcessor extends + AbstractSimpleFilteringRetrievalProcessor { + + public TrackedLegOfCompetitorFilteringRetrievalProcessor(ExecutorService executor, + Collection> resultReceivers, + FilterCriteria criteria) { + super(executor, resultReceivers, criteria); + } + + @Override + protected Iterable retrieveData(HasTrackedLegContext element) { + Collection trackedLegOfCompetitorsWithContext = new ArrayList<>(); + for (Competitor competitor : element.getRace().getCompetitors()) { + HasTrackedLegOfCompetitorContext trackedLegOfCompetitorWithContext = new HasTrackedLegOfCompetitorContextImpl(element, element.getTrackedLeg().getTrackedLeg(competitor)); + trackedLegOfCompetitorsWithContext.add(trackedLegOfCompetitorWithContext); + } + return trackedLegOfCompetitorsWithContext; + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java index 3336c570304..af648850a62 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java @@ -2,23 +2,32 @@ package com.sap.sailing.datamining.impl.data; import com.sap.sailing.datamining.data.HasGPSFixContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; public class HasGPSFixContextImpl extends HasTrackedLegOfCompetitorContextImpl implements HasGPSFixContext { - public HasGPSFixContextImpl(HasTrackedLegOfCompetitorContext legContext) { + private final GPSFixMoving gpsFix; + + public HasGPSFixContextImpl(HasTrackedLegOfCompetitorContext legContext, GPSFixMoving gpsFix) { this(legContext.getEvent(), legContext.getRegatta(), legContext.getFleet(), legContext.getTrackedRace(), - legContext.getTrackedLeg(), legContext.getLegNumber(), legContext.getCompetitor()); + legContext.getTrackedLeg(), legContext.getLegNumber(), legContext.getTrackedLegOfCompetitor(), gpsFix); } public HasGPSFixContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, - TrackedLeg trackedLeg, int legNumber, Competitor competitor) { - super(event, regatta, fleet, trackedRace, trackedLeg, legNumber, competitor); + TrackedLeg trackedLeg, int legNumber, TrackedLegOfCompetitor trackedLegOfCompetitor, GPSFixMoving gpsFix) { + super(event, regatta, fleet, trackedRace, trackedLeg, legNumber, trackedLegOfCompetitor); + this.gpsFix = gpsFix; + } + + @Override + public GPSFixMoving getGPSFix() { + return gpsFix; } } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java index b036034e760..baf025f4210 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java @@ -7,22 +7,30 @@ import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.tracking.TrackedLeg; +import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; public class HasTrackedLegOfCompetitorContextImpl extends HasTrackedLegContextImpl implements HasTrackedLegOfCompetitorContext { + private final TrackedLegOfCompetitor trackedLegOfCompetitor; private final Competitor competitor; - public HasTrackedLegOfCompetitorContextImpl(HasTrackedLegContext trackedLegContext, Competitor competitor) { + public HasTrackedLegOfCompetitorContextImpl(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) { this(trackedLegContext.getEvent(), trackedLegContext.getRegatta(), trackedLegContext.getFleet(), trackedLegContext.getTrackedRace(), trackedLegContext.getTrackedLeg(), - trackedLegContext.getLegNumber(), competitor); + trackedLegContext.getLegNumber(), trackedLegOfCompetitor); } public HasTrackedLegOfCompetitorContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, - TrackedLeg trackedLeg, int legNumber, Competitor competitor) { + TrackedLeg trackedLeg, int legNumber, TrackedLegOfCompetitor trackedLegOfCompetitor) { super(event, regatta, fleet, trackedRace, trackedLeg, legNumber); - this.competitor = competitor; + this.trackedLegOfCompetitor = trackedLegOfCompetitor; + this.competitor = trackedLegOfCompetitor.getCompetitor(); + } + + @Override + public TrackedLegOfCompetitor getTrackedLegOfCompetitor() { + return trackedLegOfCompetitor; } @Override From c79e9a82fda77ba767fa1b1d721b9111db4a4582 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 12:48:56 +0200 Subject: [PATCH 025/114] Adjusted the data class names --- ...on.java => QueryDefinitionDeprecated.java} | 2 +- .../shared/impl/SimpleQueryDefinition.java | 4 +- .../datamining/data/GPSFixWithContext.java | 52 ------------------ .../data/LeaderboardGroupWithContext.java | 10 ---- .../TrackedLegOfCompetitorWithContext.java | 54 ------------------- .../factories/DataMiningFactory.java | 6 +-- .../datamining/factories/GrouperFactory.java | 6 +-- .../components/GPSFixRetrievalProcessor.java | 4 +- .../LeaderboardGroupRetrievalProcessor.java | 9 +--- ...TrackedLegFilteringRetrievalProcessor.java | 4 +- ...CompetitorFilteringRetrievalProcessor.java | 4 +- ...rackedRaceFilteringRetrievalProcessor.java | 4 +- ...ctLeaderboardGroupDataRetrievalWorker.java | 8 +-- ...ixLeaderboardGroupDataRetrievalWorker.java | 4 +- ...DataMiningClassesWithFunctionsService.java | 12 +++-- ...ontextImpl.java => GPSFixWithContext.java} | 6 +-- ...=> TrackedLegOfCompetitorWithContext.java} | 6 +-- ...xtImpl.java => TrackedLegWithContext.java} | 6 +-- ...tImpl.java => TrackedRaceWithContext.java} | 4 +- .../datamining/client/DataMiningService.java | 4 +- .../client/DataMiningServiceAsync.java | 4 +- .../datamining/client/GroupingProvider.java | 4 +- .../QueryDefinitionChangedListener.java | 4 +- .../client/QueryDefinitionProvider.java | 8 +-- .../gwt/ui/datamining/client/QueryRunner.java | 4 +- .../datamining/client/SelectionProvider.java | 4 +- .../datamining/client/StatisticProvider.java | 4 +- .../client/execution/SimpleQueryRunner.java | 6 +-- .../AbstractQueryDefinitionProvider.java | 10 ++-- .../selection/ComplexStatisticProvider.java | 4 +- .../selection/GroupBySelectionPanel.java | 6 +-- .../QueryDefinitionProviderWithControls.java | 6 +-- .../RefreshingSelectionTablesPanel.java | 4 +- .../selection/RestrictedGroupingProvider.java | 4 +- .../gwt/ui/server/DataMiningServiceImpl.java | 12 ++--- .../datamining/impl/TestProcessorQuery.java | 8 +-- ...stAbstractFilteringRetrievalProcessor.java | 6 +-- .../components/TestFilteringProcessors.java | 1 - .../components/NonFilteringProcessor.java | 4 +- 39 files changed, 93 insertions(+), 219 deletions(-) rename java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/{QueryDefinition.java => QueryDefinitionDeprecated.java} (89%) delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/GPSFixWithContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java delete mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/TrackedLegOfCompetitorWithContext.java rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/{HasGPSFixContextImpl.java => GPSFixWithContext.java} (78%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/{HasTrackedLegOfCompetitorContextImpl.java => TrackedLegOfCompetitorWithContext.java} (78%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/{HasTrackedLegContextImpl.java => TrackedLegWithContext.java} (86%) rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/{HasTrackedRaceContextImpl.java => TrackedRaceWithContext.java} (92%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/{ => impl}/components/NonFilteringProcessor.java (85%) diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionDeprecated.java similarity index 89% rename from java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java rename to java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionDeprecated.java index 5f6548e13c9..f04ba8bfa8c 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionDeprecated.java @@ -7,7 +7,7 @@ import java.util.Map; import com.sap.sse.datamining.shared.components.AggregatorType; import com.sap.sse.datamining.shared.components.GrouperType; -public interface QueryDefinition extends Serializable { +public interface QueryDefinitionDeprecated extends Serializable { public String getLocaleInfoName(); diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java index 5547f158e17..06ab96432ea 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java @@ -8,12 +8,12 @@ import java.util.Map; import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sse.datamining.shared.components.AggregatorType; import com.sap.sse.datamining.shared.components.GrouperType; -public class SimpleQueryDefinition implements QueryDefinition { +public class SimpleQueryDefinition implements QueryDefinitionDeprecated { private static final long serialVersionUID = 8408302866342877839L; private String localeInfoName; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/GPSFixWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/GPSFixWithContext.java deleted file mode 100644 index 9eff07bbd22..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/GPSFixWithContext.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.datamining.WindStrengthCluster; -import com.sap.sailing.domain.common.LegType; -import com.sap.sailing.domain.tracking.GPSFixMoving; -import com.sap.sse.datamining.shared.annotations.Dimension; - -public interface GPSFixWithContext extends GPSFixMoving { - - @Dimension(messageKey="regatta") - public String getRegattaName(); - - @Dimension(messageKey="race") - public String getRaceName(); - - @Dimension(messageKey="legNumber") - public int getLegNumber(); - - @Dimension(messageKey="course") - public String getCourseAreaName(); - - @Dimension(messageKey="fleet") - public String getFleetName(); - - @Dimension(messageKey="boatClass") - public String getBoatClassName(); - - /** - * The year of the start of the race. - */ - @Dimension(messageKey="year") - public Integer getYear(); - - /** - * The leg type of the leg, which contains this gps fix. Can be null if there's no wind in the race. - */ - @Dimension(messageKey="legType") - public LegType getLegType(); - - @Dimension(messageKey="competitor") - public String getCompetitorName(); - - @Dimension(messageKey="sailID") - public String getCompetitorSailID(); - - @Dimension(messageKey="nationality") - public String getCompetitorNationality(); - - @Dimension(messageKey="windStrength") - public WindStrengthCluster getWindStrength(); - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java deleted file mode 100644 index 9ff5a9abeed..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/LeaderboardGroupWithContext.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sse.datamining.shared.annotations.Dimension; - -public interface LeaderboardGroupWithContext { - - @Dimension(messageKey="leaderboardGroup") - public String getLeaderboardGroupName(); - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/TrackedLegOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/TrackedLegOfCompetitorWithContext.java deleted file mode 100644 index 8499ce8d244..00000000000 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/TrackedLegOfCompetitorWithContext.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.sap.sailing.datamining.data; - -import com.sap.sailing.datamining.WindStrengthCluster; -import com.sap.sailing.domain.common.Distance; -import com.sap.sailing.domain.common.LegType; -import com.sap.sse.datamining.shared.Unit; -import com.sap.sse.datamining.shared.annotations.Dimension; -import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; - -public interface TrackedLegOfCompetitorWithContext { - - @Dimension(messageKey="regatta") - public String getRegattaName(); - - @Dimension(messageKey="race") - public String getRaceName(); - - @Dimension(messageKey="legNumber") - public int getLegNumber(); - - @Dimension(messageKey="course") - public String getCourseAreaName(); - - @Dimension(messageKey="fleet") - public String getFleetName(); - - @Dimension(messageKey="boatClass") - public String getBoatClassName(); - - /** - * The year of the start of the race. - */ - @Dimension(messageKey="year") - public Integer getYear(); - - @Dimension(messageKey="legType") - public LegType getLegType(); - - @Dimension(messageKey="competitor") - public String getCompetitorName(); - - @Dimension(messageKey="sailID") - public String getCompetitorSailID(); - - @Dimension(messageKey="nationality") - public String getCompetitorNationality(); - - @Dimension(messageKey="windStrength") - public WindStrengthCluster getWindStrength(); - - @SideEffectFreeValue(messageKey="distanceTraveled", resultUnit=Unit.Meters) - public Distance getDistanceTraveled(); - -} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java index 595fb46bfda..1ad601f6da8 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java @@ -2,7 +2,7 @@ package com.sap.sailing.datamining.factories; import java.util.Locale; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.Query; import com.sap.sse.datamining.components.ParallelAggregator; @@ -23,7 +23,7 @@ public final class DataMiningFactory { } public static Query createQuery( - QueryDefinition queryDefinition, RacingEventService racingService) { + QueryDefinitionDeprecated queryDefinition, RacingEventService racingService) { Locale locale = DataMiningStringMessages.Util.getLocaleFrom(queryDefinition.getLocaleInfoName()); ParallelDataRetriever retriever = DataRetrieverFactory.createDataRetriever( @@ -44,7 +44,7 @@ public final class DataMiningFactory { retriever, filter, grouper, extractor, aggregator); } - private static ParallelFilter createFilter(QueryDefinition queryDefinition) { + private static ParallelFilter createFilter(QueryDefinitionDeprecated queryDefinition) { if (queryDefinition.getSelection().isEmpty()) { return FilterFactory.createNonFilteringFilter(); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/GrouperFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/GrouperFactory.java index f2b28b311e7..2dc31ec2a59 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/GrouperFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/GrouperFactory.java @@ -9,7 +9,7 @@ import com.sap.sailing.datamining.dimensions.DimensionManager; import com.sap.sailing.datamining.dimensions.DimensionManagerProvider; import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sse.datamining.components.ParallelGrouper; import com.sap.sse.datamining.data.deprecated.Dimension; import com.sap.sse.datamining.impl.components.deprecated.PartitioningParallelGrouper; @@ -21,12 +21,12 @@ public final class GrouperFactory { private GrouperFactory() { } - public static ParallelGrouper createGrouper(QueryDefinition queryDefinition, ThreadPoolExecutor executor) { + public static ParallelGrouper createGrouper(QueryDefinitionDeprecated queryDefinition, ThreadPoolExecutor executor) { WorkerBuilder> workerBuilder = createGroupingWorkerBuilder(queryDefinition); return new PartitioningParallelGrouper(workerBuilder, executor); } - private static WorkerBuilder> createGroupingWorkerBuilder(QueryDefinition queryDefinition) { + private static WorkerBuilder> createGroupingWorkerBuilder(QueryDefinitionDeprecated queryDefinition) { switch (queryDefinition.getGrouperType()) { case Dimensions: return createMultiDimensionalGroupingWorkerBuilder(queryDefinition.getDataType(), queryDefinition.getDimensionsToGroupBy()); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java index 18f62fbc048..30c2b51a2ad 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/GPSFixRetrievalProcessor.java @@ -6,7 +6,7 @@ import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasGPSFixContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.datamining.impl.data.HasGPSFixContextImpl; +import com.sap.sailing.datamining.impl.data.GPSFixWithContext; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.tracking.GPSFixMoving; import com.sap.sailing.domain.tracking.GPSFixTrack; @@ -29,7 +29,7 @@ public class GPSFixRetrievalProcessor extends AbstractSimpleRetrievalProcessor { + AbstractSimpleRetrievalProcessor { public LeaderboardGroupRetrievalProcessor(ExecutorService executor, Collection> resultReceivers) { super(executor, resultReceivers); } - @Override - protected LeaderboardGroup convertWorkingToResultType(LeaderboardGroup partialElement) { - return partialElement; - } - @Override protected Iterable retrieveData(RacingEventService element) { return element.getLeaderboardGroups().values(); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java index 292101a4817..8e379a2bb78 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegFilteringRetrievalProcessor.java @@ -6,7 +6,7 @@ import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; -import com.sap.sailing.datamining.impl.data.HasTrackedLegContextImpl; +import com.sap.sailing.datamining.impl.data.TrackedLegWithContext; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; @@ -25,7 +25,7 @@ public class TrackedLegFilteringRetrievalProcessor extends Collection trackedLegsWithContext = new ArrayList<>(); int legNumber = 1; for (TrackedLeg trackedLeg : element.getTrackedRace().getTrackedLegs()) { - HasTrackedLegContext trackedLegWithContext = new HasTrackedLegContextImpl(element, trackedLeg, legNumber); + HasTrackedLegContext trackedLegWithContext = new TrackedLegWithContext(element, trackedLeg, legNumber); trackedLegsWithContext.add(trackedLegWithContext); legNumber++; } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java index 668d1148e13..9abafa3b7df 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedLegOfCompetitorFilteringRetrievalProcessor.java @@ -6,7 +6,7 @@ import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.datamining.impl.data.HasTrackedLegOfCompetitorContextImpl; +import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithContext; import com.sap.sailing.domain.base.Competitor; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; @@ -25,7 +25,7 @@ public class TrackedLegOfCompetitorFilteringRetrievalProcessor extends protected Iterable retrieveData(HasTrackedLegContext element) { Collection trackedLegOfCompetitorsWithContext = new ArrayList<>(); for (Competitor competitor : element.getRace().getCompetitors()) { - HasTrackedLegOfCompetitorContext trackedLegOfCompetitorWithContext = new HasTrackedLegOfCompetitorContextImpl(element, element.getTrackedLeg().getTrackedLeg(competitor)); + HasTrackedLegOfCompetitorContext trackedLegOfCompetitorWithContext = new TrackedLegOfCompetitorWithContext(element, element.getTrackedLeg().getTrackedLeg(competitor)); trackedLegOfCompetitorsWithContext.add(trackedLegOfCompetitorWithContext); } return trackedLegOfCompetitorsWithContext; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java index 04de3378a68..3c69164c014 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/TrackedRaceFilteringRetrievalProcessor.java @@ -5,7 +5,7 @@ import java.util.Collection; import java.util.concurrent.ExecutorService; import com.sap.sailing.datamining.data.HasTrackedRaceContext; -import com.sap.sailing.datamining.impl.data.HasTrackedRaceContextImpl; +import com.sap.sailing.datamining.impl.data.TrackedRaceWithContext; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.RaceColumn; @@ -33,7 +33,7 @@ public class TrackedRaceFilteringRetrievalProcessor extends if (trackedRace != null) { Regatta regatta = trackedRace.getTrackedRegatta().getRegatta(); Event event = regatta.getEvent(); - HasTrackedRaceContext trackedRaceWithContext = new HasTrackedRaceContextImpl(event, regatta, fleet, trackedRace); + HasTrackedRaceContext trackedRaceWithContext = new TrackedRaceWithContext(event, regatta, fleet, trackedRace); trackedRacesWithContext.add(trackedRaceWithContext); } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java index 2f9efa48d50..6288db145a6 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/AbstractLeaderboardGroupDataRetrievalWorker.java @@ -5,8 +5,8 @@ import java.util.Collection; import com.sap.sailing.datamining.data.HasTrackedLegContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.datamining.impl.data.HasTrackedLegContextImpl; -import com.sap.sailing.datamining.impl.data.HasTrackedLegOfCompetitorContextImpl; +import com.sap.sailing.datamining.impl.data.TrackedLegWithContext; +import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithContext; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.CourseArea; import com.sap.sailing.domain.base.Fleet; @@ -48,7 +48,7 @@ public abstract class AbstractLeaderboardGroupDataRetrievalWorker for (Leg leg : trackedRace.getRace().getCourse().getLegs()) { TrackedLeg trackedLeg = trackedRace.getTrackedLeg(leg); if (trackedLeg != null) { - HasTrackedLegContext dataContext = new HasTrackedLegContextImpl(group, leaderboard, + HasTrackedLegContext dataContext = new TrackedLegWithContext(group, leaderboard, courseArea, fleet, trackedRace, trackedLeg, legNumber); data.add(new Pair(trackedLeg, dataContext)); legNumber++; @@ -70,7 +70,7 @@ public abstract class AbstractLeaderboardGroupDataRetrievalWorker HasTrackedLegContext trackedLegContext = baseDataEntry.getB(); for (Competitor competitor : trackedLegContext.getRace().getCompetitors()) { TrackedLegOfCompetitor trackedLegOfCompetitor = trackedLeg.getTrackedLeg(competitor); - HasTrackedLegOfCompetitorContext dataContext = new HasTrackedLegOfCompetitorContextImpl(trackedLegContext, + HasTrackedLegOfCompetitorContext dataContext = new TrackedLegOfCompetitorWithContext(trackedLegContext, competitor); data.add(new Pair(trackedLegOfCompetitor, dataContext)); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java index 6b1bb97f045..5eb4a26e43e 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/components/deprecated/GPSFixLeaderboardGroupDataRetrievalWorker.java @@ -7,7 +7,7 @@ import java.util.List; import com.sap.sailing.datamining.data.HasGPSFixContext; import com.sap.sailing.datamining.data.GPSFixWithContext; import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; -import com.sap.sailing.datamining.impl.data.HasGPSFixContextImpl; +import com.sap.sailing.datamining.impl.data.GPSFixWithContext; import com.sap.sailing.datamining.impl.gps_fix.GPSFixWithContextImpl; import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.common.impl.Util.Pair; @@ -22,7 +22,7 @@ public class GPSFixLeaderboardGroupDataRetrievalWorker extends AbstractLeaderboa Collection data = new ArrayList(); Collection> baseData = retrieveDataTillTrackedLegOfCompetitor(getGroup()); for (Pair baseDataEntry : baseData) { - HasGPSFixContext context = new HasGPSFixContextImpl(baseDataEntry.getB()); + HasGPSFixContext context = new GPSFixWithContext(baseDataEntry.getB()); data.addAll(retrieveDataFor(context)); } return data; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java index 29c67938a58..ab7b3c1cd20 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java @@ -3,8 +3,10 @@ package com.sap.sailing.datamining.impl.data; import java.util.HashSet; import java.util.Set; -import com.sap.sailing.datamining.data.GPSFixWithContext; -import com.sap.sailing.datamining.data.TrackedLegOfCompetitorWithContext; +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.sse.datamining.functions.ClassesWithFunctionsService; public class DataMiningClassesWithFunctionsService implements ClassesWithFunctionsService { @@ -12,8 +14,10 @@ public class DataMiningClassesWithFunctionsService implements ClassesWithFunctio @Override public Set> getInternalClassesWithMarkedMethods() { Set> internalClasses = new HashSet<>(); - internalClasses.add(GPSFixWithContext.class); - internalClasses.add(TrackedLegOfCompetitorWithContext.class); + internalClasses.add(HasTrackedRaceContext.class); + internalClasses.add(HasTrackedLegContext.class); + internalClasses.add(HasTrackedLegOfCompetitorContext.class); + internalClasses.add(HasGPSFixContext.class); return internalClasses; } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java similarity index 78% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java index af648850a62..2b51b4bbd3b 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasGPSFixContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/GPSFixWithContext.java @@ -10,16 +10,16 @@ import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; -public class HasGPSFixContextImpl extends HasTrackedLegOfCompetitorContextImpl implements HasGPSFixContext { +public class GPSFixWithContext extends TrackedLegOfCompetitorWithContext implements HasGPSFixContext { private final GPSFixMoving gpsFix; - public HasGPSFixContextImpl(HasTrackedLegOfCompetitorContext legContext, GPSFixMoving gpsFix) { + public GPSFixWithContext(HasTrackedLegOfCompetitorContext legContext, GPSFixMoving gpsFix) { this(legContext.getEvent(), legContext.getRegatta(), legContext.getFleet(), legContext.getTrackedRace(), legContext.getTrackedLeg(), legContext.getLegNumber(), legContext.getTrackedLegOfCompetitor(), gpsFix); } - public HasGPSFixContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, + public GPSFixWithContext(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber, TrackedLegOfCompetitor trackedLegOfCompetitor, GPSFixMoving gpsFix) { super(event, regatta, fleet, trackedRace, trackedLeg, legNumber, trackedLegOfCompetitor); this.gpsFix = gpsFix; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java similarity index 78% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java index baf025f4210..39cdfacec06 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegOfCompetitorContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java @@ -10,18 +10,18 @@ import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; -public class HasTrackedLegOfCompetitorContextImpl extends HasTrackedLegContextImpl implements HasTrackedLegOfCompetitorContext { +public class TrackedLegOfCompetitorWithContext extends TrackedLegWithContext implements HasTrackedLegOfCompetitorContext { private final TrackedLegOfCompetitor trackedLegOfCompetitor; private final Competitor competitor; - public HasTrackedLegOfCompetitorContextImpl(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) { + public TrackedLegOfCompetitorWithContext(HasTrackedLegContext trackedLegContext, TrackedLegOfCompetitor trackedLegOfCompetitor) { this(trackedLegContext.getEvent(), trackedLegContext.getRegatta(), trackedLegContext.getFleet(), trackedLegContext.getTrackedRace(), trackedLegContext.getTrackedLeg(), trackedLegContext.getLegNumber(), trackedLegOfCompetitor); } - public HasTrackedLegOfCompetitorContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, + public TrackedLegOfCompetitorWithContext(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber, TrackedLegOfCompetitor trackedLegOfCompetitor) { super(event, regatta, fleet, trackedRace, trackedLeg, legNumber); this.trackedLegOfCompetitor = trackedLegOfCompetitor; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegWithContext.java similarity index 86% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegWithContext.java index 52e89b6e6b0..64d1e38e685 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedLegContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegWithContext.java @@ -13,19 +13,19 @@ import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; -public class HasTrackedLegContextImpl extends HasTrackedRaceContextImpl implements HasTrackedLegContext { +public class TrackedLegWithContext extends TrackedRaceWithContext implements HasTrackedLegContext { private final TrackedLeg trackedLeg; private final int legNumber; private LegType legType; private boolean legTypeHasBeenInitialized; - public HasTrackedLegContextImpl(HasTrackedRaceContext trackedRaceContext, TrackedLeg trackedLeg, int legNumber) { + public TrackedLegWithContext(HasTrackedRaceContext trackedRaceContext, TrackedLeg trackedLeg, int legNumber) { this(trackedRaceContext.getEvent(), trackedRaceContext.getRegatta(), trackedRaceContext.getFleet(), trackedRaceContext.getTrackedRace(), trackedLeg, legNumber); } - public HasTrackedLegContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber) { + public TrackedLegWithContext(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace, TrackedLeg trackedLeg, int legNumber) { super(event, regatta, fleet, trackedRace); this.trackedLeg = trackedLeg; this.legNumber = legNumber; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java similarity index 92% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java index c644ef69593..95cea419c44 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/HasTrackedRaceContextImpl.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedRaceWithContext.java @@ -12,7 +12,7 @@ import com.sap.sailing.domain.base.Regatta; import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.tracking.TrackedRace; -public class HasTrackedRaceContextImpl implements HasTrackedRaceContext { +public class TrackedRaceWithContext implements HasTrackedRaceContext { private final Event event; private final Regatta regatta; @@ -21,7 +21,7 @@ public class HasTrackedRaceContextImpl implements HasTrackedRaceContext { private Integer year; private boolean yearHasBeenInitialized; - public HasTrackedRaceContextImpl(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace) { + public TrackedRaceWithContext(Event event, Regatta regatta, Fleet fleet, TrackedRace trackedRace) { this.event = event; this.regatta = regatta; this.fleet = fleet; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningService.java index ce6f83a8213..484b0cb7c60 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningService.java @@ -4,7 +4,7 @@ import java.util.Collection; import com.google.gwt.user.client.rpc.RemoteService; import com.sap.sailing.datamining.shared.DataTypes; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sse.datamining.shared.DataMiningSerializationDummy; import com.sap.sse.datamining.shared.QueryResult; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -13,7 +13,7 @@ public interface DataMiningService extends RemoteService { Collection getDimensionsFor(DataTypes dataType); - QueryResult runQuery(QueryDefinition queryDefinition) throws Exception; + QueryResult runQuery(QueryDefinitionDeprecated queryDefinition) throws Exception; DataMiningSerializationDummy pseudoMethodSoThatSomeDataMiningClassesAreAddedToTheGWTSerializationPolicy(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningServiceAsync.java index 7ede7c5f667..22b40c21461 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningServiceAsync.java @@ -4,7 +4,7 @@ import java.util.Collection; import com.google.gwt.user.client.rpc.AsyncCallback; import com.sap.sailing.datamining.shared.DataTypes; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sse.datamining.shared.DataMiningSerializationDummy; import com.sap.sse.datamining.shared.QueryResult; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -13,7 +13,7 @@ public interface DataMiningServiceAsync { void getDimensionsFor(DataTypes dataType, AsyncCallback> callback); - void runQuery(QueryDefinition queryDefinition, AsyncCallback> callback); + void runQuery(QueryDefinitionDeprecated queryDefinition, AsyncCallback> callback); /** * This method does nothing, but is needed to ensure, that GenericGroupKey<String> in the GWT serialization policy.
diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/GroupingProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/GroupingProvider.java index 88ff9ef88c2..800f67090f8 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/GroupingProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/GroupingProvider.java @@ -3,7 +3,7 @@ package com.sap.sailing.gwt.ui.datamining.client; import java.util.Collection; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.shared.components.Component; import com.sap.sse.datamining.shared.components.GrouperType; @@ -14,7 +14,7 @@ public interface GroupingProvider extends Component { public Collection getDimensionsToGroupBy(); public String getCustomGrouperScriptText(); - public void applyQueryDefinition(QueryDefinition queryDefinition); + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition); public void addGroupingChangedListener(GroupingChangedListener listener); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionChangedListener.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionChangedListener.java index 8ebae367469..7f0d3beb112 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionChangedListener.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionChangedListener.java @@ -1,9 +1,9 @@ package com.sap.sailing.gwt.ui.datamining.client; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; public interface QueryDefinitionChangedListener { - void queryDefinitionChanged(QueryDefinition newQueryDefinition); + void queryDefinitionChanged(QueryDefinitionDeprecated newQueryDefinition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionProvider.java index 3ca6d80c975..265e071237a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryDefinitionProvider.java @@ -1,13 +1,13 @@ package com.sap.sailing.gwt.ui.datamining.client; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.shared.components.Component; public interface QueryDefinitionProvider extends Component { - public Iterable validateQueryDefinition(QueryDefinition queryDefinition); - public QueryDefinition getQueryDefinition(); - public void applyQueryDefinition(QueryDefinition queryDefinition); + public Iterable validateQueryDefinition(QueryDefinitionDeprecated queryDefinition); + public QueryDefinitionDeprecated getQueryDefinition(); + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition); public void addQueryDefinitionChangedListener(QueryDefinitionChangedListener listener); public void removeQueryDefinitionChangedListener(QueryDefinitionChangedListener listener); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryRunner.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryRunner.java index eb49e21d441..de6ea600ee9 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryRunner.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/QueryRunner.java @@ -1,11 +1,11 @@ package com.sap.sailing.gwt.ui.datamining.client; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.shared.components.Component; import com.sap.sailing.gwt.ui.datamining.client.settings.QueryRunnerSettings; public interface QueryRunner extends QueryDefinitionChangedListener, Component { - public void run(QueryDefinition queryDefinition); + public void run(QueryDefinitionDeprecated queryDefinition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/SelectionProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/SelectionProvider.java index 1acaf20a9c1..309303bd5aa 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/SelectionProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/SelectionProvider.java @@ -4,7 +4,7 @@ import java.util.Collection; import java.util.Map; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.shared.components.Component; public interface SelectionProvider extends Component { @@ -13,7 +13,7 @@ public interface SelectionProvider extends Component public Map> getSelection(); - public void applySelection(QueryDefinition queryDefinition); + public void applySelection(QueryDefinitionDeprecated queryDefinition); public void clearSelection(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/StatisticProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/StatisticProvider.java index 3680b34687c..124f6b55238 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/StatisticProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/StatisticProvider.java @@ -1,7 +1,7 @@ package com.sap.sailing.gwt.ui.datamining.client; import com.sap.sailing.datamining.shared.DataTypes; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sailing.gwt.ui.client.shared.components.Component; import com.sap.sailing.gwt.ui.datamining.client.selection.SimpleStatistic; @@ -16,6 +16,6 @@ public interface StatisticProvider extends Component { public void addStatisticChangedListener(StatisticChangedListener listener); - public void applyQueryDefinition(QueryDefinition queryDefinition); + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/execution/SimpleQueryRunner.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/execution/SimpleQueryRunner.java index c275bdb5052..a76eee2a89b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/execution/SimpleQueryRunner.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/execution/SimpleQueryRunner.java @@ -5,7 +5,7 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; 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; @@ -54,7 +54,7 @@ public class SimpleQueryRunner implements QueryRunner { } @Override - public void run(QueryDefinition queryDefinition) { + public void run(QueryDefinitionDeprecated queryDefinition) { Iterable errorMessages = queryDefinitionProvider.validateQueryDefinition(queryDefinition); if (errorMessages == null || !errorMessages.iterator().hasNext()) { // queryStatusLabel.setText(" | " + stringMessages.running()); @@ -89,7 +89,7 @@ public class SimpleQueryRunner implements QueryRunner { } @Override - public void queryDefinitionChanged(QueryDefinition newQueryDefinition) { + public void queryDefinitionChanged(QueryDefinitionDeprecated newQueryDefinition) { run(newQueryDefinition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/AbstractQueryDefinitionProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/AbstractQueryDefinitionProvider.java index 3d39d762474..6c018654cc3 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/AbstractQueryDefinitionProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/AbstractQueryDefinitionProvider.java @@ -6,7 +6,7 @@ import java.util.HashSet; import java.util.Set; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -34,7 +34,7 @@ public abstract class AbstractQueryDefinitionProvider implements QueryDefinition } @Override - public Iterable validateQueryDefinition(QueryDefinition queryDefinition) { + public Iterable validateQueryDefinition(QueryDefinitionDeprecated queryDefinition) { Collection errorMessages = new ArrayList(); if (queryDefinition != null) { @@ -51,7 +51,7 @@ public abstract class AbstractQueryDefinitionProvider implements QueryDefinition return errorMessages; } - private String validateGrouper(QueryDefinition queryDefinition) { + private String validateGrouper(QueryDefinitionDeprecated queryDefinition) { GrouperType grouper = queryDefinition.getGrouperType(); if (grouper == null) { return stringMessages.noGrouperSelectedError(); @@ -72,7 +72,7 @@ public abstract class AbstractQueryDefinitionProvider implements QueryDefinition return null; } - private String validateStatisticAndAggregator(QueryDefinition queryDefinition) { + private String validateStatisticAndAggregator(QueryDefinitionDeprecated queryDefinition) { return queryDefinition.getStatisticType() == null || queryDefinition.getAggregatorType() == null ? stringMessages.noStatisticSelectedError() : null; } @@ -92,7 +92,7 @@ public abstract class AbstractQueryDefinitionProvider implements QueryDefinition protected void notifyQueryDefinitionChanged() { if (!blockChangeNotification) { - QueryDefinition queryDefinition = getQueryDefinition(); + QueryDefinitionDeprecated queryDefinition = getQueryDefinition(); for (QueryDefinitionChangedListener listener : listeners) { listener.queryDefinitionChanged(queryDefinition); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/ComplexStatisticProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/ComplexStatisticProvider.java index 73072c3a201..1acb7ab9696 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/ComplexStatisticProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/ComplexStatisticProvider.java @@ -11,7 +11,7 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DataTypes; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent; @@ -108,7 +108,7 @@ public class ComplexStatisticProvider implements StatisticProvider { } @Override - public void applyQueryDefinition(QueryDefinition queryDefinition) { + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition) { applyStatistic(statisticsManager.getStatistic(queryDefinition.getDataType())); aggregatorListBox.setValue(queryDefinition.getAggregatorType(), false); dataTypeListBox.setValue(queryDefinition.getDataType(), false); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/GroupBySelectionPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/GroupBySelectionPanel.java index 7ca31cbe5e2..af38d5aea30 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/GroupBySelectionPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/GroupBySelectionPanel.java @@ -15,7 +15,7 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sse.datamining.shared.components.GrouperType; @@ -42,7 +42,7 @@ public abstract class GroupBySelectionPanel extends FlowPanel { dimensionsToGroupByBoxes.add(dimensionToGroupByBox); } - public void apply(QueryDefinition queryDefinition) { + public void apply(QueryDefinitionDeprecated queryDefinition) { grouperTypeListBox.setValue(queryDefinition.getGrouperType(), true); switch (queryDefinition.getGrouperType()) { @@ -54,7 +54,7 @@ public abstract class GroupBySelectionPanel extends FlowPanel { } } - private void applyDimensionsToGroupBy(QueryDefinition queryDefinition) { + private void applyDimensionsToGroupBy(QueryDefinitionDeprecated queryDefinition) { int index = 0; for (DimensionIdentifier dimension : queryDefinition.getDimensionsToGroupBy()) { dimensionsToGroupByBoxes.get(index).setValue(dimension, true); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java index 74205db1ac6..235d4ea290c 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java @@ -12,7 +12,7 @@ import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.datamining.shared.impl.SimpleQueryDefinition; import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; @@ -65,7 +65,7 @@ public class QueryDefinitionProviderWithControls extends AbstractQueryDefinition } @Override - public QueryDefinition getQueryDefinition() { + public QueryDefinitionDeprecated getQueryDefinition() { SimpleQueryDefinition queryDTO = new SimpleQueryDefinition(LocaleInfo.getCurrentLocale().getLocaleName(), groupBySelectionPanel.getGrouperType(), statisticProvider.getStatisticType(), statisticProvider.getAggregatorType(), statisticProvider.getDataType()); @@ -87,7 +87,7 @@ public class QueryDefinitionProviderWithControls extends AbstractQueryDefinition } @Override - public void applyQueryDefinition(QueryDefinition queryDefinition) { + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition) { setBlockChangeNotification(true); selectionProvider.applySelection(queryDefinition); groupBySelectionPanel.applyQueryDefinition(queryDefinition); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RefreshingSelectionTablesPanel.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RefreshingSelectionTablesPanel.java index 78f58c4bd4f..a506e751c97 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RefreshingSelectionTablesPanel.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RefreshingSelectionTablesPanel.java @@ -23,7 +23,7 @@ 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.datamining.shared.DimensionIdentifier; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.domain.common.LegType; import com.sap.sailing.domain.common.TrackedRaceStatusEnum; import com.sap.sailing.domain.common.dto.BoatClassDTO; @@ -139,7 +139,7 @@ public class RefreshingSelectionTablesPanel implements SelectionProvider> selectionEntry : queryDefinition.getSelection().entrySet()) { SelectionTable selectionTable = tablesMappedByDimension.get(selectionEntry.getKey()); selectionTable.setSelection((Iterable) selectionEntry.getValue()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RestrictedGroupingProvider.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RestrictedGroupingProvider.java index ef6bbd69f42..eeb5044ea14 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RestrictedGroupingProvider.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/RestrictedGroupingProvider.java @@ -16,7 +16,7 @@ import com.google.gwt.user.client.ui.ValueListBox; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.DimensionIdentifier.OrdinalComparator; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent; import com.sap.sailing.gwt.ui.client.shared.components.SimpleValueListBox; @@ -105,7 +105,7 @@ public class RestrictedGroupingProvider implements GroupingProvider { } @Override - public void applyQueryDefinition(QueryDefinition queryDefinition) { + public void applyQueryDefinition(QueryDefinitionDeprecated queryDefinition) { if (queryDefinition.getGrouperType() == GrouperType.Dimensions) { int index = 0; for (DimensionIdentifier dimension : queryDefinition.getDimensionsToGroupBy()) { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java index 701f33c69ee..84c377d49c6 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/DataMiningServiceImpl.java @@ -7,11 +7,11 @@ import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; import com.google.gwt.user.server.rpc.RemoteServiceServlet; -import com.sap.sailing.datamining.data.GPSFixWithContext; -import com.sap.sailing.datamining.data.TrackedLegOfCompetitorWithContext; +import com.sap.sailing.datamining.data.HasGPSFixContext; +import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.factories.DataMiningFactory; import com.sap.sailing.datamining.shared.DataTypes; -import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.gwt.ui.datamining.client.DataMiningService; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.DataMiningServer; @@ -70,9 +70,9 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM private Class getBaseClassFor(DataTypes dataType) { switch (dataType) { case GPSFix: - return GPSFixWithContext.class; + return HasGPSFixContext.class; case TrackedLegOfCompetitor: - return TrackedLegOfCompetitorWithContext.class; + return HasTrackedLegOfCompetitorContext.class; } throw new IllegalArgumentException("No base class for data type " + dataType); } @@ -86,7 +86,7 @@ public class DataMiningServiceImpl extends RemoteServiceServlet implements DataM } @Override - public QueryResult runQuery(QueryDefinition queryDefinition) throws Exception { + public QueryResult runQuery(QueryDefinitionDeprecated queryDefinition) throws Exception { Query query = DataMiningFactory.createQuery(queryDefinition, getRacingEventService()); return query.run(); } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java index 2d3c0451976..7a47a64d955 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/TestProcessorQuery.java @@ -26,7 +26,7 @@ import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.i18n.DataMiningStringMessages; -import com.sap.sse.datamining.impl.components.AbstractFilteringRetrievalProcessor; +import com.sap.sse.datamining.impl.components.AbstractSimpleFilteringRetrievalProcessor; import com.sap.sse.datamining.impl.components.AbstractSimpleParallelProcessor; import com.sap.sse.datamining.impl.components.GroupedDataEntry; import com.sap.sse.datamining.impl.components.ParallelGroupedElementsValueExtractionProcessor; @@ -122,15 +122,11 @@ public class TestProcessorQuery { return element.getValue() >= 10; } }; - Processor> filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Number, Number>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(lengthGrouper), retrievalFilterCriteria) { + Processor> filteringRetrievalProcessor = new AbstractSimpleFilteringRetrievalProcessor, Number>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(lengthGrouper), retrievalFilterCriteria) { @Override protected Iterable retrieveData(Iterable element) { return element; } - @Override - protected Number contextifyElement(Number partialElement) { - return partialElement; - } }; query.setFirstProcessor(filteringRetrievalProcessor); diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java index 35b635ac1e3..28e88a5a744 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestAbstractFilteringRetrievalProcessor.java @@ -77,15 +77,11 @@ public class TestAbstractFilteringRetrievalProcessor { return element >= 0; } }; - filteringRetrievalProcessor = new AbstractFilteringRetrievalProcessor, Integer, Integer>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(resultReceiver), filterCriteria) { + filteringRetrievalProcessor = new AbstractSimpleFilteringRetrievalProcessor, Integer>(ConcurrencyTestsUtil.getExecutor(), Arrays.asList(resultReceiver), filterCriteria) { @Override protected Iterable retrieveData(Iterable element) { return element; } - @Override - protected Integer contextifyElement(Integer partialElement) { - return partialElement; - } }; } diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java index 05c52e65707..6e175bb124e 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/components/TestFilteringProcessors.java @@ -14,7 +14,6 @@ import org.junit.Test; import com.sap.sse.datamining.AdditionalResultDataBuilder; import com.sap.sse.datamining.components.FilterCriteria; -import com.sap.sse.datamining.components.NonFilteringProcessor; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/NonFilteringProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/NonFilteringProcessor.java similarity index 85% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/NonFilteringProcessor.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/NonFilteringProcessor.java index 94712a73f05..03b2c984e24 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/components/NonFilteringProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/components/NonFilteringProcessor.java @@ -1,9 +1,9 @@ -package com.sap.sse.datamining.components; +package com.sap.sse.datamining.impl.components; import java.util.Collection; import com.sap.sse.datamining.AdditionalResultDataBuilder; -import com.sap.sse.datamining.impl.components.AbstractProcessor; +import com.sap.sse.datamining.components.Processor; public class NonFilteringProcessor extends AbstractProcessor { From 46cfee5157de5c0f106953380ec5151a47076468 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 13:15:01 +0200 Subject: [PATCH 026/114] Renamed the deprecated QueryDefinition --- ...ryDefinition.java => QueryDefinitionDeprecatedImpl.java} | 6 +++--- .../gwt/ui/datamining/client/DataMiningEntryPoint.java | 4 ++-- .../selection/QueryDefinitionProviderWithControls.java | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/{SimpleQueryDefinition.java => QueryDefinitionDeprecatedImpl.java} (89%) diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionDeprecatedImpl.java similarity index 89% rename from java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java rename to java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionDeprecatedImpl.java index 06ab96432ea..03a8c2c60f7 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/SimpleQueryDefinition.java +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionDeprecatedImpl.java @@ -13,7 +13,7 @@ import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sse.datamining.shared.components.AggregatorType; import com.sap.sse.datamining.shared.components.GrouperType; -public class SimpleQueryDefinition implements QueryDefinitionDeprecated { +public class QueryDefinitionDeprecatedImpl implements QueryDefinitionDeprecated { private static final long serialVersionUID = 8408302866342877839L; private String localeInfoName; @@ -30,9 +30,9 @@ public class SimpleQueryDefinition implements QueryDefinitionDeprecated { * Constructor for the GWT-Serialization. Don't use this! */ @Deprecated - SimpleQueryDefinition() { } + QueryDefinitionDeprecatedImpl() { } - public SimpleQueryDefinition(String localeInfoName, GrouperType grouperType, StatisticType statisticType, AggregatorType aggregatorType, DataTypes dataType) { + public QueryDefinitionDeprecatedImpl(String localeInfoName, GrouperType grouperType, StatisticType statisticType, AggregatorType aggregatorType, DataTypes dataType) { this.localeInfoName = localeInfoName; this.grouperType = grouperType; this.statisticType = statisticType; diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningEntryPoint.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningEntryPoint.java index 0370c159fa5..792ba204eed 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningEntryPoint.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/DataMiningEntryPoint.java @@ -18,7 +18,7 @@ import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.StatisticType; -import com.sap.sailing.datamining.shared.impl.SimpleQueryDefinition; +import com.sap.sailing.datamining.shared.impl.QueryDefinitionDeprecatedImpl; import com.sap.sailing.gwt.ui.client.AbstractEntryPoint; import com.sap.sailing.gwt.ui.client.GlobalNavigationPanel; import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; @@ -69,7 +69,7 @@ public class DataMiningEntryPoint extends AbstractEntryPoint { queryDefinitionProviderWithControls.addControl(queryRunner.getEntryWidget()); queryDefinitionProviderWithControls.addControl(createSettingsControlWidget(queryRunner, queryDefinitionProvider)); - SimpleQueryDefinition queryDefinition = new SimpleQueryDefinition(LocaleInfo.getCurrentLocale().getLocaleName(), GrouperType.Dimensions, StatisticType.Speed, AggregatorType.Average, DataTypes.GPSFix); + QueryDefinitionDeprecatedImpl queryDefinition = new QueryDefinitionDeprecatedImpl(LocaleInfo.getCurrentLocale().getLocaleName(), GrouperType.Dimensions, StatisticType.Speed, AggregatorType.Average, DataTypes.GPSFix); queryDefinition.appendDimensionToGroupBy(DimensionIdentifier.RegattaName); queryDefinitionProvider.applyQueryDefinition(queryDefinition); queryRunner.run(queryDefinitionProvider.getQueryDefinition()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java index 235d4ea290c..af47c768b1a 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/datamining/client/selection/QueryDefinitionProviderWithControls.java @@ -13,7 +13,7 @@ import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; -import com.sap.sailing.datamining.shared.impl.SimpleQueryDefinition; +import com.sap.sailing.datamining.shared.impl.QueryDefinitionDeprecatedImpl; import com.sap.sailing.gwt.ui.client.ErrorReporter; import com.sap.sailing.gwt.ui.client.SailingServiceAsync; import com.sap.sailing.gwt.ui.client.StringMessages; @@ -66,7 +66,7 @@ public class QueryDefinitionProviderWithControls extends AbstractQueryDefinition @Override public QueryDefinitionDeprecated getQueryDefinition() { - SimpleQueryDefinition queryDTO = new SimpleQueryDefinition(LocaleInfo.getCurrentLocale().getLocaleName(), groupBySelectionPanel.getGrouperType(), + QueryDefinitionDeprecatedImpl queryDTO = new QueryDefinitionDeprecatedImpl(LocaleInfo.getCurrentLocale().getLocaleName(), groupBySelectionPanel.getGrouperType(), statisticProvider.getStatisticType(), statisticProvider.getAggregatorType(), statisticProvider.getDataType()); From 13be51931a7a738c5c3e185c7321bcf17ff8b97c Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 13:24:50 +0200 Subject: [PATCH 027/114] Restructered the sse data mining and test packages --- .../impl/criterias/TestFilterCriterias.java | 4 ++-- .../TestCompoundFunction.java | 10 +++++----- .../TestFunctionDTOConstruction.java | 6 +++--- .../TestFunctionProvider.java | 16 ++++++++-------- .../TestMethodWrappingFunction.java | 6 +++--- .../TestMethodWrappingFunctionInvocation.java | 8 ++++---- .../TestSimpleFunctionRegistryAccess.java | 8 ++++---- .../TestSimpleFunctionRegistryRegistrations.java | 6 +++--- ...TestDeclaringTypeOrParameterTypeCriteria.java | 14 +++++++------- .../criterias}/TestFunctionFilterCriterias.java | 8 ++++---- .../test_classes/ContainerElement.java | 2 +- .../test_classes/ContainerElementImpl.java | 2 +- .../test_classes/DataTypeInterface.java | 2 +- .../test_classes/DataTypeWithContext.java | 2 +- .../test_classes/DataTypeWithContextImpl.java | 2 +- .../test_classes/ExtendingInterface.java | 2 +- .../test_classes/ExternalLibraryClass.java | 2 +- .../test_classes/MarkedContainer.java | 2 +- .../test_classes/MarkedContainerImpl.java | 2 +- .../SimpleClassWithMarkedMethods.java | 2 +- .../datamining/test/util/FunctionTestsUtil.java | 12 ++++++------ .../impl/functions/RegistryFunctionProvider.java | 1 + .../impl/functions/SimpleFunctionRegistry.java | 2 ++ .../ExternalFunctionRetrievalProcessor.java | 3 ++- .../FilteringFunctionRetrievalProcessor.java | 2 +- .../InternalFunctionRetrievalProcessor.java | 4 +++- .../FunctionMatchesDTOFilterCriteria.java | 2 +- .../IsDeclaringTypeFilterCriteria.java | 2 +- .../MethodIsCorrectDimensionFilterCriteria.java | 2 +- ...dIsCorrectExternalFunctionFilterCriteria.java | 2 +- ...CorrectSideEffectFreeValueFilterCriteria.java | 2 +- 31 files changed, 73 insertions(+), 67 deletions(-) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestCompoundFunction.java (88%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestFunctionDTOConstruction.java (96%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestFunctionProvider.java (90%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestMethodWrappingFunction.java (94%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestMethodWrappingFunctionInvocation.java (86%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestSimpleFunctionRegistryAccess.java (85%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions}/TestSimpleFunctionRegistryRegistrations.java (94%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions/criterias}/TestDeclaringTypeOrParameterTypeCriteria.java (76%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/{function => functions/criterias}/TestFunctionFilterCriterias.java (85%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/ContainerElement.java (73%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/ContainerElementImpl.java (80%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/DataTypeInterface.java (82%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/DataTypeWithContext.java (88%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/DataTypeWithContextImpl.java (93%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/ExtendingInterface.java (77%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/ExternalLibraryClass.java (84%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/MarkedContainer.java (78%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/MarkedContainerImpl.java (85%) rename java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/{function => functions}/test_classes/SimpleClassWithMarkedMethods.java (93%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => components}/ExternalFunctionRetrievalProcessor.java (82%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => components}/FilteringFunctionRetrievalProcessor.java (97%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => components}/InternalFunctionRetrievalProcessor.java (81%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => criterias}/FunctionMatchesDTOFilterCriteria.java (92%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => criterias}/IsDeclaringTypeFilterCriteria.java (97%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => criterias}/MethodIsCorrectDimensionFilterCriteria.java (88%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => criterias}/MethodIsCorrectExternalFunctionFilterCriteria.java (86%) rename java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/{ => criterias}/MethodIsCorrectSideEffectFreeValueFilterCriteria.java (87%) diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/criterias/TestFilterCriterias.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/criterias/TestFilterCriterias.java index 497f6396f11..508bcbd03be 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/criterias/TestFilterCriterias.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/criterias/TestFilterCriterias.java @@ -16,8 +16,8 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.impl.criterias.deprecated.SimpleRangeFilterCriteria; import com.sap.sse.datamining.impl.data.deprecated.ClusterOfComparableImpl; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContextImpl; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.StringRegexFilterCriteria; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestCompoundFunction.java similarity index 88% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestCompoundFunction.java index 29e285a2128..7e02c20ad2d 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestCompoundFunction.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestCompoundFunction.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -14,10 +14,10 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.impl.functions.CompoundFunction; import com.sap.sse.datamining.shared.Unit; -import com.sap.sse.datamining.test.function.test_classes.ContainerElement; -import com.sap.sse.datamining.test.function.test_classes.ContainerElementImpl; -import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; -import com.sap.sse.datamining.test.function.test_classes.MarkedContainerImpl; +import com.sap.sse.datamining.test.functions.test_classes.ContainerElement; +import com.sap.sse.datamining.test.functions.test_classes.ContainerElementImpl; +import com.sap.sse.datamining.test.functions.test_classes.MarkedContainer; +import com.sap.sse.datamining.test.functions.test_classes.MarkedContainerImpl; import com.sap.sse.datamining.test.util.TestsUtil; public class TestCompoundFunction { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionDTOConstruction.java similarity index 96% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionDTOConstruction.java index 846aa9235ba..95108a1c662 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionDTOConstruction.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionDTOConstruction.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -17,8 +17,8 @@ import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.i18n.DataMiningStringMessages; import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.TestsUtil; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionProvider.java similarity index 90% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionProvider.java index 57adff12eb3..3e59caab093 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionProvider.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestFunctionProvider.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; @@ -21,13 +21,13 @@ import com.sap.sse.datamining.i18n.DataMiningStringMessages; import com.sap.sse.datamining.impl.functions.RegistryFunctionProvider; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; import com.sap.sse.datamining.shared.dto.FunctionDTO; -import com.sap.sse.datamining.test.function.test_classes.ContainerElement; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.MarkedContainer; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.ContainerElement; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContextImpl; +import com.sap.sse.datamining.test.functions.test_classes.ExtendingInterface; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.MarkedContainer; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.TestsUtil; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunction.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunction.java similarity index 94% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunction.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunction.java index 42b155a0966..ad171480731 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunction.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunction.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -13,8 +13,8 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.i18n.DataMiningStringMessages; import com.sap.sse.datamining.impl.functions.MethodWrappingFunction; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.FunctionTestsUtil; import com.sap.sse.datamining.test.util.TestsUtil; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunctionInvocation.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunctionInvocation.java similarity index 86% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunctionInvocation.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunctionInvocation.java index 4e24323ca98..8bb5bc7913d 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestMethodWrappingFunctionInvocation.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestMethodWrappingFunctionInvocation.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; @@ -9,9 +9,9 @@ import org.junit.Test; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContextImpl; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.FunctionTestsUtil; public class TestMethodWrappingFunctionInvocation { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryAccess.java similarity index 85% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryAccess.java index 155816aae7c..fa7e8d63c69 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryAccess.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryAccess.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -12,9 +12,9 @@ import org.junit.Test; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryRegistrations.java similarity index 94% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryRegistrations.java index 93af22a13c5..d8b84a34f8d 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestSimpleFunctionRegistryRegistrations.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/TestSimpleFunctionRegistryRegistrations.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -14,8 +14,8 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; import com.sap.sse.datamining.test.util.ConcurrencyTestsUtil; import com.sap.sse.datamining.test.util.FunctionTestsUtil; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestDeclaringTypeOrParameterTypeCriteria.java similarity index 76% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestDeclaringTypeOrParameterTypeCriteria.java index 832c9a25af0..d180b383486 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestDeclaringTypeOrParameterTypeCriteria.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestDeclaringTypeOrParameterTypeCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions.criterias; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -9,12 +9,12 @@ import org.junit.Test; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.impl.functions.IsDeclaringTypeFilterCriteria; -import com.sap.sse.datamining.test.function.test_classes.DataTypeInterface; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.impl.functions.criterias.IsDeclaringTypeFilterCriteria; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeInterface; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContextImpl; +import com.sap.sse.datamining.test.functions.test_classes.ExtendingInterface; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; import com.sap.sse.datamining.test.util.FunctionTestsUtil; public class TestDeclaringTypeOrParameterTypeCriteria { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionFilterCriterias.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestFunctionFilterCriterias.java similarity index 85% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionFilterCriterias.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestFunctionFilterCriterias.java index b55274d3dd3..e8fd2b2ec52 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/function/TestFunctionFilterCriterias.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/impl/functions/criterias/TestFunctionFilterCriterias.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.function; +package com.sap.sse.datamining.impl.functions.criterias; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; @@ -8,9 +8,9 @@ import java.lang.reflect.Method; import org.junit.Test; import com.sap.sse.datamining.components.FilterCriteria; -import com.sap.sse.datamining.impl.functions.MethodIsCorrectDimensionFilterCriteria; -import com.sap.sse.datamining.impl.functions.MethodIsCorrectExternalFunctionFilterCriteria; -import com.sap.sse.datamining.impl.functions.MethodIsCorrectSideEffectFreeValueFilterCriteria; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectDimensionFilterCriteria; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectExternalFunctionFilterCriteria; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectSideEffectFreeValueFilterCriteria; import com.sap.sse.datamining.test.util.FunctionTestsUtil; public class TestFunctionFilterCriterias { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElement.java similarity index 73% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElement.java index 6bbe7b13431..c46d2076ac7 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElement.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElement.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.annotations.Dimension; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElementImpl.java similarity index 80% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElementImpl.java index 5f347d772f3..bbaf7e02800 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ContainerElementImpl.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ContainerElementImpl.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; public class ContainerElementImpl implements ContainerElement { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeInterface.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeInterface.java similarity index 82% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeInterface.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeInterface.java index f30a8df504d..0a13b0f6c0e 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeInterface.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeInterface.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.Unit; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContext.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContext.java similarity index 88% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContext.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContext.java index 48be7950e1f..cbdb8853fd1 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContext.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContext.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.annotations.Dimension; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextImpl.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContextImpl.java similarity index 93% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextImpl.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContextImpl.java index 5f225e00715..542d6bdf994 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/DataTypeWithContextImpl.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/DataTypeWithContextImpl.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; public class DataTypeWithContextImpl implements DataTypeWithContext, ExtendingInterface { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExtendingInterface.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExtendingInterface.java similarity index 77% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExtendingInterface.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExtendingInterface.java index 86a38d5d4a3..dedab763ac8 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExtendingInterface.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExtendingInterface.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExternalLibraryClass.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExternalLibraryClass.java similarity index 84% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExternalLibraryClass.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExternalLibraryClass.java index e829109147a..a740264a924 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/ExternalLibraryClass.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/ExternalLibraryClass.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; /* * DON'T CHANGE THE METHOD/CLASS NAMES! diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainer.java similarity index 78% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainer.java index 5fb7228115e..cbe396463cb 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainer.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainer.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainerImpl.java similarity index 85% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainerImpl.java index dbbe831adb8..34ed2e3a220 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/MarkedContainerImpl.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/MarkedContainerImpl.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; public class MarkedContainerImpl implements MarkedContainer { diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/SimpleClassWithMarkedMethods.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/SimpleClassWithMarkedMethods.java similarity index 93% rename from java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/SimpleClassWithMarkedMethods.java rename to java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/SimpleClassWithMarkedMethods.java index 6d0f02703d7..354393d28a1 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/function/test_classes/SimpleClassWithMarkedMethods.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/functions/test_classes/SimpleClassWithMarkedMethods.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.test.function.test_classes; +package com.sap.sse.datamining.test.functions.test_classes; import com.sap.sse.datamining.shared.annotations.Dimension; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; diff --git a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java index be07a232021..8d90690425e 100644 --- a/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java +++ b/java/com.sap.sse.datamining.test/src/com/sap/sse/datamining/test/util/FunctionTestsUtil.java @@ -9,12 +9,12 @@ import java.util.Set; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; -import com.sap.sse.datamining.test.function.test_classes.DataTypeInterface; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContext; -import com.sap.sse.datamining.test.function.test_classes.DataTypeWithContextImpl; -import com.sap.sse.datamining.test.function.test_classes.ExtendingInterface; -import com.sap.sse.datamining.test.function.test_classes.ExternalLibraryClass; -import com.sap.sse.datamining.test.function.test_classes.SimpleClassWithMarkedMethods; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeInterface; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContext; +import com.sap.sse.datamining.test.functions.test_classes.DataTypeWithContextImpl; +import com.sap.sse.datamining.test.functions.test_classes.ExtendingInterface; +import com.sap.sse.datamining.test.functions.test_classes.ExternalLibraryClass; +import com.sap.sse.datamining.test.functions.test_classes.SimpleClassWithMarkedMethods; public class FunctionTestsUtil extends ConcurrencyTestsUtil { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java index af97824487a..b7d8a883710 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/RegistryFunctionProvider.java @@ -10,6 +10,7 @@ import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionProvider; import com.sap.sse.datamining.functions.FunctionRegistry; +import com.sap.sse.datamining.impl.functions.criterias.FunctionMatchesDTOFilterCriteria; import com.sap.sse.datamining.shared.dto.FunctionDTO; public class RegistryFunctionProvider implements FunctionProvider { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index 03272caf8b4..790336bc5c9 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -21,6 +21,8 @@ import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.functions.FunctionRetrievalProcessor; +import com.sap.sse.datamining.impl.functions.components.ExternalFunctionRetrievalProcessor; +import com.sap.sse.datamining.impl.functions.components.InternalFunctionRetrievalProcessor; public class SimpleFunctionRegistry implements FunctionRegistry { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/ExternalFunctionRetrievalProcessor.java similarity index 82% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/ExternalFunctionRetrievalProcessor.java index b241ff7f0a4..804626a2eb6 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/ExternalFunctionRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/ExternalFunctionRetrievalProcessor.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.components; import java.lang.reflect.Method; import java.util.Collection; @@ -7,6 +7,7 @@ import java.util.concurrent.ExecutorService; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectExternalFunctionFilterCriteria; public class ExternalFunctionRetrievalProcessor extends FilteringFunctionRetrievalProcessor { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/FilteringFunctionRetrievalProcessor.java similarity index 97% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/FilteringFunctionRetrievalProcessor.java index b4e1aa3f64d..a21dc4500b2 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FilteringFunctionRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/FilteringFunctionRetrievalProcessor.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.components; import java.lang.reflect.Method; import java.util.Collection; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/InternalFunctionRetrievalProcessor.java similarity index 81% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/InternalFunctionRetrievalProcessor.java index 47b602437c9..f9e3264c6fc 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/InternalFunctionRetrievalProcessor.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/components/InternalFunctionRetrievalProcessor.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.components; import java.lang.reflect.Method; import java.util.Collection; @@ -9,6 +9,8 @@ import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.impl.criterias.CompoundFilterCriteria; import com.sap.sse.datamining.impl.criterias.OrCompoundFilterCriteria; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectDimensionFilterCriteria; +import com.sap.sse.datamining.impl.functions.criterias.MethodIsCorrectSideEffectFreeValueFilterCriteria; public class InternalFunctionRetrievalProcessor extends FilteringFunctionRetrievalProcessor { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/FunctionMatchesDTOFilterCriteria.java similarity index 92% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/FunctionMatchesDTOFilterCriteria.java index c39d7de5729..9e60de2af82 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/FunctionMatchesDTOFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/FunctionMatchesDTOFilterCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.criterias; import com.sap.sse.datamining.components.FilterCriteria; import com.sap.sse.datamining.factories.FunctionDTOFactory; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/IsDeclaringTypeFilterCriteria.java similarity index 97% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/IsDeclaringTypeFilterCriteria.java index 7504eef90ef..335f8531f26 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/IsDeclaringTypeFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/IsDeclaringTypeFilterCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.criterias; import java.util.Arrays; import java.util.Collection; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectDimensionFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectDimensionFilterCriteria.java similarity index 88% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectDimensionFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectDimensionFilterCriteria.java index 55b8c58f868..221506fd277 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectDimensionFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectDimensionFilterCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.criterias; import java.lang.reflect.Method; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectExternalFunctionFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectExternalFunctionFilterCriteria.java similarity index 86% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectExternalFunctionFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectExternalFunctionFilterCriteria.java index 8a36c1b6575..ff2d5d10296 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectExternalFunctionFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectExternalFunctionFilterCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.criterias; import java.lang.reflect.Method; diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectSideEffectFreeValueFilterCriteria.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectSideEffectFreeValueFilterCriteria.java similarity index 87% rename from java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectSideEffectFreeValueFilterCriteria.java rename to java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectSideEffectFreeValueFilterCriteria.java index ef6fdb1900b..ee4babf251a 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/MethodIsCorrectSideEffectFreeValueFilterCriteria.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/criterias/MethodIsCorrectSideEffectFreeValueFilterCriteria.java @@ -1,4 +1,4 @@ -package com.sap.sse.datamining.impl.functions; +package com.sap.sse.datamining.impl.functions.criterias; import java.lang.reflect.Method; From aa5d338843a50cf8d59173180f1af4db77431df8 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 18:13:29 +0200 Subject: [PATCH 028/114] Implemented a better fitting QueryDefinition --- .../datamining/shared/QueryDefinition.java | 21 ++++++++ .../shared/impl/QueryDefinitionImpl.java | 50 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java create mode 100644 java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java new file mode 100644 index 00000000000..2c78d1a33f0 --- /dev/null +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinition.java @@ -0,0 +1,21 @@ +package com.sap.sailing.datamining.shared; + +import java.util.List; +import java.util.Map; + +import com.sap.sse.datamining.shared.components.AggregatorType; +import com.sap.sse.datamining.shared.dto.FunctionDTO; + +public interface QueryDefinition { + + public String getLocaleInfoName(); + + public Map> getFilterSelection(); + + public List getDimensionsToGroupBy(); + + public FunctionDTO getExtractionFunction(); + + public AggregatorType getAggregatorType(); + +} diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java new file mode 100644 index 00000000000..95b488f994a --- /dev/null +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java @@ -0,0 +1,50 @@ +package com.sap.sailing.datamining.shared.impl; + +import java.util.List; +import java.util.Map; + +import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sse.datamining.shared.components.AggregatorType; +import com.sap.sse.datamining.shared.dto.FunctionDTO; + +public class QueryDefinitionImpl implements QueryDefinition { + + private final String localeInfoName; + private final Map> filterSelection; + private final List dimensionsToGroupBy; + private final AggregatorType aggregatorType; + + public QueryDefinitionImpl(String localeInfoName, Map> filterSelection, + List dimensionsToGroupBy, AggregatorType aggregatorType) { + this.localeInfoName = localeInfoName; + this.filterSelection = filterSelection; + this.dimensionsToGroupBy = dimensionsToGroupBy; + this.aggregatorType = aggregatorType; + } + + @Override + public String getLocaleInfoName() { + return localeInfoName; + } + + @Override + public Map> getFilterSelection() { + return filterSelection; + } + + @Override + public List getDimensionsToGroupBy() { + return dimensionsToGroupBy; + } + + @Override + public FunctionDTO getExtractionFunction() { + return getExtractionFunction(); + } + + @Override + public AggregatorType getAggregatorType() { + return aggregatorType; + } + +} From afd2cca59009504e29bc78693d006ab56593f635 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 18:33:01 +0200 Subject: [PATCH 029/114] Opened the concrete QueryDefinition --- .../shared/impl/QueryDefinitionImpl.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java index 95b488f994a..19b4a3ed7f5 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java @@ -1,8 +1,10 @@ package com.sap.sailing.datamining.shared.impl; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import com.google.gwt.dev.util.collect.HashMap; import com.sap.sailing.datamining.shared.QueryDefinition; import com.sap.sse.datamining.shared.components.AggregatorType; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -12,15 +14,24 @@ public class QueryDefinitionImpl implements QueryDefinition { private final String localeInfoName; private final Map> filterSelection; private final List dimensionsToGroupBy; + private final FunctionDTO extractionFunction; private final AggregatorType aggregatorType; - public QueryDefinitionImpl(String localeInfoName, Map> filterSelection, - List dimensionsToGroupBy, AggregatorType aggregatorType) { + public QueryDefinitionImpl(String localeInfoName, FunctionDTO extractionFunction, AggregatorType aggregatorType) { this.localeInfoName = localeInfoName; - this.filterSelection = filterSelection; - this.dimensionsToGroupBy = dimensionsToGroupBy; + this.filterSelection = new HashMap<>(); + this.dimensionsToGroupBy = new ArrayList<>(); + this.extractionFunction = extractionFunction; this.aggregatorType = aggregatorType; } + + public void setFilterSelectionFor(FunctionDTO dimension, Iterable selection) { + filterSelection.put(dimension, selection); + } + + public void appenDimensionToGroupBy(FunctionDTO dimensionToGroupBy) { + dimensionsToGroupBy.add(dimensionToGroupBy); + } @Override public String getLocaleInfoName() { @@ -39,7 +50,7 @@ public class QueryDefinitionImpl implements QueryDefinition { @Override public FunctionDTO getExtractionFunction() { - return getExtractionFunction(); + return extractionFunction; } @Override From aac9fa227474aef2f4c2677e52d38730a00cea41 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sat, 3 May 2014 18:33:19 +0200 Subject: [PATCH 030/114] Implemented a rough query definition converter --- .../shared/QueryDefinitionConverter.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java new file mode 100644 index 00000000000..8bcc77917bd --- /dev/null +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java @@ -0,0 +1,43 @@ +package com.sap.sailing.datamining.shared; + +import java.util.Map.Entry; + +import com.sap.sailing.datamining.shared.impl.QueryDefinitionImpl; +import com.sap.sse.datamining.shared.dto.FunctionDTO; + +public class QueryDefinitionConverter { + + public static QueryDefinition convertDeprecatedQueryDefinition(QueryDefinitionDeprecated queryDefinitionDeprecated) { + //TODO implement the statistic type to function conversion + QueryDefinitionImpl queryDefinition = new QueryDefinitionImpl(queryDefinitionDeprecated.getLocaleInfoName(), + convertToFunctionDTO(queryDefinitionDeprecated.getStatisticType()), queryDefinitionDeprecated.getAggregatorType()); + + for (Entry> filterSelectionEntry : queryDefinitionDeprecated.getSelection().entrySet()) { + //TODO implement the dimension identifier to function conversion + queryDefinition.setFilterSelectionFor(convertToFunctionDTO(filterSelectionEntry.getKey()), + filterSelectionEntry.getValue()); + } + + for (DimensionIdentifier dimensionIdentifier : queryDefinitionDeprecated.getDimensionsToGroupBy()) { + queryDefinition.appenDimensionToGroupBy(convertToFunctionDTO(dimensionIdentifier)); + } + + return queryDefinition; + } + + private static FunctionDTO convertToFunctionDTO(StatisticType statisticType) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Not yet implemented"); +// return null; + } + + private static FunctionDTO convertToFunctionDTO(DimensionIdentifier dimensionIdentifier) { + // TODO Auto-generated method stub + throw new UnsupportedOperationException("Not yet implemented"); + // return null; + } + + private QueryDefinitionConverter() { + } + +} From be51206abb7f561db7949371d303c04f8a050368 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sun, 4 May 2014 14:53:59 +0200 Subject: [PATCH 031/114] Cleaned the DataMiningActivator --- .../datamining/impl/DataMiningActivator.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java index f28980198f4..d37cd774223 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/DataMiningActivator.java @@ -45,39 +45,10 @@ public class DataMiningActivator implements BundleActivator { FunctionRegistry functionRegistry = createAndBuildFunctionRegistry(); FunctionProvider functionProvider = new RegistryFunctionProvider(functionRegistry); - dataMiningServer = new DataMiningServerImpl(functionRegistry, functionProvider); registerDataMiningServer(); } - private void registerDataMiningServer() { - context.registerService(DataMiningServer.class, dataMiningServer, null); - } - - private FunctionRegistry createAndBuildFunctionRegistry() { - FunctionRegistry functionRegistry = new SimpleFunctionRegistry(getExecutor()); - - Set> internalClassesWithMarkedMethods = new HashSet<>(); - Set> externalLibraryClasses = new HashSet<>(); - for (ServiceReference serviceReference : serviceReferences) { - ClassesWithFunctionsService service = context.getService(serviceReference); - - Set> internalClassesWithMarkedMethodsToAdd = service.getInternalClassesWithMarkedMethods(); - if (internalClassesWithMarkedMethodsToAdd != null) { - internalClassesWithMarkedMethods.addAll(internalClassesWithMarkedMethodsToAdd); - } - - Set> externalLibraryClassesToAdd = service.getExternalLibraryClasses(); - if (externalLibraryClassesToAdd != null) { - externalLibraryClasses.addAll(externalLibraryClassesToAdd); - } - } - - functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesWithMarkedMethods); - functionRegistry.registerAllWithExternalFunctionPolicy(externalLibraryClasses); - return functionRegistry; - } - private Collection> getAllClassesWithMarkedMethodsServices() { try { ServiceReference[] serviceReferences = context.getServiceReferences(ClassesWithFunctionsService.class.getName(), null); @@ -107,6 +78,35 @@ public class DataMiningActivator implements BundleActivator { return specificServiceReferences; } + private FunctionRegistry createAndBuildFunctionRegistry() { + FunctionRegistry functionRegistry = new SimpleFunctionRegistry(getExecutor()); + + Set> internalClassesWithMarkedMethods = new HashSet<>(); + Set> externalLibraryClasses = new HashSet<>(); + for (ServiceReference serviceReference : serviceReferences) { + internalClassesWithMarkedMethods.addAll(getInternalClassesWithMarkedMethodsFromService(serviceReference)); + externalLibraryClasses.addAll(getExternalLibraryClassesFromService(serviceReference)); + } + + functionRegistry.registerAllWithInternalFunctionPolicy(internalClassesWithMarkedMethods); + functionRegistry.registerAllWithExternalFunctionPolicy(externalLibraryClasses); + return functionRegistry; + } + + private Collection> getInternalClassesWithMarkedMethodsFromService(ServiceReference serviceReference) { + Collection> internalClassesWithMarkedMethods = context.getService(serviceReference).getInternalClassesWithMarkedMethods(); + return internalClassesWithMarkedMethods != null ? internalClassesWithMarkedMethods : new ArrayList>(); + } + + private Collection> getExternalLibraryClassesFromService(ServiceReference serviceReference) { + Collection> externalLibraryClasses = context.getService(serviceReference).getExternalLibraryClasses(); + return externalLibraryClasses != null ? externalLibraryClasses : new ArrayList>(); + } + + private void registerDataMiningServer() { + context.registerService(DataMiningServer.class, dataMiningServer, null); + } + @Override public void stop(BundleContext context) throws Exception { for (ServiceReference serviceReference : serviceReferences) { From 08134bcd1e9619ae0637474a2c55b2555d2c48a6 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sun, 4 May 2014 14:55:04 +0200 Subject: [PATCH 032/114] Formatted and cleaned the sailing data mining activator --- .../sailing/datamining/impl/Activator.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java index 4fd17a70345..03738c2e0d3 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java @@ -9,28 +9,28 @@ import com.sap.sse.datamining.functions.ClassesWithFunctionsService; public class Activator implements BundleActivator { - private static BundleContext context; + private static BundleContext context; - private ServiceRegistration classesWithFunctionsServiceReference; + private ServiceRegistration classesWithFunctionsServiceRegistration; - @Override - public void start(BundleContext context) throws Exception { + @Override + public void start(BundleContext context) throws Exception { Activator.context = context; - registerClassesWithFunctionsService(); - } + registerClassesWithFunctionsService(); + } - @Override - public void stop(BundleContext context) throws Exception { - unregisterClassesWithFunctionsService(); - } + @Override + public void stop(BundleContext context) throws Exception { + unregisterClassesWithFunctionsService(); + } private void unregisterClassesWithFunctionsService() { - context.ungetService(classesWithFunctionsServiceReference.getReference()); - } + context.ungetService(classesWithFunctionsServiceRegistration.getReference()); + } - private void registerClassesWithFunctionsService() { - classesWithFunctionsServiceReference = context.registerService(ClassesWithFunctionsService.class, - new DataMiningClassesWithFunctionsService(), null); + private void registerClassesWithFunctionsService() { + classesWithFunctionsServiceRegistration = context.registerService(ClassesWithFunctionsService.class, + new DataMiningClassesWithFunctionsService(), null); } } From 1319bf390bdc4073bf82caaa68305b2a6beb3d71 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Sun, 4 May 2014 17:40:59 +0200 Subject: [PATCH 033/114] Added a stubbed integration test for the sailing functions registration --- .../TestSailingFunctionsRegistration.java | 56 +++++++++++++++++++ .../sailing/datamining/impl/Activator.java | 4 +- ...ataMiningClassesWithFunctionsService.java} | 2 +- .../datamining/factories/FunctionFactory.java | 18 ++++++ .../functions/SimpleFunctionRegistry.java | 6 +- 5 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/functions/TestSailingFunctionsRegistration.java rename java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/{DataMiningClassesWithFunctionsService.java => SailingDataMiningClassesWithFunctionsService.java} (90%) diff --git a/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/functions/TestSailingFunctionsRegistration.java b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/functions/TestSailingFunctionsRegistration.java new file mode 100644 index 00000000000..3ad31ae3007 --- /dev/null +++ b/java/com.sap.sailing.datamining.test/src/com/sap/sailing/datamining/impl/functions/TestSailingFunctionsRegistration.java @@ -0,0 +1,56 @@ +package com.sap.sailing.datamining.impl.functions; + +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collection; + +import org.junit.BeforeClass; +import org.junit.Test; + +import com.sap.sailing.datamining.impl.data.SailingDataMiningClassesWithFunctionsService; +import com.sap.sailing.datamining.test.util.ConcurrencyTestsUtil; +import com.sap.sse.datamining.factories.FunctionFactory; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.functions.FunctionProvider; +import com.sap.sse.datamining.functions.FunctionRegistry; + +public class TestSailingFunctionsRegistration { + + private static FunctionRegistry functionRegistry; + private static FunctionProvider functionProvider; + + @BeforeClass + public static void setUpFunctionRegistryAndProvider() { + SailingDataMiningClassesWithFunctionsService classesWithFunctionsService = new SailingDataMiningClassesWithFunctionsService(); + + functionRegistry = FunctionFactory.createFunctionRegistry(ConcurrencyTestsUtil.getExecutor()); + functionRegistry.registerAllWithInternalFunctionPolicy(classesWithFunctionsService.getInternalClassesWithMarkedMethods()); + functionProvider = FunctionFactory.createRegistryFunctionProvider(functionRegistry); + } + + @Test + public void testRegisteredDimensionsWithoutTheTransitiveOnes() { + Collection> expectedDimensions = createExpectedRegisteredDimensionsWithoutTheTransitiveOnes(); + assertThat(functionRegistry.getAllDimensions(), is(expectedDimensions)); + } + + private Collection> createExpectedRegisteredDimensionsWithoutTheTransitiveOnes() { + // TODO Auto-generated method stub + return null; + } + + @Test + public void testImportantRegisteredFunctions() { + // This tests for the methods marked as SideEffectFreeValue, that will be used for the data extraction + Function[] expectedFunctions = createExpectedImportantRegisteredFunctions(); + assertThat(functionRegistry.getAllFunctions(), hasItems(expectedFunctions)); + } + + private Function[] createExpectedImportantRegisteredFunctions() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java index 03738c2e0d3..fbeedc509b2 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/Activator.java @@ -4,7 +4,7 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; -import com.sap.sailing.datamining.impl.data.DataMiningClassesWithFunctionsService; +import com.sap.sailing.datamining.impl.data.SailingDataMiningClassesWithFunctionsService; import com.sap.sse.datamining.functions.ClassesWithFunctionsService; public class Activator implements BundleActivator { @@ -30,7 +30,7 @@ public class Activator implements BundleActivator { private void registerClassesWithFunctionsService() { classesWithFunctionsServiceRegistration = context.registerService(ClassesWithFunctionsService.class, - new DataMiningClassesWithFunctionsService(), null); + new SailingDataMiningClassesWithFunctionsService(), null); } } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/SailingDataMiningClassesWithFunctionsService.java similarity index 90% rename from java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/SailingDataMiningClassesWithFunctionsService.java index ab7b3c1cd20..b6329b6ce9e 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/DataMiningClassesWithFunctionsService.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/SailingDataMiningClassesWithFunctionsService.java @@ -9,7 +9,7 @@ import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sse.datamining.functions.ClassesWithFunctionsService; -public class DataMiningClassesWithFunctionsService implements ClassesWithFunctionsService { +public class SailingDataMiningClassesWithFunctionsService implements ClassesWithFunctionsService { @Override public Set> getInternalClassesWithMarkedMethods() { diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java index 7aa7676f9a6..ac965abacc4 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/FunctionFactory.java @@ -1,15 +1,33 @@ package com.sap.sse.datamining.factories; import java.lang.reflect.Method; +import java.util.Collection; import java.util.List; +import java.util.concurrent.ExecutorService; import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.functions.FunctionProvider; +import com.sap.sse.datamining.functions.FunctionRegistry; import com.sap.sse.datamining.impl.functions.CompoundFunction; import com.sap.sse.datamining.impl.functions.MethodWrappingFunction; +import com.sap.sse.datamining.impl.functions.RegistryFunctionProvider; +import com.sap.sse.datamining.impl.functions.SimpleFunctionRegistry; public class FunctionFactory { private FunctionFactory() { } + + public static FunctionRegistry createFunctionRegistry(ExecutorService executor) { + return new SimpleFunctionRegistry(executor); + } + + public static FunctionProvider createRegistryFunctionProvider(FunctionRegistry... functionRegistries) { + return new RegistryFunctionProvider(functionRegistries); + } + + public static FunctionProvider createRegistryFunctionProvider(Collection functionRegistries) { + return new RegistryFunctionProvider(functionRegistries); + } /** * Creates a {@link MethodWrappingFunction} for the given method.
diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java index 790336bc5c9..14331cccb66 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/functions/SimpleFunctionRegistry.java @@ -123,11 +123,11 @@ public class SimpleFunctionRegistry implements FunctionRegistry { } private Collection> collectAllFunctionsIn(Map, Collection>> functionsMap) { - Set> registeredMethods = new HashSet<>(); + Set> registeredFunctions = new HashSet<>(); for (Collection> registeredMethodsOfClass : functionsMap.values()) { - registeredMethods.addAll(registeredMethodsOfClass); + registeredFunctions.addAll(registeredMethodsOfClass); } - return registeredMethods; + return registeredFunctions; } private class FunctionsReceiver implements Processor>> { From 02a07f0bb63360a80592f7c0611f7b83bfbd4dda Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 8 May 2014 13:29:52 +0200 Subject: [PATCH 034/114] Implemented a stub for a function converter Committing to be able to push the changes --- .../impl/DeprecatedToFunctionConverter.java | 90 +++++++++++++++++++ .../impl}/QueryDefinitionConverter.java | 14 +-- .../com/sap/sailing/domain/common/Speed.java | 4 + .../com/sap/sailing/domain/base/Moving.java | 2 + 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java rename java/{com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared => com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl}/QueryDefinitionConverter.java (77%) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java new file mode 100644 index 00000000000..156e32a0d96 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java @@ -0,0 +1,90 @@ +package com.sap.sailing.datamining.impl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import com.sap.sailing.datamining.impl.data.GPSFixWithContext; +import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithContext; +import com.sap.sailing.datamining.shared.DimensionIdentifier; +import com.sap.sailing.datamining.shared.StatisticType; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.shared.dto.FunctionDTO; +import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; + +public class DeprecatedToFunctionConverter { + + private static Map statisticTypeToFunctionDTOMap = new HashMap<>(); + private static Map dimensionIdentifierToFunctionDTOMap = new HashMap<>(); + + private static Map> functionDTOToFunctionMap = new HashMap<>(); + + static { + initializeDeprecatedEnumsToFunctionDTOMaps(); + initializeFunctionDTOToFunctionMap(); + } + + public static FunctionDTO getFunctionDTOFor(StatisticType statisticType) { + return statisticTypeToFunctionDTOMap.get(statisticType); + } + + private static void initializeDeprecatedEnumsToFunctionDTOMaps() { + for (StatisticType statisticType : StatisticType.values()) { + FunctionDTO functionDTO = null; + switch (statisticType) { + case Distance: + functionDTO = new FunctionDTOImpl("Distance", GPSFixWithContext.class.getSimpleName(), "double", new ArrayList(), "Distance", false); + break; + case Speed: + functionDTO = new FunctionDTOImpl("Speed", TrackedLegOfCompetitorWithContext.class.getSimpleName(), "double", new ArrayList(), "Speed", false); + break; + } + statisticTypeToFunctionDTOMap.put(statisticType, functionDTO); + } + } + + private static void initializeFunctionDTOToFunctionMap() { + for (DimensionIdentifier dimensionIdentifier : DimensionIdentifier.values()) { +// FunctionDTO functionDTO = null; + switch (dimensionIdentifier) { + case BoatClassName: + break; + case CompetitorName: + break; + case CourseAreaName: + break; + case FleetName: + break; + case LegNumber: + break; + case LegType: + break; + case Nationality: + break; + case RaceName: + break; + case RegattaName: + break; + case SailID: + break; + case WindStrength: + break; + case Year: + break; + } + dimensionIdentifierToFunctionDTOMap.put(dimensionIdentifier, functionDTO); + } + } + + public static FunctionDTO getFunctionDTOFor(DimensionIdentifier dimensionIdentifier) { + return dimensionIdentifierToFunctionDTOMap.get(dimensionIdentifier); + } + + public static Function getFunctionFor(FunctionDTO functionDTO) { + return functionDTOToFunctionMap.get(functionDTO); + } + + private DeprecatedToFunctionConverter() { + } + +} diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java similarity index 77% rename from java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java rename to java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java index 8bcc77917bd..b6d3e3d782b 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/QueryDefinitionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java @@ -1,7 +1,11 @@ -package com.sap.sailing.datamining.shared; +package com.sap.sailing.datamining.impl; import java.util.Map.Entry; +import com.sap.sailing.datamining.shared.DimensionIdentifier; +import com.sap.sailing.datamining.shared.QueryDefinition; +import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; +import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sailing.datamining.shared.impl.QueryDefinitionImpl; import com.sap.sse.datamining.shared.dto.FunctionDTO; @@ -26,15 +30,11 @@ public class QueryDefinitionConverter { } private static FunctionDTO convertToFunctionDTO(StatisticType statisticType) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Not yet implemented"); -// return null; + return DeprecatedToFunctionConverter.getFunctionDTOFor(statisticType); } private static FunctionDTO convertToFunctionDTO(DimensionIdentifier dimensionIdentifier) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Not yet implemented"); - // return null; + return DeprecatedToFunctionConverter.getFunctionDTOFor(dimensionIdentifier); } private QueryDefinitionConverter() { diff --git a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Speed.java b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Speed.java index 192bb359998..9520ad0025f 100755 --- a/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Speed.java +++ b/java/com.sap.sailing.domain.common/src/com/sap/sailing/domain/common/Speed.java @@ -2,6 +2,9 @@ package com.sap.sailing.domain.common; import java.io.Serializable; +import com.sap.sse.datamining.shared.Unit; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; + /** * A speed, convertable in various units of measure. Can be negative. * @@ -48,6 +51,7 @@ public interface Speed extends Comparable, Serializable { } }; + @SideEffectFreeValue(messageKey="InKnots", resultDecimals=2, resultUnit=Unit.Knots) double getKnots(); double getMetersPerSecond(); diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Moving.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Moving.java index 01993de2f32..61b7054abc0 100755 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Moving.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/base/Moving.java @@ -1,7 +1,9 @@ package com.sap.sailing.domain.base; import com.sap.sailing.domain.common.SpeedWithBearing; +import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface Moving { + @SideEffectFreeValue(messageKey="Speed") SpeedWithBearing getSpeed(); } From 7d7dbc7eac24f34ae9197fbeb0607bbe3a700684 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 8 May 2014 14:36:12 +0200 Subject: [PATCH 035/114] Implemented deprecated to function DTO convertion --- .../impl/DeprecatedToFunctionConverter.java | 51 ++++++++++++++----- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java index 156e32a0d96..53b0d3a5883 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java @@ -4,10 +4,13 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import com.sap.sailing.datamining.impl.data.GPSFixWithContext; -import com.sap.sailing.datamining.impl.data.TrackedLegOfCompetitorWithContext; +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.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.StatisticType; +import com.sap.sailing.domain.common.LegType; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; @@ -24,58 +27,82 @@ public class DeprecatedToFunctionConverter { initializeFunctionDTOToFunctionMap(); } - public static FunctionDTO getFunctionDTOFor(StatisticType statisticType) { - return statisticTypeToFunctionDTOMap.get(statisticType); - } - private static void initializeDeprecatedEnumsToFunctionDTOMaps() { for (StatisticType statisticType : StatisticType.values()) { FunctionDTO functionDTO = null; switch (statisticType) { case Distance: - functionDTO = new FunctionDTOImpl("Distance", GPSFixWithContext.class.getSimpleName(), "double", new ArrayList(), "Distance", false); + functionDTO = new FunctionDTOImpl("Distance", HasGPSFixContext.class.getSimpleName(), "double", new ArrayList(), "Distance", false); break; case Speed: - functionDTO = new FunctionDTOImpl("Speed", TrackedLegOfCompetitorWithContext.class.getSimpleName(), "double", new ArrayList(), "Speed", false); + functionDTO = new FunctionDTOImpl("Speed", HasTrackedLegOfCompetitorContext.class.getSimpleName(), "double", new ArrayList(), "Speed", false); break; } statisticTypeToFunctionDTOMap.put(statisticType, functionDTO); } - } - - private static void initializeFunctionDTOToFunctionMap() { + for (DimensionIdentifier dimensionIdentifier : DimensionIdentifier.values()) { -// FunctionDTO functionDTO = null; + FunctionDTO functionDTO = null; switch (dimensionIdentifier) { case BoatClassName: + new FunctionDTOImpl("BoatClassName", HasTrackedRaceContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Boat Class Name", true); break; case CompetitorName: + new FunctionDTOImpl("CompetitorName", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Competitor Name", true); break; case CourseAreaName: + new FunctionDTOImpl("CourseClassName", HasTrackedRaceContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Course Area Name", true); break; case FleetName: + new FunctionDTOImpl("FleetName", HasTrackedRaceContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Fleet Name", true); break; case LegNumber: + new FunctionDTOImpl("LegNumber", HasTrackedLegContext.class.getSimpleName(), + "int", new ArrayList(), "Leg Number", true); break; case LegType: + new FunctionDTOImpl("LegType", HasTrackedLegContext.class.getSimpleName(), + LegType.class.getSimpleName(), new ArrayList(), "Leg Type", true); break; case Nationality: + new FunctionDTOImpl("Nationality", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Nationality", true); break; case RaceName: + new FunctionDTOImpl("RaceName", HasTrackedRaceContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Race Name", true); break; case RegattaName: + new FunctionDTOImpl("RegattaName", HasTrackedRaceContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Regattay Name", true); break; case SailID: + new FunctionDTOImpl("SailID", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + String.class.getSimpleName(), new ArrayList(), "Sail ID", true); break; case WindStrength: break; case Year: + new FunctionDTOImpl("Year", HasTrackedRaceContext.class.getSimpleName(), + "int", new ArrayList(), "Year", true); break; } dimensionIdentifierToFunctionDTOMap.put(dimensionIdentifier, functionDTO); } } + private static void initializeFunctionDTOToFunctionMap() { + + } + + public static FunctionDTO getFunctionDTOFor(StatisticType statisticType) { + return statisticTypeToFunctionDTOMap.get(statisticType); + } + public static FunctionDTO getFunctionDTOFor(DimensionIdentifier dimensionIdentifier) { return dimensionIdentifierToFunctionDTOMap.get(dimensionIdentifier); } From aca737262e184fe45a41e4d37bbeba3d7d5f0c6c Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Thu, 8 May 2014 15:28:43 +0200 Subject: [PATCH 036/114] Implemented the deprecated to function convertion for statistics --- .../HasTrackedLegOfCompetitorContext.java | 5 ++ .../impl/DeprecatedToFunctionConverter.java | 69 ++++++++++++++++++- .../TrackedLegOfCompetitorWithContext.java | 7 ++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index f51929df0e2..d928be85ad4 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -1,7 +1,9 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.base.Competitor; +import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; +import com.sap.sse.datamining.shared.Unit; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; public interface HasTrackedLegOfCompetitorContext extends HasTrackedLegContext { @@ -10,5 +12,8 @@ public interface HasTrackedLegOfCompetitorContext extends HasTrackedLegContext { @SideEffectFreeValue(messageKey="Competitor") public Competitor getCompetitor(); + + @SideEffectFreeValue(messageKey="DistanceTraveled", resultUnit=Unit.Meters, resultDecimals=0) + public double getDistanceTraveled(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java index 53b0d3a5883..b5351fe91b0 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java @@ -1,6 +1,8 @@ package com.sap.sailing.datamining.impl; +import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -10,7 +12,10 @@ import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.StatisticType; +import com.sap.sailing.domain.base.Moving; import com.sap.sailing.domain.common.LegType; +import com.sap.sailing.domain.common.Speed; +import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.shared.impl.dto.FunctionDTOImpl; @@ -32,10 +37,12 @@ public class DeprecatedToFunctionConverter { FunctionDTO functionDTO = null; switch (statisticType) { case Distance: - functionDTO = new FunctionDTOImpl("Distance", HasGPSFixContext.class.getSimpleName(), "double", new ArrayList(), "Distance", false); + functionDTO = new FunctionDTOImpl("Distance", HasGPSFixContext.class.getSimpleName(), "double", + new ArrayList(), "Distance", false); break; case Speed: - functionDTO = new FunctionDTOImpl("Speed", HasTrackedLegOfCompetitorContext.class.getSimpleName(), "double", new ArrayList(), "Speed", false); + functionDTO = new FunctionDTOImpl("Speed", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + "double", new ArrayList(), "Speed", false); break; } statisticTypeToFunctionDTOMap.put(statisticType, functionDTO); @@ -96,7 +103,65 @@ public class DeprecatedToFunctionConverter { } private static void initializeFunctionDTOToFunctionMap() { + for (StatisticType statisticType : StatisticType.values()) { + FunctionDTO functionDTO = getFunctionDTOFor(statisticType); + Method method = null; + Function function = null; + switch (statisticType) { + case Distance: + method = getNullaryMethodFromClass(HasTrackedLegOfCompetitorContext.class, "getDistanceTraveled"); + function = FunctionFactory.createMethodWrappingFunction(method); + break; + case Speed: + method = getNullaryMethodFromClass(HasGPSFixContext.class, "getGPSFix"); + Function getGPSFix = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Moving.class, "getSpeed"); + Function getSpeed = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Speed.class, "getKnots"); + Function getKnots = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Speed", Arrays.asList(getGPSFix, getSpeed, getKnots)); + break; + } + functionDTOToFunctionMap.put(functionDTO, function); + } + for (DimensionIdentifier dimensionIdentifier : DimensionIdentifier.values()) { + switch (dimensionIdentifier) { + case BoatClassName: + break; + case CompetitorName: + break; + case CourseAreaName: + break; + case FleetName: + break; + case LegNumber: + break; + case LegType: + break; + case Nationality: + break; + case RaceName: + break; + case RegattaName: + break; + case SailID: + break; + case WindStrength: + break; + case Year: + break; + } + } + } + + private static Method getNullaryMethodFromClass(Class clazz, String methodName) { + try { + return clazz.getMethod(methodName, new Class[0]); + } catch (NoSuchMethodException | SecurityException e) { + throw new IllegalArgumentException("The class " + clazz.getSimpleName() + " doesn't have" + + " the nullary method " + methodName); + } } public static FunctionDTO getFunctionDTOFor(StatisticType statisticType) { diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java index 39cdfacec06..bc6923b00d9 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java @@ -6,6 +6,7 @@ import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Event; import com.sap.sailing.domain.base.Fleet; import com.sap.sailing.domain.base.Regatta; +import com.sap.sailing.domain.common.TimePoint; import com.sap.sailing.domain.tracking.TrackedLeg; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sailing.domain.tracking.TrackedRace; @@ -37,5 +38,11 @@ public class TrackedLegOfCompetitorWithContext extends TrackedLegWithContext imp public Competitor getCompetitor() { return competitor; } + + @Override + public double getDistanceTraveled() { + TimePoint timePoint = getTrackedRace().getEndOfTracking(); + return getTrackedLegOfCompetitor().getDistanceTraveled(timePoint).getMeters(); + } } From 931217d001cd5275b8ab5a660f24c7b91a3a6e09 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 9 May 2014 09:58:45 +0200 Subject: [PATCH 037/114] Added missed assignments for the function DTO convertion --- .../impl/DeprecatedToFunctionConverter.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java index b5351fe91b0..89b0f6067e1 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java @@ -52,53 +52,55 @@ public class DeprecatedToFunctionConverter { FunctionDTO functionDTO = null; switch (dimensionIdentifier) { case BoatClassName: - new FunctionDTOImpl("BoatClassName", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("BoatClassName", HasTrackedRaceContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Boat Class Name", true); break; case CompetitorName: - new FunctionDTOImpl("CompetitorName", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("CompetitorName", HasTrackedLegOfCompetitorContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Competitor Name", true); break; case CourseAreaName: - new FunctionDTOImpl("CourseClassName", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("CourseClassName", HasTrackedRaceContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Course Area Name", true); break; case FleetName: - new FunctionDTOImpl("FleetName", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("FleetName", HasTrackedRaceContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Fleet Name", true); break; case LegNumber: - new FunctionDTOImpl("LegNumber", HasTrackedLegContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("LegNumber", HasTrackedLegContext.class.getSimpleName(), "int", new ArrayList(), "Leg Number", true); break; case LegType: - new FunctionDTOImpl("LegType", HasTrackedLegContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("LegType", HasTrackedLegContext.class.getSimpleName(), LegType.class.getSimpleName(), new ArrayList(), "Leg Type", true); break; case Nationality: - new FunctionDTOImpl("Nationality", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("Nationality", HasTrackedLegOfCompetitorContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Nationality", true); break; case RaceName: - new FunctionDTOImpl("RaceName", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("RaceName", HasTrackedRaceContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Race Name", true); break; case RegattaName: - new FunctionDTOImpl("RegattaName", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("RegattaName", HasTrackedRaceContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Regattay Name", true); break; case SailID: - new FunctionDTOImpl("SailID", HasTrackedLegOfCompetitorContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("SailID", HasTrackedLegOfCompetitorContext.class.getSimpleName(), String.class.getSimpleName(), new ArrayList(), "Sail ID", true); break; case WindStrength: break; case Year: - new FunctionDTOImpl("Year", HasTrackedRaceContext.class.getSimpleName(), + functionDTO = new FunctionDTOImpl("Year", HasTrackedRaceContext.class.getSimpleName(), "int", new ArrayList(), "Year", true); break; } - dimensionIdentifierToFunctionDTOMap.put(dimensionIdentifier, functionDTO); + if (functionDTO != null) { + dimensionIdentifierToFunctionDTOMap.put(dimensionIdentifier, functionDTO); + } } } From 16db415d66dcbb85209f293f6eb196fa2062c7b6 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 9 May 2014 10:48:45 +0200 Subject: [PATCH 038/114] Implemented the deprecated to function convertion for dimensions --- .../HasTrackedLegOfCompetitorContext.java | 1 - .../impl/DeprecatedToFunctionConverter.java | 58 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index d928be85ad4..7ba1efc9cc6 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -1,7 +1,6 @@ package com.sap.sailing.datamining.data; import com.sap.sailing.domain.base.Competitor; -import com.sap.sailing.domain.common.Distance; import com.sap.sailing.domain.tracking.TrackedLegOfCompetitor; import com.sap.sse.datamining.shared.Unit; import com.sap.sse.datamining.shared.annotations.SideEffectFreeValue; diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java index 89b0f6067e1..4ce0c2edfc5 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/DeprecatedToFunctionConverter.java @@ -12,8 +12,13 @@ import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.data.HasTrackedRaceContext; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.StatisticType; +import com.sap.sailing.domain.base.Boat; +import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Moving; +import com.sap.sailing.domain.base.Nationality; +import com.sap.sailing.domain.base.WithNationality; import com.sap.sailing.domain.common.LegType; +import com.sap.sailing.domain.common.Named; import com.sap.sailing.domain.common.Speed; import com.sap.sse.datamining.factories.FunctionFactory; import com.sap.sse.datamining.functions.Function; @@ -128,32 +133,85 @@ public class DeprecatedToFunctionConverter { } for (DimensionIdentifier dimensionIdentifier : DimensionIdentifier.values()) { + FunctionDTO functionDTO = getFunctionDTOFor(dimensionIdentifier); + Method method = null; + Function function = null; + + method = getNullaryMethodFromClass(Named.class, "getName"); + Function getName = FunctionFactory.createMethodWrappingFunction(method); switch (dimensionIdentifier) { case BoatClassName: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getBoatClass"); + Function getBoatClass = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Boat Class Name", + Arrays.asList(getBoatClass, getName)); break; case CompetitorName: + method = getNullaryMethodFromClass(HasTrackedLegOfCompetitorContext.class, "getCompetitor"); + Function getCompetitor = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Competitor Name", + Arrays.asList(getCompetitor, getName)); break; case CourseAreaName: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getCourseArea"); + Function getCourseArea = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Course Area Name", + Arrays.asList(getCourseArea, getName)); break; case FleetName: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getFleet"); + Function getFleet = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Fleet Name", Arrays.asList(getFleet, getName)); break; case LegNumber: + method = getNullaryMethodFromClass(HasTrackedLegContext.class, "getLegNumber"); + function = FunctionFactory.createMethodWrappingFunction(method); break; case LegType: + method = getNullaryMethodFromClass(HasTrackedLegContext.class, "getLegType"); + function = FunctionFactory.createMethodWrappingFunction(method); break; case Nationality: + method = getNullaryMethodFromClass(HasTrackedLegOfCompetitorContext.class, "getCompetitor"); + getCompetitor = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Competitor.class, "getTeam"); + Function getTeam = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(WithNationality.class, "getNationality"); + Function getNationality = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Nationality.class, "getThreeLetterIOCAcronym"); + Function getNationalityAcronym = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Nationality", + Arrays.asList(getCompetitor, getTeam, getNationality, getNationalityAcronym)); break; case RaceName: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getRace"); + Function getRace = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Race Name", Arrays.asList(getRace, getName)); break; case RegattaName: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getRegatta"); + Function getRegatta = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Regatta Name", Arrays.asList(getRegatta, getName)); break; case SailID: + method = getNullaryMethodFromClass(HasTrackedLegOfCompetitorContext.class, "getCompetitor"); + getCompetitor = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Competitor.class, "getBoat"); + Function getBoat = FunctionFactory.createMethodWrappingFunction(method); + method = getNullaryMethodFromClass(Boat.class, "getSailID"); + Function getSailID = FunctionFactory.createMethodWrappingFunction(method); + function = FunctionFactory.createCompoundFunction("Sail ID", Arrays.asList(getCompetitor, getBoat, getSailID)); break; case WindStrength: break; case Year: + method = getNullaryMethodFromClass(HasTrackedRaceContext.class, "getYear"); + function = FunctionFactory.createMethodWrappingFunction(method); break; } + if (function != null) { + functionDTOToFunctionMap.put(functionDTO, function); + } } } From 6a38370dbb5ac9ba903185185c9d53defd196bd0 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 9 May 2014 13:55:22 +0200 Subject: [PATCH 039/114] Implemented the ProcessorQuery fabrication except the retrieval --- .../shared/impl/QueryDefinitionImpl.java | 2 +- .../HasTrackedLegOfCompetitorContext.java | 2 +- .../factories/DataMiningFactory.java | 49 +++++++++++++ .../factories/DataRetrieverFactory.java | 8 +++ .../impl/QueryDefinitionConverter.java | 28 +++----- .../TrackedLegOfCompetitorWithContext.java | 2 +- .../factories/ProcessorFactory.java | 71 +++++++++++++++++++ .../sse/datamining/impl/ProcessorQuery.java | 2 +- 8 files changed, 142 insertions(+), 22 deletions(-) create mode 100644 java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/ProcessorFactory.java diff --git a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java index 19b4a3ed7f5..7d3f6ee39b3 100644 --- a/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java +++ b/java/com.sap.sailing.datamining.shared/src/com/sap/sailing/datamining/shared/impl/QueryDefinitionImpl.java @@ -29,7 +29,7 @@ public class QueryDefinitionImpl implements QueryDefinition { filterSelection.put(dimension, selection); } - public void appenDimensionToGroupBy(FunctionDTO dimensionToGroupBy) { + public void appendDimensionToGroupBy(FunctionDTO dimensionToGroupBy) { dimensionsToGroupBy.add(dimensionToGroupBy); } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java index 7ba1efc9cc6..26f7855b7d5 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/data/HasTrackedLegOfCompetitorContext.java @@ -13,6 +13,6 @@ public interface HasTrackedLegOfCompetitorContext extends HasTrackedLegContext { public Competitor getCompetitor(); @SideEffectFreeValue(messageKey="DistanceTraveled", resultUnit=Unit.Meters, resultDecimals=0) - public double getDistanceTraveled(); + public Double getDistanceTraveled(); } \ No newline at end of file diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java index 1ad601f6da8..7b71adacddb 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java @@ -1,7 +1,12 @@ package com.sap.sailing.datamining.factories; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import com.sap.sailing.datamining.impl.DeprecatedToFunctionConverter; +import com.sap.sailing.datamining.impl.QueryDefinitionConverter; +import com.sap.sailing.datamining.shared.QueryDefinition; import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.Query; @@ -10,10 +15,16 @@ import com.sap.sse.datamining.components.ParallelDataRetriever; import com.sap.sse.datamining.components.ParallelExtractor; import com.sap.sse.datamining.components.ParallelFilter; import com.sap.sse.datamining.components.ParallelGrouper; +import com.sap.sse.datamining.components.Processor; import com.sap.sse.datamining.factories.AggregatorFactory; +import com.sap.sse.datamining.factories.ProcessorFactory; +import com.sap.sse.datamining.functions.Function; import com.sap.sse.datamining.i18n.DataMiningStringMessages; 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.deprecated.QueryImpl; +import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.workers.FiltrationWorker; import com.sap.sse.datamining.workers.WorkerBuilder; @@ -21,7 +32,45 @@ public final class DataMiningFactory { private DataMiningFactory() { } + + // TODO Delete, after the deprecated components have been removed + public Query createQuery(QueryDefinitionDeprecated queryDefinition, DataSourceType dataSource) { + return createQuery(QueryDefinitionConverter.convertDeprecatedQueryDefinition(queryDefinition), dataSource); + } + // TODO Make public, after the deprecated components have been removed + private static Query createQuery(QueryDefinition queryDefinition, DataSourceType dataSource) { + ProcessorQuery query = ProcessorFactory.createProcessorQuery(dataSource, queryDefinition.getLocaleInfoName()); + Processor> aggregationProcessor = ProcessorFactory.createAggregationProcessor(query, queryDefinition.getAggregatorType()); + + Function extractionFunction = getExtractionFunction(queryDefinition); + Processor> extractionProcessor = ProcessorFactory.createExtractionProcessor(aggregationProcessor, extractionFunction); + + List> dimensionsToGroupBy = getDimensionsToGroupBy(queryDefinition); + Processor groupingProcessor = ProcessorFactory.createGroupingProcessor(extractionProcessor, dimensionsToGroupBy); + + Processor firstRetrievalProcessor = DataRetrieverFactory.createRetrievalProcessorChain(groupingProcessor, queryDefinition.getFilterSelection()); + + query.setFirstProcessor(firstRetrievalProcessor); + return query; + } + + //TODO Get the function from the function provider, not the converter + @SuppressWarnings("unchecked") // All extraction functions in the DeprecatedToFunctionConverter have the return type Double + private static Function getExtractionFunction(QueryDefinition queryDefinition) { + return (Function) DeprecatedToFunctionConverter.getFunctionFor(queryDefinition.getExtractionFunction()); + } + + //TODO Get the functions from the function provider, not the converter + private static List> getDimensionsToGroupBy(QueryDefinition queryDefinition) { + List> dimensionsToGroupBy = new ArrayList<>(); + for (FunctionDTO functionDTO : queryDefinition.getDimensionsToGroupBy()) { + dimensionsToGroupBy.add(DeprecatedToFunctionConverter.getFunctionFor(functionDTO)); + } + return dimensionsToGroupBy; + } + + @Deprecated public static Query createQuery( QueryDefinitionDeprecated queryDefinition, RacingEventService racingService) { Locale locale = DataMiningStringMessages.Util.getLocaleFrom(queryDefinition.getLocaleInfoName()); diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java index 3b5e9ba1987..1670111d172 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java @@ -1,5 +1,6 @@ package com.sap.sailing.datamining.factories; +import java.util.Map; import java.util.concurrent.ThreadPoolExecutor; import com.sap.sailing.datamining.impl.components.deprecated.GroupDividingParallelDataRetriever; @@ -8,6 +9,8 @@ import com.sap.sailing.datamining.shared.DataTypes; import com.sap.sailing.domain.leaderboard.LeaderboardGroup; import com.sap.sailing.server.RacingEventService; import com.sap.sse.datamining.components.ParallelDataRetriever; +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.workers.DataRetrievalWorker; import com.sap.sse.datamining.workers.WorkerBuilder; @@ -15,6 +18,11 @@ public final class DataRetrieverFactory { private DataRetrieverFactory() { } + + public static Processor createRetrievalProcessorChain(Processor groupingProcessor, Map> filterSelection) { + //TODO implement me + return null; + } /** * Creates a retriever for the given data type. Throws an exception, if the used DataType doesn't match diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java index b6d3e3d782b..cb68672962a 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/QueryDefinitionConverter.java @@ -5,38 +5,30 @@ import java.util.Map.Entry; import com.sap.sailing.datamining.shared.DimensionIdentifier; import com.sap.sailing.datamining.shared.QueryDefinition; import com.sap.sailing.datamining.shared.QueryDefinitionDeprecated; -import com.sap.sailing.datamining.shared.StatisticType; import com.sap.sailing.datamining.shared.impl.QueryDefinitionImpl; -import com.sap.sse.datamining.shared.dto.FunctionDTO; public class QueryDefinitionConverter { public static QueryDefinition convertDeprecatedQueryDefinition(QueryDefinitionDeprecated queryDefinitionDeprecated) { - //TODO implement the statistic type to function conversion QueryDefinitionImpl queryDefinition = new QueryDefinitionImpl(queryDefinitionDeprecated.getLocaleInfoName(), - convertToFunctionDTO(queryDefinitionDeprecated.getStatisticType()), queryDefinitionDeprecated.getAggregatorType()); + DeprecatedToFunctionConverter.getFunctionDTOFor(queryDefinitionDeprecated.getStatisticType()), + queryDefinitionDeprecated.getAggregatorType()); - for (Entry> filterSelectionEntry : queryDefinitionDeprecated.getSelection().entrySet()) { - //TODO implement the dimension identifier to function conversion - queryDefinition.setFilterSelectionFor(convertToFunctionDTO(filterSelectionEntry.getKey()), - filterSelectionEntry.getValue()); + for (Entry> filterSelectionEntry : queryDefinitionDeprecated.getSelection() + .entrySet()) { + queryDefinition.setFilterSelectionFor( + DeprecatedToFunctionConverter.getFunctionDTOFor(filterSelectionEntry.getKey()), + filterSelectionEntry.getValue()); } - + for (DimensionIdentifier dimensionIdentifier : queryDefinitionDeprecated.getDimensionsToGroupBy()) { - queryDefinition.appenDimensionToGroupBy(convertToFunctionDTO(dimensionIdentifier)); + queryDefinition.appendDimensionToGroupBy(DeprecatedToFunctionConverter + .getFunctionDTOFor(dimensionIdentifier)); } return queryDefinition; } - private static FunctionDTO convertToFunctionDTO(StatisticType statisticType) { - return DeprecatedToFunctionConverter.getFunctionDTOFor(statisticType); - } - - private static FunctionDTO convertToFunctionDTO(DimensionIdentifier dimensionIdentifier) { - return DeprecatedToFunctionConverter.getFunctionDTOFor(dimensionIdentifier); - } - private QueryDefinitionConverter() { } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java index bc6923b00d9..e956e796fd7 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/impl/data/TrackedLegOfCompetitorWithContext.java @@ -40,7 +40,7 @@ public class TrackedLegOfCompetitorWithContext extends TrackedLegWithContext imp } @Override - public double getDistanceTraveled() { + public Double getDistanceTraveled() { TimePoint timePoint = getTrackedRace().getEndOfTracking(); return getTrackedLegOfCompetitor().getDistanceTraveled(timePoint).getMeters(); } diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/ProcessorFactory.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/ProcessorFactory.java new file mode 100644 index 00000000000..4b402a2e431 --- /dev/null +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/factories/ProcessorFactory.java @@ -0,0 +1,71 @@ +package com.sap.sse.datamining.factories; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; + +import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.functions.Function; +import com.sap.sse.datamining.i18n.DataMiningStringMessages; +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.ParallelGroupedElementsValueExtractionProcessor; +import com.sap.sse.datamining.impl.components.ParallelMultiDimensionalGroupingProcessor; +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; +import com.sap.sse.datamining.shared.GroupKey; +import com.sap.sse.datamining.shared.components.AggregatorType; + +public class ProcessorFactory { + + private ProcessorFactory() { + } + + public static ProcessorQuery createProcessorQuery(DataSourceType dataSource, String localeInfoName) { + return new ProcessorQuery(DataMiningActivator.getExecutor(), dataSource, + DataMiningActivator.getStringMessages(), DataMiningStringMessages.Util.getLocaleFrom(localeInfoName)); + } + + public static Processor> createAggregationProcessor(ProcessorQuery query, AggregatorType aggregatorType) { + Collection>> resultReceivers = Arrays.asList(query.getResultReceiver()); + return createAggregationProcessor(aggregatorType, resultReceivers); + } + + public static Processor> createAggregationProcessor(AggregatorType aggregatorType, Collection>> resultReceivers) { + ExecutorService executor = DataMiningActivator.getExecutor(); + switch (aggregatorType) { + case Average: + return new ParallelGroupedDoubleDataAverageAggregationProcessor(executor, resultReceivers); + case Median: + return new ParallelGroupedDoubleDataMedianAggregationProcessor(executor, resultReceivers); + case Sum: + return new ParallelGroupedDoubleDataSumAggregationProcessor(executor, resultReceivers); + default: + throw new IllegalArgumentException("No aggregation processor implemented for the aggregation type '" + aggregatorType + "'"); + } + } + + public static Processor> createExtractionProcessor( + Processor> aggregationProcessor, Function extractionFunction) { + return createExtractionProcessor(Arrays.asList(aggregationProcessor), extractionFunction); + } + + public static Processor> createExtractionProcessor( + Collection>> resultReceivers, Function extractionFunction) { + return new ParallelGroupedElementsValueExtractionProcessor(DataMiningActivator.getExecutor(), + resultReceivers, extractionFunction); + } + + public static Processor createGroupingProcessor(Processor> extractionProcessor, List> dimensionsToGroupBy) { + return createGroupingProcessor(Arrays.asList(extractionProcessor), dimensionsToGroupBy); + } + + public static Processor createGroupingProcessor(Collection>> resultReceivers, List> dimensionsToGroupBy) { + return new ParallelMultiDimensionalGroupingProcessor<>(DataMiningActivator.getExecutor(), resultReceivers, dimensionsToGroupBy); + } + +} diff --git a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java index 11df025ae51..8f9d85abf6b 100644 --- a/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java +++ b/java/com.sap.sse.datamining/src/com/sap/sse/datamining/impl/ProcessorQuery.java @@ -140,7 +140,7 @@ public class ProcessorQuery implements Query> getResultReceiver() { + public Processor> getResultReceiver() { return resultReceiver; } From 0c5f4a10490de29c6533ff0290de91e565a115ea Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 16 May 2014 14:01:42 +0200 Subject: [PATCH 040/114] Implemented the retriever construction --- .../factories/DataMiningFactory.java | 18 +++++- .../factories/DataRetrieverFactory.java | 60 ++++++++++++++++++- .../factories/SailingDataRetrievalLevels.java | 7 +++ 3 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/SailingDataRetrievalLevels.java diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java index 7b71adacddb..39453295d6d 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataMiningFactory.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import com.sap.sailing.datamining.data.HasGPSFixContext; +import com.sap.sailing.datamining.data.HasTrackedLegOfCompetitorContext; import com.sap.sailing.datamining.impl.DeprecatedToFunctionConverter; import com.sap.sailing.datamining.impl.QueryDefinitionConverter; import com.sap.sailing.datamining.shared.QueryDefinition; @@ -29,7 +31,7 @@ import com.sap.sse.datamining.workers.FiltrationWorker; import com.sap.sse.datamining.workers.WorkerBuilder; public final class DataMiningFactory { - + private DataMiningFactory() { } @@ -49,7 +51,8 @@ public final class DataMiningFactory { List> dimensionsToGroupBy = getDimensionsToGroupBy(queryDefinition); Processor groupingProcessor = ProcessorFactory.createGroupingProcessor(extractionProcessor, dimensionsToGroupBy); - Processor firstRetrievalProcessor = DataRetrieverFactory.createRetrievalProcessorChain(groupingProcessor, queryDefinition.getFilterSelection()); + SailingDataRetrievalLevels dataRetrievalLevel = calculateDataRetrievalLevel(extractionFunction); + Processor firstRetrievalProcessor = DataRetrieverFactory.createRetrievalProcessorChain(dataRetrievalLevel, groupingProcessor, queryDefinition.getFilterSelection()); query.setFirstProcessor(firstRetrievalProcessor); return query; @@ -69,6 +72,17 @@ public final class DataMiningFactory { } return dimensionsToGroupBy; } + + //TODO Generalize the way to calculate the base data type from the extraction function + private static SailingDataRetrievalLevels calculateDataRetrievalLevel(Function extractionFunction) { + if (extractionFunction.getDeclaringType().equals(HasGPSFixContext.class)) { + return SailingDataRetrievalLevels.GPSFix; + } + if (extractionFunction.getDeclaringType().equals(HasTrackedLegOfCompetitorContext.class)) { + return SailingDataRetrievalLevels.TrackedLegOfCompetitor; + } + return SailingDataRetrievalLevels.GPSFix; + } @Deprecated public static Query createQuery( diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java index 1670111d172..7a97cb53121 100644 --- a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/DataRetrieverFactory.java @@ -1,15 +1,27 @@ package com.sap.sailing.datamining.factories; +import java.util.Arrays; import java.util.Map; import java.util.concurrent.ThreadPoolExecutor; +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.impl.components.GPSFixRetrievalProcessor; +import com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor; +import com.sap.sailing.datamining.impl.components.RegattaLeaderboardFilteringRetrievalProcessor; +import com.sap.sailing.datamining.impl.components.TrackedLegFilteringRetrievalProcessor; +import com.sap.sailing.datamining.impl.components.TrackedLegOfCompetitorFilteringRetrievalProcessor; import com.sap.sailing.datamining.impl.components.deprecated.GroupDividingParallelDataRetriever; import com.sap.sailing.datamining.impl.workers.builders.deprecated.DataRetrieverWorkerBuilder; import com.sap.sailing.datamining.shared.DataTypes; 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.ParallelDataRetriever; import com.sap.sse.datamining.components.Processor; +import com.sap.sse.datamining.impl.DataMiningActivator; import com.sap.sse.datamining.shared.dto.FunctionDTO; import com.sap.sse.datamining.workers.DataRetrievalWorker; import com.sap.sse.datamining.workers.WorkerBuilder; @@ -19,8 +31,52 @@ public final class DataRetrieverFactory { private DataRetrieverFactory() { } - public static Processor createRetrievalProcessorChain(Processor groupingProcessor, Map> filterSelection) { - //TODO implement me + /** + * Creates the processor chain for the data retrieval and returns the first processor of the chain. + * @param groupingProcessor The result receiver after the retrieval + * @param filterSelection The filter functions and values for the filtration + * @return The first processor of the retrieval chain. + */ + @SuppressWarnings("unchecked") + public static Processor createRetrievalProcessorChain(SailingDataRetrievalLevels dataRetrievalLevel, Processor groupingProcessor, Map> filterSelection) { + Processor resultReceiver = groupingProcessor; + for (int i = dataRetrievalLevel.ordinal(); i <= 0; i--) { + resultReceiver = createDataRetrieverFor(SailingDataRetrievalLevels.values()[i], resultReceiver, filterSelection); + } + return (Processor) resultReceiver; + } + + @SuppressWarnings("unchecked") + /* The way this method is used should guarantee, that the result receiver matches the new processor + */ + private static Processor createDataRetrieverFor(SailingDataRetrievalLevels dataRetrievalLevel, + Processor resultReceiver, Map> filterSelection) { + ThreadPoolExecutor executor = DataMiningActivator.getExecutor(); + + switch (dataRetrievalLevel) { + case GPSFix: + Processor gpsFixSpecificResultReceiver = (Processor) resultReceiver; + return new GPSFixRetrievalProcessor(executor, Arrays.asList(gpsFixSpecificResultReceiver)); + case LeaderboardGroup: + Processor leaderboardGroupSpecificResultReceiver = (Processor) resultReceiver; + return new LeaderboardGroupRetrievalProcessor(executor, Arrays.asList(leaderboardGroupSpecificResultReceiver)); + case RegattaLeaderboard: + Processor regattaLeaderboardSpecificResultReceiver = (Processor) resultReceiver; + return new RegattaLeaderboardFilteringRetrievalProcessor(executor, Arrays.asList(regattaLeaderboardSpecificResultReceiver), getFilterCriteriaForBaseDataType(RegattaLeaderboard.class, filterSelection)); + case TrackedLeg: + Processor trackedLegSpecificResultReceiver = (Processor) resultReceiver; + return new TrackedLegFilteringRetrievalProcessor(executor, Arrays.asList(trackedLegSpecificResultReceiver), getFilterCriteriaForBaseDataType(HasTrackedLegContext.class, filterSelection)); + case TrackedLegOfCompetitor: + Processor trackedLegOfCompetitorSpecificResultReceiver = (Processor) resultReceiver; + return new TrackedLegOfCompetitorFilteringRetrievalProcessor(executor, Arrays.asList(trackedLegOfCompetitorSpecificResultReceiver), getFilterCriteriaForBaseDataType(HasTrackedLegOfCompetitorContext.class, filterSelection)); + } + throw new IllegalArgumentException("No data retriever implemented for the given data retrieval level '" + + dataRetrievalLevel + "'"); + } + + private static FilterCriteria getFilterCriteriaForBaseDataType(Class baseDataType, + Map> filterSelection) { + // TODO Auto-generated method stub return null; } diff --git a/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/SailingDataRetrievalLevels.java b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/SailingDataRetrievalLevels.java new file mode 100644 index 00000000000..616aa3215d5 --- /dev/null +++ b/java/com.sap.sailing.datamining/src/com/sap/sailing/datamining/factories/SailingDataRetrievalLevels.java @@ -0,0 +1,7 @@ +package com.sap.sailing.datamining.factories; + +public enum SailingDataRetrievalLevels { + + LeaderboardGroup, RegattaLeaderboard, TrackedLeg, TrackedLegOfCompetitor, GPSFix + +} From 379b04f1248e7e725bd14c0168edd4de6ddd1fd8 Mon Sep 17 00:00:00 2001 From: Lennart Hensler Date: Fri, 16 May 2014 14:02:31 +0200 Subject: [PATCH 041/114] Added race data files to the sailing datamining test bundle --- .../.classpath | 1 + .../event_20110609_KielerWoch-505_Race_2.mtb | Bin 0 -> 6537826 bytes .../event_20110609_KielerWoch-505_Race_2.txt | 1419 +++++++++++++++ .../event_20110609_KielerWoch-505_Race_3.mtb | Bin 0 -> 7572813 bytes .../event_20110609_KielerWoch-505_Race_3.txt | 1419 +++++++++++++++ .../event_20110609_KielerWoch-505_race_4.mtb | Bin 0 -> 8591202 bytes .../event_20110609_KielerWoch-505_race_4.txt | 1547 +++++++++++++++++ 7 files changed, 4386 insertions(+) create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_2.mtb create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_2.txt create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_3.mtb create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_3.txt create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_race_4.mtb create mode 100644 java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_race_4.txt diff --git a/java/com.sap.sailing.datamining.test/.classpath b/java/com.sap.sailing.datamining.test/.classpath index 5c0149e1673..ba4e0d198fd 100644 --- a/java/com.sap.sailing.datamining.test/.classpath +++ b/java/com.sap.sailing.datamining.test/.classpath @@ -4,5 +4,6 @@ + diff --git a/java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_2.mtb b/java/com.sap.sailing.datamining.test/resources/event_20110609_KielerWoch-505_Race_2.mtb new file mode 100644 index 0000000000000000000000000000000000000000..38321e1dff2e6f532ba08f77df8caff210f0c372 GIT binary patch literal 6537826 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⁢1@Zb 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