summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--documentation/datamodel/datamodel-datasources.asciidoc12
-rw-r--r--server/src/main/java/com/vaadin/server/data/BackEndDataSource.java85
-rw-r--r--server/src/main/java/com/vaadin/server/data/DataSource.java65
-rw-r--r--server/src/main/java/com/vaadin/server/data/InMemoryDataSource.java42
-rw-r--r--server/src/main/java/com/vaadin/server/data/SortOrder.java27
-rw-r--r--server/src/test/java/com/vaadin/server/data/datasource/InMemoryDataSourceTest.java73
-rw-r--r--server/src/test/java/com/vaadin/server/data/datasource/bov/DataSourceBoVTest.java78
-rw-r--r--server/src/test/java/com/vaadin/server/data/datasource/bov/PersonService.java16
8 files changed, 340 insertions, 58 deletions
diff --git a/documentation/datamodel/datamodel-datasources.asciidoc b/documentation/datamodel/datamodel-datasources.asciidoc
index ddc78bc6cf..997ad20207 100644
--- a/documentation/datamodel/datamodel-datasources.asciidoc
+++ b/documentation/datamodel/datamodel-datasources.asciidoc
@@ -152,7 +152,7 @@ Information about which items to fetch as well as some additional details are ma
[source, java]
----
-DataSource<Person> dataSource = new DataSource<>(
+DataSource<Person> dataSource = new BackendDataSource<>(
// First callback fetches items based on a query
query -> {
// The index of the first item to load
@@ -197,7 +197,7 @@ public interface PersonService {
int getPersonCount();
- static PersonSort createSort(
+ PersonSort createSort(
String propertyName,
boolean descending);
}
@@ -208,11 +208,11 @@ The sorting options set through the component will be available through [interfa
[source, java]
----
-DataSource<Person> dataSource = new DataSource<>(
+DataSource<Person> dataSource = new BackEndDataSource<>(
query -> {
List<PersonSort> sortOrders = new ArrayList<>();
for(SortOrder<String> queryOrder : query.getSortOrders()) {
- PersonSort sort = PersonService.createSort(
+ PersonSort sort = getPersonService().createSort(
// The name of the sorted property
queryOrder.getSorted(),
// The sort direction for this property
@@ -220,7 +220,7 @@ DataSource<Person> dataSource = new DataSource<>(
sortOrders.add(sort);
}
- return service.fetchPersons(
+ return getPersonService().fetchPersons(
query.getOffset(),
query.getLimit(),
sortOrders
@@ -329,7 +329,7 @@ We can create a helper method for handling the filter since the same logic is ne
[source, java]
----
-DataSource<Person> dataSource = new DataSource<>(
+DataSource<Person> dataSource = new BackEndDataSource<>(
query -> {
BackendFilter filter = query.getFilter();
diff --git a/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java
new file mode 100644
index 0000000000..556d9cb25c
--- /dev/null
+++ b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 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.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * A {@link DataSource} for any back end.
+ *
+ * @param <T>
+ * data source data type
+ */
+public class BackEndDataSource<T> implements
+ DataSource<T> {
+
+ private Function<Query, Stream<T>> request;
+ private Function<Query, Integer> sizeCallback;
+
+ /**
+ * Constructs a new DataSource 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 BackEndDataSource(Function<Query, Stream<T>> request,
+ Function<Query, Integer> 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> apply(Query t) {
+ return request.apply(t);
+ }
+
+ @Override
+ public int size(Query t) {
+ return sizeCallback.apply(t);
+ }
+
+ /**
+ * Sets a default sorting order to the data source.
+ *
+ * @param sortOrders
+ * a list of sorting information containing field ids and directions
+ * @return new data source with modified sorting
+ */
+ public BackEndDataSource<T> sortingBy(List<SortOrder<String>> sortOrders) {
+ return new BackEndDataSource<>(query -> {
+ List<SortOrder<String>> queryOrder = new ArrayList<>(
+ query.getSortOrders());
+ queryOrder.addAll(sortOrders);
+ return request.apply(new Query(query.getLimit(), query.getOffset(),
+ queryOrder, query.getFilters()));
+ }, sizeCallback);
+ }
+
+ @Override
+ public boolean isInMemory() {
+ return false;
+ }
+
+}
diff --git a/server/src/main/java/com/vaadin/server/data/DataSource.java b/server/src/main/java/com/vaadin/server/data/DataSource.java
index d4e5e17aac..4f6db29535 100644
--- a/server/src/main/java/com/vaadin/server/data/DataSource.java
+++ b/server/src/main/java/com/vaadin/server/data/DataSource.java
@@ -15,43 +15,42 @@
*/
package com.vaadin.server.data;
+import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
/**
- * A generic data source for any back end and Listing UI components.
- *
+ * Minimal DataSource API for communication between the DataProvider and a back
+ * end service.
+ *
+ * @since
* @param <T>
- * data source data type
+ * data type
+ *
+ * @see InMemoryDataSource
+ * @see BackEndDataSource
*/
-public class DataSource<T> implements
- Function<Query, Stream<T>>, java.io.Serializable {
-
- protected Function<Query, Stream<T>> request;
- protected Function<Query, Integer> sizeCallback;
+public interface DataSource<T> extends Function<Query, Stream<T>>,
+ Serializable {
- protected DataSource() {
- }
+ /**
+ * Gets whether the DataSource content all available in memory or does it
+ * use some external backend.
+ *
+ * @return {@code true} if all data is in memory; {@code false} if not
+ */
+ boolean isInMemory();
/**
- * Constructs a new DataSource 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
+ * Gets the amount of data in this DataSource.
+ *
+ * @param t
+ * query with sorting and filtering
+ * @return the size of the data source
*/
- public DataSource(Function<Query, Stream<T>> request,
- Function<Query, Integer> 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;
- }
+ int size(Query t);
/**
* This method creates a new {@link InMemoryDataSource} from a given
@@ -79,18 +78,4 @@ public class DataSource<T> implements
public static <T> InMemoryDataSource<T> create(T... data) {
return new InMemoryDataSource<>(Arrays.asList(data));
}
-
- @Override
- public Stream<T> apply(Query t) {
- return request.apply(t);
- }
-
- public int size(Query t) {
- return sizeCallback.apply(t);
- }
-
- public boolean isInMemory() {
- return false;
- }
-
-}
+} \ No newline at end of file
diff --git a/server/src/main/java/com/vaadin/server/data/InMemoryDataSource.java b/server/src/main/java/com/vaadin/server/data/InMemoryDataSource.java
index bbc5d738c6..bb75f45ffb 100644
--- a/server/src/main/java/com/vaadin/server/data/InMemoryDataSource.java
+++ b/server/src/main/java/com/vaadin/server/data/InMemoryDataSource.java
@@ -17,6 +17,7 @@ package com.vaadin.server.data;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -28,14 +29,15 @@ import java.util.stream.Stream;
* @param <T>
* data type
*/
-public class InMemoryDataSource<T> extends DataSource<T> {
+public class InMemoryDataSource<T> implements DataSource<T> {
+ private Function<Query, Stream<T>> request;
private int size;
/**
* Constructs a new ListDataSource. This method makes a protective copy of
* the contents of the Collection.
- *
+ *
* @param collection
* initial data
*/
@@ -49,12 +51,44 @@ public class InMemoryDataSource<T> extends DataSource<T> {
* Chaining constructor for making modified {@link InMemoryDataSource}s.
* This Constructor is used internally for making sorted and filtered
* variants of a base data source with actual data.
- *
+ *
* @param request
* request for the new data source
*/
protected InMemoryDataSource(Function<Query, Stream<T>> request) {
- super(request,null);
+ this.request = request;
+ }
+
+ @Override
+ public Stream<T> apply(Query query) {
+ return request.apply(query);
+ }
+
+ /**
+ * Sets a default sorting order to the data source.
+ *
+ * @param sortOrder
+ * a {@link Comparator} providing the needed sorting order
+ * @return new data source with modified sorting
+ */
+ public InMemoryDataSource<T> sortingBy(Comparator<T> sortOrder) {
+ return new InMemoryDataSource<>(q -> request.apply(q)
+ .sorted(sortOrder));
+ }
+
+ /**
+ * Sets a default sorting order to the data source. This method is a
+ * short-hand for {@code sortingBy(Comparator.comparing(sortOrder))}.
+ *
+ * @param sortOrder
+ * function to sort by
+ * @param <U>
+ * the type of the Comparable sort key
+ * @return new data source with modified sorting
+ */
+ public <U extends Comparable<? super U>> InMemoryDataSource<T> sortingBy(
+ Function<T, U> sortOrder) {
+ return sortingBy(Comparator.comparing(sortOrder));
}
@Override
diff --git a/server/src/main/java/com/vaadin/server/data/SortOrder.java b/server/src/main/java/com/vaadin/server/data/SortOrder.java
index 3b8fb65932..cf2cd7e208 100644
--- a/server/src/main/java/com/vaadin/server/data/SortOrder.java
+++ b/server/src/main/java/com/vaadin/server/data/SortOrder.java
@@ -19,20 +19,43 @@ import java.io.Serializable;
import com.vaadin.shared.data.sort.SortDirection;
+/**
+ * Sorting information for one field.
+ *
+ * @see Query
+ */
public class SortOrder<T> implements Serializable {
- private T sorted;
- private SortDirection direction;
+ private final T sorted;
+ private final SortDirection direction;
+ /**
+ * Constructs a field sorting information
+ *
+ * @param sorted
+ * sorting information, usually field id or {@link java.util.Comparator}
+ * @param direction
+ * sorting direction
+ */
public SortOrder(T sorted, SortDirection direction) {
this.sorted = sorted;
this.direction = direction;
}
+ /**
+ * Sorting information
+ *
+ * @return sorting entity, usually field id or {@link java.util.Comparator}
+ */
public T getSorted() {
return sorted;
}
+ /**
+ * Sorting direction
+ *
+ * @return sorting direction
+ */
public SortDirection getDirection() {
return direction;
}
diff --git a/server/src/test/java/com/vaadin/server/data/datasource/InMemoryDataSourceTest.java b/server/src/test/java/com/vaadin/server/data/datasource/InMemoryDataSourceTest.java
index 9ab9731beb..5c71b1e48f 100644
--- a/server/src/test/java/com/vaadin/server/data/datasource/InMemoryDataSourceTest.java
+++ b/server/src/test/java/com/vaadin/server/data/datasource/InMemoryDataSourceTest.java
@@ -2,14 +2,17 @@ package com.vaadin.server.data.datasource;
import static org.junit.Assert.assertTrue;
+import java.util.Comparator;
import java.util.List;
+import java.util.stream.Collectors;
import com.vaadin.server.data.DataSource;
+import com.vaadin.server.data.InMemoryDataSource;
+import com.vaadin.server.data.Query;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import com.vaadin.server.data.InMemoryDataSource;
-import com.vaadin.server.data.Query;
public class InMemoryDataSourceTest {
@@ -32,4 +35,70 @@ public class InMemoryDataSourceTest {
data.isEmpty());
}
+ @Test
+ public void testSortByComparatorListsDiffer() {
+ Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
+ .thenComparing(StrBean::getRandomNumber)
+ .thenComparing(StrBean::getId);
+ List<StrBean> list = dataSource.sortingBy(comp).apply(new Query())
+ .collect(Collectors.toList());
+
+ // First value in data is { Xyz, 10, 100 } which should be last in list
+ Assert.assertNotEquals("First value should not match", data.get(0),
+ list.get(0));
+
+ Assert.assertEquals("Sorted data and original data sizes don't match",
+ data.size(), list.size());
+
+ data.sort(comp);
+ for (int i = 0; i < data.size(); ++i) {
+ Assert.assertEquals("Sorting result differed", data.get(i),
+ list.get(i));
+ }
+ }
+
+ @Test
+ public void testDefatulSortWithSpecifiedPostSort() {
+ Comparator<StrBean> comp = Comparator.comparing(StrBean::getValue)
+ .thenComparing(Comparator.comparing(StrBean::getId).reversed());
+ List<StrBean> list = dataSource.sortingBy(comp).apply(new Query())
+ // The sort here should come e.g from a Component
+ .sorted(Comparator.comparing(StrBean::getRandomNumber))
+ .collect(Collectors.toList());
+
+ Assert.assertEquals("Sorted data and original data sizes don't match",
+ data.size(), list.size());
+
+ for (int i = 1; i < list.size(); ++i) {
+ StrBean prev = list.get(i - 1);
+ StrBean cur = list.get(i);
+ // Test specific sort
+ Assert.assertTrue(prev.getRandomNumber() <= cur.getRandomNumber());
+
+ if (prev.getRandomNumber() == cur.getRandomNumber()) {
+ // Test default sort
+ Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0);
+ if (prev.getValue().equals(cur.getValue())) {
+ Assert.assertTrue(prev.getId() > cur.getId());
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testDefatulSortWithFunction() {
+ List<StrBean> list = dataSource.sortingBy(StrBean::getValue)
+ .apply(new Query()).collect(Collectors.toList());
+
+ Assert.assertEquals("Sorted data and original data sizes don't match",
+ data.size(), list.size());
+
+ for (int i = 1; i < list.size(); ++i) {
+ StrBean prev = list.get(i - 1);
+ StrBean cur = list.get(i);
+
+ // Test default sort
+ Assert.assertTrue(prev.getValue().compareTo(cur.getValue()) <= 0);
+ }
+ }
}
diff --git a/server/src/test/java/com/vaadin/server/data/datasource/bov/DataSourceBoVTest.java b/server/src/test/java/com/vaadin/server/data/datasource/bov/DataSourceBoVTest.java
index a42657813a..3b0c12deb1 100644
--- a/server/src/test/java/com/vaadin/server/data/datasource/bov/DataSourceBoVTest.java
+++ b/server/src/test/java/com/vaadin/server/data/datasource/bov/DataSourceBoVTest.java
@@ -15,13 +15,19 @@
*/
package com.vaadin.server.data.datasource.bov;
+import com.vaadin.server.data.BackEndDataSource;
import com.vaadin.server.data.DataSource;
+import com.vaadin.server.data.SortOrder;
+import com.vaadin.shared.data.sort.SortDirection;
import org.junit.Before;
import org.junit.Test;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Vaadin 8 Example from Book of Vaadin
@@ -32,7 +38,7 @@ public class DataSourceBoVTest {
private PersonServiceImpl personService;
- public static class PersonServiceImpl implements PersonService{
+ public static class PersonServiceImpl implements PersonService {
final Person[] persons;
public PersonServiceImpl(Person... persons) {
@@ -48,15 +54,48 @@ public class DataSourceBoVTest {
}
@Override
+ public List<Person> fetchPersons(int offset, int limit, Collection<PersonSort> personSorts) {
+ Stream<Person> personStream = Arrays.stream(persons)
+ .skip(offset)
+ .limit(limit);
+ if (personSorts != null)
+ for (PersonSort personSort : personSorts) {
+ personStream = personStream.sorted(personSort);
+ }
+ return personStream.collect(Collectors.toList());
+ }
+
+ @Override
public int getPersonCount() {
return persons.length;
}
+
+ @Override
+ public PersonSort createSort(String propertyName, boolean descending) {
+ PersonSort result;
+ switch (propertyName) {
+ case "name":
+ result = (person1, person2) -> String.CASE_INSENSITIVE_ORDER.compare(person1.getName(), person2.getName());
+ break;
+ case "born":
+ result = (person1, person2) -> person2.getBorn() - person1.getBorn();
+ break;
+ default:
+ throw new IllegalArgumentException("wrong field name " + propertyName);
+ }
+ if (descending) return (person1, person2) -> result.compare(person2, person1);
+ else return result;
+ }
}
@Test
public void testPersons() {
+ DataSource<Person> dataSource = createUnsortedDatasource();
+ //TODO test if the datasource contains all defined Persons in correct(unchanged) order
+ }
- DataSource<Person> dataSource = new DataSource<Person>(
+ private DataSource<Person> createUnsortedDatasource() {
+ DataSource<Person> dataSource = new BackEndDataSource<>(
// First callback fetches items based on a query
query -> {
// The index of the first item to load
@@ -72,6 +111,41 @@ public class DataSourceBoVTest {
// Second callback fetches the number of items for a query
query -> getPersonService().getPersonCount()
);
+ return dataSource;
+ }
+
+ @Test
+ public void testSortedPersons() {
+
+ DataSource<Person> dataSource = createSortedDataSource();
+ //TODO test if datasource contains all defined Persons in correct order
+ //TODO test Query.sortOrders correctness
+ }
+
+ private DataSource<Person> createSortedDataSource() {
+ DataSource<Person> dataSource = new BackEndDataSource<>(
+ // First callback fetches items based on a query
+ query -> {
+ List<PersonService.PersonSort> sortOrders = new ArrayList<>();
+ for (SortOrder<String> queryOrder : query.getSortOrders()) {
+ PersonService.PersonSort sort = personService.createSort(
+ // The name of the sorted property
+ queryOrder.getSorted(),
+ // The sort direction for this property
+ queryOrder.getDirection() == SortDirection.DESCENDING);
+ sortOrders.add(sort);
+ }
+ return getPersonService().fetchPersons(
+ query.getOffset(),
+ query.getLimit(),
+ sortOrders
+ ).stream();
+ }
+ ,
+ // Second callback fetches the number of items for a query
+ query -> getPersonService().getPersonCount()
+ );
+ return dataSource;
}
public PersonServiceImpl getPersonService() {
diff --git a/server/src/test/java/com/vaadin/server/data/datasource/bov/PersonService.java b/server/src/test/java/com/vaadin/server/data/datasource/bov/PersonService.java
index 752cda4032..75419e4f00 100644
--- a/server/src/test/java/com/vaadin/server/data/datasource/bov/PersonService.java
+++ b/server/src/test/java/com/vaadin/server/data/datasource/bov/PersonService.java
@@ -16,15 +16,27 @@
package com.vaadin.server.data.datasource.bov;
import java.io.Serializable;
+import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
/**
- * TODO class description
+ * Data access service example.
*
* @author Vaadin Ltd
+ * @see Person
*/
-public interface PersonService extends Serializable{
+public interface PersonService extends Serializable {
List<Person> fetchPersons(int offset, int limit);
+ List<Person> fetchPersons(int offset, int limit, Collection<PersonSort> personSorts);
+
int getPersonCount();
+
+ public interface PersonSort extends Comparator<Person>, Serializable {
+ }
+
+ PersonSort createSort(
+ String propertyName,
+ boolean descending);
}