aboutsummaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorLeif Åstrand <legioth@gmail.com>2017-01-20 10:34:33 +0200
committerGitHub <noreply@github.com>2017-01-20 10:34:33 +0200
commitcb264dacfe74cba1266b54df8ce8c6ded1510004 (patch)
treedef7d7988d42ce2add93391a002399a4ce2949ff /server/src
parent1fb40df8742791803e0a08328028bbbd67deb78b (diff)
downloadvaadin-framework-cb264dacfe74cba1266b54df8ce8c6ded1510004.tar.gz
vaadin-framework-cb264dacfe74cba1266b54df8ce8c6ded1510004.zip
Add a data provider wrapper with a configurable filter (#8280)
* Add a data provider wrapper with a configurable filter This is one of many steps towards #8245
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java42
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProvider.java43
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapper.java79
-rw-r--r--server/src/main/java/com/vaadin/data/provider/DataProviderWrapper.java6
-rw-r--r--server/src/main/java/com/vaadin/data/provider/ListDataProvider.java4
-rw-r--r--server/src/main/java/com/vaadin/server/SerializableBiFunction.java39
-rw-r--r--server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java42
-rw-r--r--server/src/test/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapperTest.java96
8 files changed, 331 insertions, 20 deletions
diff --git a/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java b/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
index 96d5e54394..199d0b64fe 100644
--- a/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java
@@ -18,6 +18,8 @@ package com.vaadin.data.provider;
import java.util.Collections;
import java.util.List;
+import com.vaadin.server.SerializableBiFunction;
+
/**
* A data provider that lazy loads items from a back end.
*
@@ -71,4 +73,44 @@ public interface BackEndDataProvider<T, F> extends DataProvider<T, F> {
default boolean isInMemory() {
return false;
}
+
+ /**
+ * Wraps this data provider to create a data provider that supports
+ * programmatically setting a filter that will be combined with a filter
+ * provided through the query.
+ *
+ * @see #withConfigurableFilter()
+ *
+ * @param filterCombiner
+ * a callback for combining and the configured filter with the
+ * filter from the query to get a filter to pass to the wrapped
+ * provider. Will only be called if the query contains a filter.
+ *
+ * @return a data provider with a configurable filter, not <code>null</code>
+ */
+ public default <C> ConfigurableFilterDataProvider<T, C, F> withConfigurableFilter(
+ SerializableBiFunction<F, C, F> filterCombiner) {
+ return new ConfigurableFilterDataProviderWrapper<T, C, F>(this) {
+ @Override
+ protected F combineFilters(F configuredFilter, C queryFilter) {
+ return filterCombiner.apply(configuredFilter, queryFilter);
+ }
+ };
+ }
+
+ /**
+ * Wraps this data provider to create a data provider that supports
+ * programmatically setting a filter but no filtering through the query.
+ *
+ * @see #withConfigurableFilter(SerializableBiFunction)
+ *
+ * @return a data provider with a configurable filter, not <code>null</code>
+ */
+ public default ConfigurableFilterDataProvider<T, Void, F> withConfigurableFilter() {
+ return withConfigurableFilter((configuredFilter, queryFilter) -> {
+ assert queryFilter == null : "Filter from Void query must be null";
+
+ return configuredFilter;
+ });
+ }
}
diff --git a/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProvider.java b/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProvider.java
new file mode 100644
index 0000000000..8521e5498a
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+/**
+ * A data provider that supports programmatically setting a filter that will be
+ * applied to all queries.
+ *
+ * @author Vaadin Ltd
+ *
+ * @param <T>
+ * the data provider item type
+ * @param <Q>
+ * the query filter type
+ * @param <C>
+ * the configurable filter type
+ */
+public interface ConfigurableFilterDataProvider<T, Q, C>
+ extends DataProvider<T, Q> {
+
+ /**
+ * Sets the filter to use for all queries handled by this data provider.
+ *
+ * @param filter
+ * the filter to set, or <code>null</code> to clear any
+ * previously set filter
+ */
+ public void setFilter(C filter);
+
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapper.java b/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapper.java
new file mode 100644
index 0000000000..c6256787ce
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapper.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+/**
+ * A configurable data provider that wraps another data provider by combining
+ * any filter from the component with the configured filter and passing that to
+ * the wrapped provider through the query.
+ *
+ * @author Vaadin Ltd
+ *
+ * @param <T>
+ * the data provider item type
+ * @param <Q>
+ * the query filter type
+ * @param <C>
+ * the configurable filter type
+ */
+public abstract class ConfigurableFilterDataProviderWrapper<T, Q, C>
+ extends DataProviderWrapper<T, Q, C>
+ implements ConfigurableFilterDataProvider<T, Q, C> {
+
+ private C configuredFilter;
+
+ /**
+ * Creates a new configurable filter data provider by wrapping an existing
+ * data provider.
+ *
+ * @param dataProvider
+ * the data provider to wrap, not <code>null</code>
+ */
+ public ConfigurableFilterDataProviderWrapper(
+ DataProvider<T, C> dataProvider) {
+ super(dataProvider);
+ }
+
+ @Override
+ protected C getFilter(Query<T, Q> query) {
+ return query.getFilter().map(
+ queryFilter -> combineFilters(configuredFilter, queryFilter))
+ .orElse(configuredFilter);
+ }
+
+ /**
+ * Combines the configured filter and the filter from the query into one
+ * filter instance that can be passed to the wrapped data provider. This
+ * method is called only if there is a query filter, otherwise the
+ * configured filter will be directly passed to the query.
+ *
+ * @param configuredFilter
+ * the filter that this data provider is configured to use, or
+ * <code>null</code> if no filter has been configured
+ * @param queryFilter
+ * the filter received through the query, not <code>null</code>
+ * @return a filter that combines the two provided queries, or
+ * <code>null</code> to not pass any filter to the wrapped data
+ * provider
+ */
+ protected abstract C combineFilters(C configuredFilter, Q queryFilter);
+
+ @Override
+ public void setFilter(C filter) {
+ this.configuredFilter = filter;
+ refreshAll();
+ }
+}
diff --git a/server/src/main/java/com/vaadin/data/provider/DataProviderWrapper.java b/server/src/main/java/com/vaadin/data/provider/DataProviderWrapper.java
index f792c8c255..b6f835ac42 100644
--- a/server/src/main/java/com/vaadin/data/provider/DataProviderWrapper.java
+++ b/server/src/main/java/com/vaadin/data/provider/DataProviderWrapper.java
@@ -15,6 +15,7 @@
*/
package com.vaadin.data.provider;
+import java.util.Objects;
import java.util.stream.Stream;
import com.vaadin.server.SerializableFunction;
@@ -78,10 +79,11 @@ public abstract class DataProviderWrapper<T, F, M>
* Constructs a filtering wrapper for a data provider.
*
* @param dataProvider
- * the wrapped data provider
+ * the wrapped data provider, not <code>null</code>
*/
protected DataProviderWrapper(DataProvider<T, M> dataProvider) {
- this.dataProvider = dataProvider;
+ this.dataProvider = Objects.requireNonNull(dataProvider,
+ "The wrapped data provider cannot be null.");
}
@Override
diff --git a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
index 3d021dc0e6..470339bc2a 100644
--- a/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
+++ b/server/src/main/java/com/vaadin/data/provider/ListDataProvider.java
@@ -35,7 +35,8 @@ import com.vaadin.shared.data.sort.SortDirection;
*/
public class ListDataProvider<T>
extends AbstractDataProvider<T, SerializablePredicate<T>>
- implements AppendableFilterDataProvider<T, SerializablePredicate<T>> {
+ implements AppendableFilterDataProvider<T, SerializablePredicate<T>>,
+ ConfigurableFilterDataProvider<T, SerializablePredicate<T>, SerializablePredicate<T>> {
private SerializableComparator<T> sortOrder = null;
@@ -236,6 +237,7 @@ public class ListDataProvider<T>
* the filter to set, or <code>null</code> to remove any set
* filters
*/
+ @Override
public void setFilter(SerializablePredicate<T> filter) {
this.filter = filter;
refreshAll();
diff --git a/server/src/main/java/com/vaadin/server/SerializableBiFunction.java b/server/src/main/java/com/vaadin/server/SerializableBiFunction.java
new file mode 100644
index 0000000000..04d082c283
--- /dev/null
+++ b/server/src/main/java/com/vaadin/server/SerializableBiFunction.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.io.Serializable;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * A {@link BiFunction} that is also {@link Serializable}.
+ *
+ * @see Function
+ * @author Vaadin Ltd
+ * @since 8.0
+ * @param <T>
+ * the type of the the first function parameter
+ * @param <U>
+ * the type of the the second function parameter
+ * @param <R>
+ * the type of the result of the function
+ */
+@FunctionalInterface
+public interface SerializableBiFunction<T, U, R>
+ extends BiFunction<T, U, R>, Serializable {
+ // Only method inherited from BiFunction
+}
diff --git a/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java b/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java
index 797f14957c..e2f5211d00 100644
--- a/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java
+++ b/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java
@@ -23,7 +23,7 @@ public class BackendDataProviderTest extends
Comparator.comparing(StrBean::getRandomNumber));
}
- private Comparator<StrBean> getComparator(SortOrder<String> so) {
+ private static Comparator<StrBean> getComparator(SortOrder<String> so) {
Comparator<StrBean> comparator = propertyToComparatorMap
.get(so.getSorted());
if (so.getDirection() == SortDirection.DESCENDING) {
@@ -32,24 +32,32 @@ public class BackendDataProviderTest extends
return comparator;
}
+ public static class StrBeanBackEndDataProvider extends
+ CallbackDataProvider<StrBean, SerializablePredicate<StrBean>> {
+
+ public StrBeanBackEndDataProvider(List<StrBean> data) {
+ super(query -> {
+ Stream<StrBean> stream = data.stream().filter(
+ t -> query.getFilter().orElse(s -> true).test(t));
+ if (!query.getSortOrders().isEmpty()) {
+ Comparator<StrBean> sorting = query.getSortOrders().stream()
+ .map(BackendDataProviderTest::getComparator)
+ .reduce((c1, c2) -> c1.thenComparing(c2)).get();
+ stream = stream.sorted(sorting);
+ }
+ List<StrBean> list = stream.skip(query.getOffset())
+ .limit(query.getLimit()).collect(Collectors.toList());
+ list.forEach(s -> System.err.println(s.toString()));
+ return list.stream();
+ }, query -> (int) data.stream()
+ .filter(t -> query.getFilter().orElse(s -> true).test(t))
+ .count());
+ }
+ }
+
@Override
protected BackEndDataProvider<StrBean, SerializablePredicate<StrBean>> createDataProvider() {
- return dataProvider = new CallbackDataProvider<>(query -> {
- Stream<StrBean> stream = data.stream()
- .filter(t -> query.getFilter().orElse(s -> true).test(t));
- if (!query.getSortOrders().isEmpty()) {
- Comparator<StrBean> sorting = query.getSortOrders().stream()
- .map(this::getComparator)
- .reduce((c1, c2) -> c1.thenComparing(c2)).get();
- stream = stream.sorted(sorting);
- }
- List<StrBean> list = stream.skip(query.getOffset())
- .limit(query.getLimit()).collect(Collectors.toList());
- list.forEach(s -> System.err.println(s.toString()));
- return list.stream();
- }, query -> (int) data.stream()
- .filter(t -> query.getFilter().orElse(s -> true).test(t))
- .count());
+ return dataProvider = new StrBeanBackEndDataProvider(data);
}
@Override
diff --git a/server/src/test/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapperTest.java b/server/src/test/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapperTest.java
new file mode 100644
index 0000000000..115e4fd6bd
--- /dev/null
+++ b/server/src/test/java/com/vaadin/data/provider/ConfigurableFilterDataProviderWrapperTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.provider;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.data.provider.BackendDataProviderTest.StrBeanBackEndDataProvider;
+import com.vaadin.server.SerializablePredicate;
+
+public class ConfigurableFilterDataProviderWrapperTest {
+ private static SerializablePredicate<StrBean> xyzFilter = item -> item
+ .getValue().equals("Xyz");
+
+ private StrBeanBackEndDataProvider backEndProvider = new StrBeanBackEndDataProvider(
+ StrBean.generateRandomBeans(100));
+ private ConfigurableFilterDataProvider<StrBean, Void, SerializablePredicate<StrBean>> configurableVoid = backEndProvider
+ .withConfigurableFilter();
+ private ConfigurableFilterDataProvider<StrBean, SerializablePredicate<StrBean>, SerializablePredicate<StrBean>> configurablePredicate = backEndProvider
+ .withConfigurableFilter((configuredFilter, queryFilter) -> item -> {
+ if (configuredFilter != null && !configuredFilter.test(item)) {
+ return false;
+ }
+
+ return queryFilter.test(item);
+ });
+
+ @Test
+ public void void_setFilter() {
+ configurableVoid.setFilter(xyzFilter);
+
+ Assert.assertEquals("Set filter should be used", 1,
+ configurableVoid.size(new Query<>()));
+
+ configurableVoid.setFilter(null);
+
+ Assert.assertEquals("null filter should return all items", 100,
+ configurableVoid.size(new Query<>()));
+ }
+
+ @Test(expected = Exception.class)
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void void_nonNullQueryFilter_throws() {
+ configurableVoid
+ .size((Query) new Query<StrBean, String>("invalid filter"));
+ }
+
+ @Test
+ public void predicate_setFilter() {
+ configurablePredicate.setFilter(xyzFilter);
+
+ Assert.assertEquals("Set filter should be used", 1,
+ configurablePredicate.size(new Query<>()));
+
+ configurablePredicate.setFilter(null);
+
+ Assert.assertEquals("null filter should return all items", 100,
+ configurablePredicate.size(new Query<>()));
+ }
+
+ @Test
+ public void predicate_queryFilter() {
+ Assert.assertEquals("Query filter should be used", 1,
+ configurablePredicate.size(new Query<>(xyzFilter)));
+
+ Assert.assertEquals("null query filter should return all items", 100,
+ configurablePredicate.size(new Query<>()));
+ }
+
+ @Test
+ public void predicate_combinedFilters() {
+ configurablePredicate.setFilter(item -> item.getValue().equals("Foo"));
+
+ Assert.assertEquals("Both filters should be used", 0,
+ configurablePredicate.size(new Query<>(xyzFilter)));
+
+ configurablePredicate.setFilter(null);
+
+ Assert.assertEquals("Only zyz filter should be used", 1,
+ configurablePredicate.size(new Query<>(xyzFilter)));
+ }
+
+}