diff options
11 files changed, 190 insertions, 90 deletions
diff --git a/documentation/datamodel/datamodel-providers.asciidoc b/documentation/datamodel/datamodel-providers.asciidoc index a7acc1e10e..cff31f6b0e 100644 --- a/documentation/datamodel/datamodel-providers.asciidoc +++ b/documentation/datamodel/datamodel-providers.asciidoc @@ -215,7 +215,7 @@ The sorting options set through the component will be available through [interfa [source, java] ---- -DataProvider<Person, Void> dataProvider = new BackEndDataProvider<>( +DataProvider<Person, Void> dataProvider = new CallbackDataProvider<>( query -> { List<PersonSort> sortOrders = new ArrayList<>(); for(SortOrder<String> queryOrder : query.getSortOrders()) { @@ -362,7 +362,7 @@ It would then look for a string to filter by in the query and pass it to the ser [source, java] ---- -DataProvider<Person, String> dataProvider = new BackEndDataProvider<>( +DataProvider<Person, String> dataProvider = new CallbackDataProvider<>( query -> { // getFilter returns Optional<String> String filter = query.getFilter().orElse(null); 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 <T> + * data provider data type + * @param <F> + * data provider filter type + */ +public abstract class AbstractBackEndDataProvider<T, F> extends + AbstractDataProvider<T, F> implements BackEndDataProvider<T, F> { + + private List<SortOrder<String>> sortOrders = new ArrayList<>(); + + private Query<T, F> mixInSortOrders(Query<T, F> query) { + if (sortOrders.isEmpty()) { + return query; + } + + Set<String> sortedPropertyNames = query.getSortOrders().stream() + .map(SortOrder::getSorted).collect(Collectors.toSet()); + + List<SortOrder<String>> 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<T> fetch(Query<T, F> query) { + return fetchFromBackEnd(mixInSortOrders(query)); + } + + @Override + public int size(Query<T, F> 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<T> fetchFromBackEnd(Query<T, F> 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<T, F> query); + + @Override + public void setSortOrders(List<SortOrder<String>> 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 <T> * data provider data type * @param <F> * data provider filter type */ -public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> { - - private List<SortOrder<String>> sortOrders = new ArrayList<>(); - - private final SerializableFunction<Query<T, F>, Stream<T>> request; - private final SerializableToIntFunction<Query<T, F>> 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<Query<T, F>, Stream<T>> request, - SerializableToIntFunction<Query<T, F>> 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<T> fetch(Query<T, F> query) { - return request.apply(mixInSortOrders(query)); - } - - @Override - public int size(Query<T, F> query) { - return sizeCallback.applyAsInt(mixInSortOrders(query)); - } - - private Query<T, F> mixInSortOrders(Query<T, F> query) { - Set<String> sortedPropertyNames = query.getSortOrders().stream() - .map(SortOrder::getSorted).collect(Collectors.toSet()); - - List<SortOrder<String>> 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<T, F> extends DataProvider<T, F> { /** * Sets a list of sort orders to use as the default sorting for this data @@ -99,11 +42,7 @@ public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> { * @param sortOrders * a list of sort orders to set, not <code>null</code> */ - public void setSortOrders(List<SortOrder<String>> sortOrders) { - this.sortOrders = Objects.requireNonNull(sortOrders, - "Sort orders cannot be null"); - refreshAll(); - } + void setSortOrders(List<SortOrder<String>> sortOrders); /** * Sets a single sort order to use as the default sorting for this data @@ -120,7 +59,7 @@ public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> { * a sort order to set, or <code>null</code> to clear any * previously set sort orders */ - public void setSortOrder(SortOrder<String> sortOrder) { + default void setSortOrder(SortOrder<String> sortOrder) { if (sortOrder == null) { setSortOrders(Collections.emptyList()); } else { @@ -129,8 +68,7 @@ public class BackEndDataProvider<T, F> extends AbstractDataProvider<T, F> { } @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 <T> + * data provider data type + * @param <F> + * data provider filter type + */ +public class CallbackDataProvider<T, F> + extends AbstractBackEndDataProvider<T, F> { + private final SerializableFunction<Query<T, F>, Stream<T>> fetchCallback; + private final SerializableToIntFunction<Query<T, F>> 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<Query<T, F>, Stream<T>> fetchCallback, + SerializableToIntFunction<Query<T, F>> 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<T> fetchFromBackEnd(Query<T, F> query) { + return fetchCallback.apply(query); + } + + @Override + protected int sizeInBackEnd(Query<T, F> 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<T, F> extends AbstractExtension { * <p> * 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<T, F> extends AbstractExtension { private final ActiveDataHandler handler = new ActiveDataHandler(); /** Empty default data provider */ - private DataProvider<T, F> dataProvider = new BackEndDataProvider<>( - q -> Stream.of(), q -> 0); + private DataProvider<T, F> dataProvider = new CallbackDataProvider<>( + q -> Stream.empty(), q -> 0); private final DataKeyMapper<T> 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<T, F> 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, F> t); + int size(Query<T, F> 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<StrBean, SerializablePredicate<StrBean>> createDataProvider() { - return dataProvider = new BackEndDataProvider<>(query -> { + return dataProvider = new CallbackDataProvider<>(query -> { Stream<StrBean> 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<Person, ?> createUnsortedDataProvider() { - DataProvider<Person, ?> dataProvider = new BackEndDataProvider<>( + DataProvider<Person, ?> 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<Person, ?> createSortedDataProvider() { - DataProvider<Person, ?> dataProvider = new BackEndDataProvider<>( + DataProvider<Person, ?> dataProvider = new CallbackDataProvider<>( // First callback fetches items based on a query query -> { List<PersonService.PersonSort> 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<String, String>( + new CallbackDataProvider<String, String>( 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", diff --git a/uitest/src/main/java/com/vaadin/tests/util/ItemDataProvider.java b/uitest/src/main/java/com/vaadin/tests/util/ItemDataProvider.java index f7261a5d6d..90d668cf78 100644 --- a/uitest/src/main/java/com/vaadin/tests/util/ItemDataProvider.java +++ b/uitest/src/main/java/com/vaadin/tests/util/ItemDataProvider.java @@ -4,7 +4,7 @@ import java.util.Locale; import java.util.stream.IntStream; import java.util.stream.Stream; -import com.vaadin.data.provider.BackEndDataProvider; +import com.vaadin.data.provider.CallbackDataProvider; import com.vaadin.data.provider.Query; /** @@ -12,7 +12,8 @@ import com.vaadin.data.provider.Query; * * @author Vaadin Ltd */ -public class ItemDataProvider extends BackEndDataProvider<String, String> { +public class ItemDataProvider + extends CallbackDataProvider<String, String> { public ItemDataProvider(int size) { super(q -> itemStream(q, size).skip(q.getOffset()).limit(q.getLimit()), |