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