From dafc8310259a2e79bb203c7f786c9aba5354937b Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Thu, 19 Jan 2017 09:12:24 +0200 Subject: Change BackEndDataProvider into an interface (#8268) * Change BackEndDataProvider into an interface BackEndDataProvider is now an interface with methods for setting sorting options based on SortOrder instances. AbstractBackEndDataProvider stores sorting options, combines them with the sorting provided in the query and invokes its own abstract fetch and size methods. CallbackDataProvider implements a BackEndDataProvider based on two lambdas. This is one of many steps towards #8245 --- .../data/provider/AbstractBackEndDataProvider.java | 95 ++++++++++++++++++++++ .../vaadin/data/provider/BackEndDataProvider.java | 72 ++-------------- .../vaadin/data/provider/CallbackDataProvider.java | 69 ++++++++++++++++ .../com/vaadin/data/provider/DataCommunicator.java | 10 +-- .../com/vaadin/data/provider/DataProvider.java | 6 +- .../data/provider/BackendDataProviderTest.java | 2 +- .../data/provider/bov/DataProviderBoVTest.java | 6 +- .../grid/GridMultiSelectionModelTest.java | 4 +- .../java/com/vaadin/ui/AbstractListingTest.java | 7 +- 9 files changed, 185 insertions(+), 86 deletions(-) create mode 100644 server/src/main/java/com/vaadin/data/provider/AbstractBackEndDataProvider.java create mode 100644 server/src/main/java/com/vaadin/data/provider/CallbackDataProvider.java (limited to 'server') diff --git a/server/src/main/java/com/vaadin/data/provider/AbstractBackEndDataProvider.java b/server/src/main/java/com/vaadin/data/provider/AbstractBackEndDataProvider.java new file mode 100644 index 0000000000..8da5d7a726 --- /dev/null +++ b/server/src/main/java/com/vaadin/data/provider/AbstractBackEndDataProvider.java @@ -0,0 +1,95 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * Abstract base class for implementing back end data providers. + * + * @param + * data provider data type + * @param + * data provider filter type + */ +public abstract class AbstractBackEndDataProvider extends + AbstractDataProvider implements BackEndDataProvider { + + private List> sortOrders = new ArrayList<>(); + + private Query mixInSortOrders(Query query) { + if (sortOrders.isEmpty()) { + return query; + } + + Set sortedPropertyNames = query.getSortOrders().stream() + .map(SortOrder::getSorted).collect(Collectors.toSet()); + + List> combinedSortOrders = Stream + .concat(query.getSortOrders().stream(), + sortOrders.stream() + .filter(order -> !sortedPropertyNames + .contains(order.getSorted()))) + .collect(Collectors.toList()); + + return new Query<>(query.getOffset(), query.getLimit(), + combinedSortOrders, query.getInMemorySorting(), + query.getFilter().orElse(null)); + } + + @Override + public Stream fetch(Query query) { + return fetchFromBackEnd(mixInSortOrders(query)); + } + + @Override + public int size(Query query) { + return sizeInBackEnd(mixInSortOrders(query)); + } + + /** + * Fetches data from the back end using the given query. + * + * @param query + * the query that defines sorting, filtering and paging for + * fetching the data + * @return a stream of items matching the query + */ + protected abstract Stream fetchFromBackEnd(Query query); + + /** + * Counts the number of items available in the back end. + * + * @param query + * the query that defines filtering to be used for counting the + * number of items + * @return the number of available items + */ + protected abstract int sizeInBackEnd(Query query); + + @Override + public void setSortOrders(List> sortOrders) { + this.sortOrders = Objects.requireNonNull(sortOrders, + "Sort orders cannot be null"); + refreshAll(); + } + +} 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 3606a99ade..96d5e54394 100644 --- a/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java +++ b/server/src/main/java/com/vaadin/data/provider/BackEndDataProvider.java @@ -15,75 +15,18 @@ */ package com.vaadin.data.provider; -import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import com.vaadin.server.SerializableFunction; -import com.vaadin.server.SerializableToIntFunction; /** - * A {@link DataProvider} for any back end. + * A data provider that lazy loads items from a back end. * * @param * data provider data type * @param * data provider filter type */ -public class BackEndDataProvider extends AbstractDataProvider { - - private List> sortOrders = new ArrayList<>(); - - private final SerializableFunction, Stream> request; - private final SerializableToIntFunction> sizeCallback; - - /** - * Constructs a new DataProvider to request data from an arbitrary back end - * request function. - * - * @param request - * function that requests data from back end based on query - * @param sizeCallback - * function that return the amount of data in back end for query - */ - public BackEndDataProvider( - SerializableFunction, Stream> request, - SerializableToIntFunction> sizeCallback) { - Objects.requireNonNull(request, "Request function can't be null"); - Objects.requireNonNull(sizeCallback, "Size callback can't be null"); - this.request = request; - this.sizeCallback = sizeCallback; - } - - @Override - public Stream fetch(Query query) { - return request.apply(mixInSortOrders(query)); - } - - @Override - public int size(Query query) { - return sizeCallback.applyAsInt(mixInSortOrders(query)); - } - - private Query mixInSortOrders(Query query) { - Set sortedPropertyNames = query.getSortOrders().stream() - .map(SortOrder::getSorted).collect(Collectors.toSet()); - - List> combinedSortOrders = Stream - .concat(query.getSortOrders().stream(), - sortOrders.stream() - .filter(order -> !sortedPropertyNames - .contains(order.getSorted()))) - .collect(Collectors.toList()); - - return new Query<>(query.getOffset(), query.getLimit(), - combinedSortOrders, query.getInMemorySorting(), - query.getFilter().orElse(null)); - } +public interface BackEndDataProvider extends DataProvider { /** * Sets a list of sort orders to use as the default sorting for this data @@ -99,11 +42,7 @@ public class BackEndDataProvider extends AbstractDataProvider { * @param sortOrders * a list of sort orders to set, not null */ - public void setSortOrders(List> sortOrders) { - this.sortOrders = Objects.requireNonNull(sortOrders, - "Sort orders cannot be null"); - refreshAll(); - } + void setSortOrders(List> sortOrders); /** * Sets a single sort order to use as the default sorting for this data @@ -120,7 +59,7 @@ public class BackEndDataProvider extends AbstractDataProvider { * a sort order to set, or null to clear any * previously set sort orders */ - public void setSortOrder(SortOrder sortOrder) { + default void setSortOrder(SortOrder sortOrder) { if (sortOrder == null) { setSortOrders(Collections.emptyList()); } else { @@ -129,8 +68,7 @@ public class BackEndDataProvider extends AbstractDataProvider { } @Override - public boolean isInMemory() { + default boolean isInMemory() { return false; } - } diff --git a/server/src/main/java/com/vaadin/data/provider/CallbackDataProvider.java b/server/src/main/java/com/vaadin/data/provider/CallbackDataProvider.java new file mode 100644 index 0000000000..dcb0340416 --- /dev/null +++ b/server/src/main/java/com/vaadin/data/provider/CallbackDataProvider.java @@ -0,0 +1,69 @@ +/* + * 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 java.util.Objects; +import java.util.stream.Stream; + +import com.vaadin.server.SerializableFunction; +import com.vaadin.server.SerializableToIntFunction; + +/** + * Data provider that uses one callback for fetching items from a back end and + * another callback for counting the number of available items. + * + * @author Vaadin Ltd + * + * @param + * data provider data type + * @param + * data provider filter type + */ +public class CallbackDataProvider + extends AbstractBackEndDataProvider { + private final SerializableFunction, Stream> fetchCallback; + private final SerializableToIntFunction> sizeCallback; + + /** + * Constructs a new DataProvider to request data using callbacks for + * fetching and counting items in the back end. + * + * @param fetchCallback + * function that returns a stream of items from the back end for + * a query + * @param sizeCallback + * function that return the number of items in the back end for a + * query + */ + public CallbackDataProvider( + SerializableFunction, Stream> fetchCallback, + SerializableToIntFunction> sizeCallback) { + Objects.requireNonNull(fetchCallback, "Request function can't be null"); + Objects.requireNonNull(sizeCallback, "Size callback can't be null"); + this.fetchCallback = fetchCallback; + this.sizeCallback = sizeCallback; + } + + @Override + public Stream fetchFromBackEnd(Query query) { + return fetchCallback.apply(query); + } + + @Override + protected int sizeInBackEnd(Query query) { + return sizeCallback.applyAsInt(query); + } +} diff --git a/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java b/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java index c9523fc34b..12fd323bc1 100644 --- a/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java +++ b/server/src/main/java/com/vaadin/data/provider/DataCommunicator.java @@ -85,9 +85,9 @@ public class DataCommunicator extends AbstractExtension { *

* When the {@link DataCommunicator} is pushing new data to the client-side * via {@link DataCommunicator#pushData(int, Stream)}, - * {@link #addActiveData(Stream)} and {@link #cleanUp(Stream)} are - * called with the same parameter. In the clean up method any dropped data - * objects that are not in the given collection will be cleaned up and + * {@link #addActiveData(Stream)} and {@link #cleanUp(Stream)} are called + * with the same parameter. In the clean up method any dropped data objects + * that are not in the given collection will be cleaned up and * {@link DataGenerator#destroyData(Object)} will be called for them. */ protected class ActiveDataHandler @@ -190,8 +190,8 @@ public class DataCommunicator extends AbstractExtension { private final ActiveDataHandler handler = new ActiveDataHandler(); /** Empty default data provider */ - private DataProvider dataProvider = new BackEndDataProvider<>( - q -> Stream.of(), q -> 0); + private DataProvider dataProvider = new CallbackDataProvider<>( + q -> Stream.empty(), q -> 0); private final DataKeyMapper keyMapper; private boolean reset = false; diff --git a/server/src/main/java/com/vaadin/data/provider/DataProvider.java b/server/src/main/java/com/vaadin/data/provider/DataProvider.java index cdf3387212..aa008434bd 100644 --- a/server/src/main/java/com/vaadin/data/provider/DataProvider.java +++ b/server/src/main/java/com/vaadin/data/provider/DataProvider.java @@ -22,8 +22,6 @@ import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; -import com.vaadin.data.HasDataProvider; -import com.vaadin.data.HasFilterableDataProvider; import com.vaadin.server.SerializableFunction; import com.vaadin.shared.Registration; @@ -67,11 +65,11 @@ public interface DataProvider extends Serializable { /** * Gets the amount of data in this DataProvider. * - * @param t + * @param query * query with sorting and filtering * @return the size of the data provider */ - int size(Query t); + int size(Query query); /** * Fetches data from this DataProvider using given {@code query}. 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 5504861165..797f14957c 100644 --- a/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java +++ b/server/src/test/java/com/vaadin/data/provider/BackendDataProviderTest.java @@ -34,7 +34,7 @@ public class BackendDataProviderTest extends @Override protected BackEndDataProvider> createDataProvider() { - return dataProvider = new BackEndDataProvider<>(query -> { + return dataProvider = new CallbackDataProvider<>(query -> { Stream stream = data.stream() .filter(t -> query.getFilter().orElse(s -> true).test(t)); if (!query.getSortOrders().isEmpty()) { diff --git a/server/src/test/java/com/vaadin/data/provider/bov/DataProviderBoVTest.java b/server/src/test/java/com/vaadin/data/provider/bov/DataProviderBoVTest.java index 4b9c0bf628..45cfb82f69 100644 --- a/server/src/test/java/com/vaadin/data/provider/bov/DataProviderBoVTest.java +++ b/server/src/test/java/com/vaadin/data/provider/bov/DataProviderBoVTest.java @@ -25,7 +25,7 @@ import java.util.stream.Stream; import org.junit.Before; import org.junit.Test; -import com.vaadin.data.provider.BackEndDataProvider; +import com.vaadin.data.provider.CallbackDataProvider; import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.SortOrder; import com.vaadin.shared.data.sort.SortDirection; @@ -102,7 +102,7 @@ public class DataProviderBoVTest { } private DataProvider createUnsortedDataProvider() { - DataProvider dataProvider = new BackEndDataProvider<>( + DataProvider dataProvider = new CallbackDataProvider<>( // First callback fetches items based on a query query -> { // The index of the first item to load @@ -130,7 +130,7 @@ public class DataProviderBoVTest { } private DataProvider createSortedDataProvider() { - DataProvider dataProvider = new BackEndDataProvider<>( + DataProvider dataProvider = new CallbackDataProvider<>( // First callback fetches items based on a query query -> { List sortOrders = new ArrayList<>(); diff --git a/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java b/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java index 8124927ed7..2f8f5d9efa 100644 --- a/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java +++ b/server/src/test/java/com/vaadin/tests/components/grid/GridMultiSelectionModelTest.java @@ -24,7 +24,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import com.vaadin.data.provider.BackEndDataProvider; +import com.vaadin.data.provider.CallbackDataProvider; import com.vaadin.data.provider.bov.Person; import com.vaadin.event.selection.MultiSelectionEvent; import com.vaadin.event.selection.MultiSelectionListener; @@ -664,7 +664,7 @@ public class GridMultiSelectionModelTest { model.getSelectAllCheckBoxVisibility()); grid.setDataProvider( - new BackEndDataProvider( + new CallbackDataProvider( q -> IntStream .range(q.getOffset(), Math.max(q.getOffset() + q.getLimit() diff --git a/server/src/test/java/com/vaadin/ui/AbstractListingTest.java b/server/src/test/java/com/vaadin/ui/AbstractListingTest.java index c6cc9a1507..496d7e06bb 100644 --- a/server/src/test/java/com/vaadin/ui/AbstractListingTest.java +++ b/server/src/test/java/com/vaadin/ui/AbstractListingTest.java @@ -12,7 +12,7 @@ import org.junit.Before; import org.junit.Test; import com.vaadin.data.HasDataProvider; -import com.vaadin.data.provider.BackEndDataProvider; +import com.vaadin.data.provider.CallbackDataProvider; import com.vaadin.data.provider.DataProvider; import com.vaadin.data.provider.ListDataProvider; import com.vaadin.data.provider.Query; @@ -40,8 +40,7 @@ public class AbstractListingTest { } @Override - protected void readItems(Element design, - DesignContext context) { + protected void readItems(Element design, DesignContext context) { } @Override @@ -114,7 +113,7 @@ public class AbstractListingTest { listing.setDataProvider(dataProvider); Assert.assertEquals("setDataProvider did not set data provider", dataProvider, listing.getDataProvider()); - listing.setDataProvider(new BackEndDataProvider<>(q -> Stream + listing.setDataProvider(new CallbackDataProvider<>(q -> Stream .of(ITEM_ARRAY).skip(q.getOffset()).limit(q.getLimit()), q -> ITEM_ARRAY.length)); Assert.assertNotEquals("setDataProvider did not replace data provider", -- cgit v1.2.3