aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main/java
diff options
context:
space:
mode:
authorDenis Anisimov <denis@vaadin.com>2016-09-12 16:52:13 +0300
committerVaadin Code Review <review@vaadin.com>2016-09-14 11:41:25 +0000
commit62d712fb4514b2ed118539f43967c9b24d906518 (patch)
tree4fe5dc00f8eac65a42c51ef893edeb397e62d093 /server/src/main/java
parent4aac5294bba6eff216cddaa826b7739494376ff7 (diff)
downloadvaadin-framework-62d712fb4514b2ed118539f43967c9b24d906518.tar.gz
vaadin-framework-62d712fb4514b2ed118539f43967c9b24d906518.zip
DataSource.refreshAll() for notifying components to reload (#233).
The method refreshAll() fires an event which is handled by UI components to reload their content. Change-Id: Ibbbe1f24b08ed883f0dda93c3ff6f05f380e9eaa
Diffstat (limited to 'server/src/main/java')
-rw-r--r--server/src/main/java/com/vaadin/server/data/AbstractDataSource.java104
-rw-r--r--server/src/main/java/com/vaadin/server/data/BackEndDataSource.java2
-rw-r--r--server/src/main/java/com/vaadin/server/data/DataChangeEvent.java48
-rw-r--r--server/src/main/java/com/vaadin/server/data/DataCommunicator.java31
-rw-r--r--server/src/main/java/com/vaadin/server/data/DataSource.java23
-rw-r--r--server/src/main/java/com/vaadin/server/data/DataSourceListener.java42
-rw-r--r--server/src/main/java/com/vaadin/server/data/ListDataSource.java36
7 files changed, 270 insertions, 16 deletions
diff --git a/server/src/main/java/com/vaadin/server/data/AbstractDataSource.java b/server/src/main/java/com/vaadin/server/data/AbstractDataSource.java
new file mode 100644
index 0000000000..9dba0bd35e
--- /dev/null
+++ b/server/src/main/java/com/vaadin/server/data/AbstractDataSource.java
@@ -0,0 +1,104 @@
+/*
+ * 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.data;
+
+import java.lang.reflect.Method;
+import java.util.EventObject;
+import java.util.Objects;
+
+import com.vaadin.event.EventRouter;
+import com.vaadin.shared.Registration;
+
+/**
+ * Abstract data source implementation which takes care of refreshing data from
+ * the underlying data provider.
+ *
+ * @author Vaadin Ltd
+ * @since 8.0
+ *
+ */
+public abstract class AbstractDataSource<T> implements DataSource<T> {
+
+ private EventRouter eventRouter;
+
+ @Override
+ public Registration addDataSourceListener(DataSourceListener listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ addListener(DataChangeEvent.class, listener,
+ DataSourceListener.class.getMethods()[0]);
+ return () -> removeListener(DataChangeEvent.class, listener);
+ }
+
+ @Override
+ public void refreshAll() {
+ fireEvent(new DataChangeEvent(this));
+ }
+
+ /**
+ * Registers a new listener with the specified activation method to listen
+ * events generated by this component. If the activation method does not
+ * have any arguments the event object will not be passed to it when it's
+ * called.
+ *
+ * @param eventType
+ * the type of the listened event. Events of this type or its
+ * subclasses activate the listener.
+ * @param listener
+ * the object instance who owns the activation method.
+ * @param method
+ * the activation method.
+ *
+ */
+ protected void addListener(Class<?> eventType, DataSourceListener listener,
+ Method method) {
+ if (eventRouter == null) {
+ eventRouter = new EventRouter();
+ }
+ eventRouter.addListener(eventType, listener, method);
+ }
+
+ /**
+ * Removes all registered listeners matching the given parameters. Since
+ * this method receives the event type and the listener object as
+ * parameters, it will unregister all <code>object</code>'s methods that are
+ * registered to listen to events of type <code>eventType</code> generated
+ * by this component.
+ *
+ * @param eventType
+ * the exact event type the <code>object</code> listens to.
+ * @param listener
+ * the target object that has registered to listen to events of
+ * type <code>eventType</code> with one or more methods.
+ */
+ protected void removeListener(Class<?> eventType,
+ DataSourceListener listener) {
+ if (eventRouter != null) {
+ eventRouter.removeListener(eventType, listener);
+ }
+ }
+
+ /**
+ * Sends the event to all listeners.
+ *
+ * @param event
+ * the Event to be sent to all listeners.
+ */
+ protected void fireEvent(EventObject event) {
+ if (eventRouter != null) {
+ eventRouter.fireEvent(event);
+ }
+ }
+}
diff --git a/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java
index 34379deb60..e0cfc8f48b 100644
--- a/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java
+++ b/server/src/main/java/com/vaadin/server/data/BackEndDataSource.java
@@ -27,7 +27,7 @@ import java.util.stream.Stream;
* @param <T>
* data source data type
*/
-public class BackEndDataSource<T> implements DataSource<T> {
+public class BackEndDataSource<T> extends AbstractDataSource<T> {
private Function<Query, Stream<T>> request;
private Function<Query, Integer> sizeCallback;
diff --git a/server/src/main/java/com/vaadin/server/data/DataChangeEvent.java b/server/src/main/java/com/vaadin/server/data/DataChangeEvent.java
new file mode 100644
index 0000000000..cf2e9621de
--- /dev/null
+++ b/server/src/main/java/com/vaadin/server/data/DataChangeEvent.java
@@ -0,0 +1,48 @@
+/*
+ * 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.data;
+
+import java.util.EventObject;
+
+/**
+ * An event fired when the data of a {@code DataSource} changes.
+ *
+ *
+ * @see DataSourceListener
+ *
+ * @author Vaadin Ltd
+ * @since 8.0
+ *
+ */
+public class DataChangeEvent extends EventObject {
+
+ /**
+ * Creates a new {@code DataChangeEvent} event originating from the given
+ * data source.
+ *
+ * @param source
+ * the data source, not null
+ */
+ public DataChangeEvent(DataSource<?> source) {
+ super(source);
+ }
+
+ @Override
+ public DataSource<?> getSource() {
+ return (DataSource<?>) super.getSource();
+ }
+
+}
diff --git a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java
index b0ade744de..5fc11bb15d 100644
--- a/server/src/main/java/com/vaadin/server/data/DataCommunicator.java
+++ b/server/src/main/java/com/vaadin/server/data/DataCommunicator.java
@@ -32,6 +32,7 @@ import java.util.stream.Stream;
import com.vaadin.server.AbstractExtension;
import com.vaadin.server.KeyMapper;
import com.vaadin.shared.Range;
+import com.vaadin.shared.Registration;
import com.vaadin.shared.data.DataCommunicatorClientRpc;
import com.vaadin.shared.data.DataCommunicatorConstants;
import com.vaadin.shared.data.DataRequestRpc;
@@ -50,6 +51,8 @@ import elemental.json.JsonObject;
*/
public class DataCommunicator<T> extends AbstractExtension {
+ private Registration dataSourceUpdateRegistration;
+
/**
* Simple implementation of collection data provider communication. All data
* is sent by server automatically and no data is requested by client.
@@ -195,6 +198,18 @@ public class DataCommunicator<T> extends AbstractExtension {
keyMapper = createKeyMapper();
}
+ @Override
+ public void attach() {
+ super.attach();
+ attachDataSourceListener();
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ detachDataSourceListener();
+ }
+
/**
* Initially and in the case of a reset all data should be pushed to the
* client.
@@ -459,6 +474,22 @@ public class DataCommunicator<T> extends AbstractExtension {
public void setDataSource(DataSource<T> dataSource) {
Objects.requireNonNull(dataSource, "data source cannot be null");
this.dataSource = dataSource;
+ detachDataSourceListener();
+ if (isAttached()) {
+ attachDataSourceListener();
+ }
reset();
}
+
+ private void attachDataSourceListener() {
+ dataSourceUpdateRegistration = getDataSource()
+ .addDataSourceListener(event -> reset());
+ }
+
+ private void detachDataSourceListener() {
+ if (dataSourceUpdateRegistration != null) {
+ dataSourceUpdateRegistration.remove();
+ dataSourceUpdateRegistration = null;
+ }
+ }
}
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 25679a3c89..f767f60cf0 100644
--- a/server/src/main/java/com/vaadin/server/data/DataSource.java
+++ b/server/src/main/java/com/vaadin/server/data/DataSource.java
@@ -21,6 +21,8 @@ import java.util.Collection;
import java.util.function.Function;
import java.util.stream.Stream;
+import com.vaadin.shared.Registration;
+
/**
* Minimal DataSource API for communication between the DataProvider and a back
* end service.
@@ -56,6 +58,27 @@ public interface DataSource<T>
int size(Query t);
/**
+ * Refreshes all data based on currently available data in the underlying
+ * provider.
+ */
+ void refreshAll();
+
+ /**
+ * Adds a data source listener. The listener is called when some piece of
+ * data is updated.
+ * <p>
+ * The {@link #refreshAll()} method fires {@link DataChangeEvent} each time
+ * when it's called. It allows to update UI components when user changes
+ * something in the underlying data.
+ *
+ * @see #refreshAll()
+ * @param listener
+ * the data change listener, not null
+ * @return a registration for the listener
+ */
+ Registration addDataSourceListener(DataSourceListener listener);
+
+ /**
* This method creates a new {@link ListDataSource} from a given Collection.
* The ListDataSource creates a protective List copy of all the contents in
* the Collection.
diff --git a/server/src/main/java/com/vaadin/server/data/DataSourceListener.java b/server/src/main/java/com/vaadin/server/data/DataSourceListener.java
new file mode 100644
index 0000000000..c9c486cfd1
--- /dev/null
+++ b/server/src/main/java/com/vaadin/server/data/DataSourceListener.java
@@ -0,0 +1,42 @@
+/*
+ * 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.data;
+
+import java.io.Serializable;
+
+/**
+ * Interface for listening for a data change events fired by a
+ * {@link DataSource}.
+ *
+ * @author Vaadin Ltd
+ * @since 8.0
+ */
+public interface DataSourceListener extends Serializable {
+
+ /**
+ * Invoked when this listener receives a data change event from a data
+ * source to which it has been added.
+ * <p>
+ * This event is fired when something has changed in the underlying data. It
+ * doesn't allow to distinguish different kind of events
+ * (add/remove/update). It means that the method implementation normally
+ * just reloads the whole data to refresh.
+ *
+ * @param event
+ * the received event, not null
+ */
+ void onDataChange(DataChangeEvent event);
+}
diff --git a/server/src/main/java/com/vaadin/server/data/ListDataSource.java b/server/src/main/java/com/vaadin/server/data/ListDataSource.java
index ecac378182..64b7c03cb1 100644
--- a/server/src/main/java/com/vaadin/server/data/ListDataSource.java
+++ b/server/src/main/java/com/vaadin/server/data/ListDataSource.java
@@ -15,10 +15,8 @@
*/
package com.vaadin.server.data;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
-import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
@@ -30,10 +28,10 @@ import java.util.stream.Stream;
* @param <T>
* data type
*/
-public class ListDataSource<T> implements DataSource<T> {
+public class ListDataSource<T> extends AbstractDataSource<T> {
- private Function<Query, Stream<T>> request;
- private int size;
+ private Comparator<T> sortOrder;
+ private final Collection<T> backend;
/**
* Constructs a new ListDataSource. This method makes a protective copy of
@@ -44,26 +42,33 @@ public class ListDataSource<T> implements DataSource<T> {
*/
public ListDataSource(Collection<T> items) {
Objects.requireNonNull(items, "items cannot be null");
- final List<T> backend = new ArrayList<>(items);
- request = query -> backend.stream();
- size = backend.size();
+ backend = items;
+ sortOrder = null;
}
/**
* Chaining constructor for making modified {@link ListDataSource}s. This
* Constructor is used internally for making sorted and filtered variants of
* a base data source with actual data.
+ *
+ * @param items
+ * the backend data from the original list data source
+ * @param sortOrder
+ * a {@link Comparator} providing the needed sorting order
*
- * @param request
- * request for the new data source
*/
- protected ListDataSource(Function<Query, Stream<T>> request) {
- this.request = request;
+ protected ListDataSource(Collection<T> items, Comparator<T> sortOrder) {
+ this(items);
+ this.sortOrder = sortOrder;
}
@Override
public Stream<T> apply(Query query) {
- return request.apply(query);
+ Stream<T> stream = backend.stream();
+ if (sortOrder != null) {
+ stream = stream.sorted(sortOrder);
+ }
+ return stream;
}
/**
@@ -77,7 +82,7 @@ public class ListDataSource<T> implements DataSource<T> {
* @return new data source with modified sorting
*/
public ListDataSource<T> sortingBy(Comparator<T> sortOrder) {
- return new ListDataSource<>(q -> request.apply(q).sorted(sortOrder));
+ return new ListDataSource<>(backend, sortOrder);
}
/**
@@ -113,6 +118,7 @@ public class ListDataSource<T> implements DataSource<T> {
*/
@Override
public int size(Query t) {
- return size;
+ return backend.size();
}
+
}