diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-06-15 15:14:09 +0300 |
---|---|---|
committer | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-06-15 17:42:11 +0300 |
commit | fc96cea89e7d5a374603eae14f329a36e92e89b7 (patch) | |
tree | a9ee989b04a3541e07882212637443149431d51e | |
parent | fa1ae150f0a0de39e31a424eeb426abca6f46fa6 (diff) | |
download | vaadin-framework-fc96cea89e7d5a374603eae14f329a36e92e89b7.tar.gz vaadin-framework-fc96cea89e7d5a374603eae14f329a36e92e89b7.zip |
Add a DataProvider implementation
Change-Id: I8fba190a905a4dac6bfef5693064218672e23ba4
9 files changed, 1012 insertions, 0 deletions
diff --git a/client/src/main/java/com/vaadin/client/connectors/data/DataSourceConnector.java b/client/src/main/java/com/vaadin/client/connectors/data/DataSourceConnector.java new file mode 100644 index 0000000000..5a559dfafa --- /dev/null +++ b/client/src/main/java/com/vaadin/client/connectors/data/DataSourceConnector.java @@ -0,0 +1,192 @@ +/* + * 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.client.connectors.data; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.vaadin.client.ServerConnector; +import com.vaadin.client.extensions.AbstractExtensionConnector; +import com.vaadin.client.widget.grid.datasources.ListDataSource; +import com.vaadin.server.communication.data.typed.SimpleDataProvider; +import com.vaadin.shared.data.DataRequestRpc; +import com.vaadin.shared.data.typed.DataProviderClientRpc; +import com.vaadin.shared.data.typed.DataProviderConstants; +import com.vaadin.shared.ui.Connect; + +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonObject; + +/** + * A simple connector for DataProvider class. Based on {@link ListDataSource} + * and does not support lazy loading or paging. + * + * @since + */ +@Connect(SimpleDataProvider.class) +public class DataSourceConnector extends AbstractExtensionConnector { + + private Map<String, JsonObject> keyToJson = new HashMap<String, JsonObject>(); + private Set<String> droppedKeys = new HashSet<String>(); + private ListDataSource<JsonObject> ds = new ListDataSource<JsonObject>(); + private boolean pendingDrop = false; + + @Override + protected void extend(ServerConnector target) { + registerRpc(DataProviderClientRpc.class, new DataProviderClientRpc() { + + @Override + public void reset() { + ds.asList().clear(); + // Inform the server-side that all keys are now dropped. + Set<String> keySet = new HashSet<String>(keyToJson.keySet()); + for (String key : keySet) { + dropKey(key); + } + sendDroppedKeys(); + } + + @Override + public void setData(long firstIndex, JsonArray data) { + List<JsonObject> l = ds.asList(); + assert firstIndex <= l.size() : "Gap in data. First Index: " + + firstIndex + ", Size: " + l.size(); + for (long i = 0; i < data.length(); ++i) { + JsonObject object = data.getObject((int) i); + if (i + firstIndex == l.size()) { + l.add(object); + } else if (i + firstIndex < l.size()) { + int index = (int) (i + firstIndex); + dropKey(getKey(l.get(index))); + l.set(index, object); + } + keyToJson.put(getKey(object), object); + } + sendDroppedKeys(); + } + + @Override + public void add(JsonObject dataObject) { + ds.asList().add(dataObject); + keyToJson.put(getKey(dataObject), dataObject); + } + + @Override + public void drop(String key) { + if (keyToJson.containsKey(key)) { + ds.asList().remove(keyToJson.get(key)); + dropKey(key); + sendDroppedKeys(); + } + } + + @Override + public void updateData(JsonArray data) { + List<JsonObject> list = ds.asList(); + for (int i = 0; i < data.length(); ++i) { + JsonObject json = data.getObject(i); + String key = getKey(json); + + if (keyToJson.containsKey(key)) { + int index = list.indexOf(keyToJson.get(key)); + list.set(index, json); + keyToJson.put(key, json); + } else { + dropKey(key); + } + } + sendDroppedKeys(); + } + }); + + ServerConnector parent = getParent(); + if (parent instanceof HasDataSource) { + ((HasDataSource) parent).setDataSource(ds); + } else { + assert false : "Parent not implementing HasDataSource"; + } + } + + /** + * Marks a key as dropped. Call to + * {@link DataSourceConnector#sendDroppedKeys()} should be called to make + * sure the information is sent to the server-side. + * + * @param key + * dropped key + */ + private void dropKey(String key) { + droppedKeys.add(key); + if (keyToJson.containsKey(key)) { + keyToJson.remove(key); + } + } + + /** + * Sends dropped keys to the server-side with a deferred scheduled command. + * Multiple calls to this method will only result to one command being + * executed. + */ + private void sendDroppedKeys() { + if (pendingDrop) { + return; + } + + pendingDrop = true; + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + + @Override + public void execute() { + pendingDrop = false; + if (droppedKeys.isEmpty()) { + return; + } + + JsonArray keyArray = Json.createArray(); + int i = 0; + for (String key : droppedKeys) { + keyArray.set(i++, key); + } + + getRpcProxy(DataRequestRpc.class).dropRows(keyArray); + + // Force RPC since it's delayed. + getConnection().getServerRpcQueue().flush(); + + droppedKeys.clear(); + } + }); + } + + /** + * Gets the mapping key from given {@link JsonObject}. + * + * @param jsonObject + * json object to get the key from + */ + protected String getKey(JsonObject jsonObject) { + if (jsonObject.hasKey(DataProviderConstants.KEY)) { + return jsonObject.getString(DataProviderConstants.KEY); + } + return null; + } +}
\ No newline at end of file diff --git a/client/src/main/java/com/vaadin/client/connectors/data/HasDataSource.java b/client/src/main/java/com/vaadin/client/connectors/data/HasDataSource.java new file mode 100644 index 0000000000..36a206115c --- /dev/null +++ b/client/src/main/java/com/vaadin/client/connectors/data/HasDataSource.java @@ -0,0 +1,35 @@ +/* + * 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.client.connectors.data; + +import com.vaadin.client.data.DataSource; + +import elemental.json.JsonObject; + +/** + * Marker interface for Connectors that have a {@link DataSource}. + */ +public interface HasDataSource { + + /** + * Sets the data source for this Conenctor. + * + * @param dataSource + * new data source + */ + public void setDataSource(DataSource<JsonObject> dataSource); + +} diff --git a/server/src/main/java/com/vaadin/server/communication/data/typed/DataKeyMapper.java b/server/src/main/java/com/vaadin/server/communication/data/typed/DataKeyMapper.java new file mode 100644 index 0000000000..ff56a38639 --- /dev/null +++ b/server/src/main/java/com/vaadin/server/communication/data/typed/DataKeyMapper.java @@ -0,0 +1,62 @@ +/* + * 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.communication.data.typed; + +import java.io.Serializable; + +/** + * DataKeyMapper to map data objects to key strings. + * + * @since + * @param <T> + * data type + */ +public interface DataKeyMapper<T> extends Serializable { + + /** + * Gets the key for data object. If no key exists beforehand, a new key is + * created. + * + * @param dataObject + * data object for key mapping + * @return key for given data object + */ + String key(T dataObject); + + /** + * Gets the data object identified by given key. + * + * @param key + * key of a data object + * @return identified data object; <code>null</code> if invalid key + */ + T get(String key); + + /** + * Removes a data object from the key mapping. The key is also dropped. + * Dropped keys are not reused. + * + * @param dataObject + * dropped data object + */ + void remove(T dataObject); + + /** + * Removes all data objects from the key mapping. The keys are also dropped. + * Dropped keys are not reused. + */ + void removeAll(); +}
\ No newline at end of file diff --git a/server/src/main/java/com/vaadin/server/communication/data/typed/DataProvider.java b/server/src/main/java/com/vaadin/server/communication/data/typed/DataProvider.java new file mode 100644 index 0000000000..309d38d558 --- /dev/null +++ b/server/src/main/java/com/vaadin/server/communication/data/typed/DataProvider.java @@ -0,0 +1,353 @@ +/* + * 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.communication.data.typed; + +import java.io.Serializable; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +import com.vaadin.server.AbstractExtension; +import com.vaadin.server.ClientConnector; +import com.vaadin.shared.data.DataRequestRpc; +import com.vaadin.shared.data.typed.DataProviderClientRpc; +import com.vaadin.shared.data.typed.DataProviderConstants; +import com.vaadin.ui.AbstractComponent; + +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonObject; + +/** + * DataProvider base class. This class is the base for all DataProvider + * communication implementations. It uses {@link TypedDataGenerator}s to write + * {@link JsonObject}s representing each data object to be sent to the + * client-side. + * + * @since + */ +public abstract class DataProvider<T> extends AbstractExtension { + + /** + * Creates the appropriate type of DataProvider based on the type of + * Collection provided to the method. + * <p> + * <strong>Note:</strong> this method will also extend the given component + * with the newly created DataProvider. The user should <strong>not</strong> + * call the {@link #extend(com.vaadin.server.AbstractClientConnector)} + * method explicitly. + * <p> + * TODO: Actually use different DataProviders and provide an API for the + * back end to inform changes back. + * + * @param data + * collection of data objects + * @param component + * component to extend with the data provider + * @return created data provider + */ + public static <V> SimpleDataProvider<V> create(DataSource<V> data, + AbstractComponent component) { + SimpleDataProvider<V> dataProvider = new SimpleDataProvider<V>(data); + dataProvider.extend(component); + return dataProvider; + } + + /** + * A class for handling currently active data and dropping data that is no + * longer needed. Data tracking is based on key string provided by + * {@link DataKeyMapper}. + * <p> + * When the {@link DataProvider} is pushing new data to the client-side via + * {@link DataProvider#pushData(long, Collection)}, + * {@link #addActiveData(Collection)} and {@link #cleanUp(Collection)} 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 TypedDataGenerator#destroyData(Object)} will be called for them. + */ + protected class ActiveDataHandler implements Serializable, + TypedDataGenerator<T> { + + /** + * Set of key strings for currently active data objects + */ + private final Set<String> activeData = new HashSet<String>(); + + /** + * Set of key strings for data objects dropped on the client. This set + * is used to clean up old data when it's no longer needed. + */ + private final Set<String> droppedData = new HashSet<String>(); + + /** + * Adds given objects as currently active objects. + * + * @param dataObjects + * collection of new active data objects + */ + public void addActiveData(Iterable<T> dataObjects) { + for (T data : dataObjects) { + if (!activeData.contains(getKeyMapper().key(data))) { + activeData.add(getKeyMapper().key(data)); + } + } + } + + /** + * Executes the data destruction for dropped data that is not sent to + * the client. This method takes most recently sent data objects in a + * collection. Doing the clean up like this prevents the + * {@link ActiveDataHandler} from creating new keys for rows that were + * dropped but got re-requested by the client-side. In the case of + * having all data at the client, the collection should be all the data + * in the back end. + * + * @see DataProvider#pushData(long, Collection) + * @param dataObjects + * collection of most recently sent data to the client + */ + public void cleanUp(Iterable<T> dataObjects) { + Collection<String> keys = new HashSet<String>(); + for (T data : dataObjects) { + keys.add(getKeyMapper().key(data)); + } + + // Remove still active rows that were dropped by the client + droppedData.removeAll(keys); + // Do data clean up for object no longer needed. + dropData(droppedData); + droppedData.clear(); + } + + /** + * Marks a data object identified by given key string to be dropped. + * + * @param key + * key string + */ + public void dropActiveData(String key) { + if (activeData.contains(key)) { + droppedData.add(key); + } + } + + /** + * Returns the collection of all currently active data. + * + * @return collection of active data objects + */ + public Collection<T> getActiveData() { + HashSet<T> hashSet = new HashSet<T>(); + for (String key : activeData) { + hashSet.add(getKeyMapper().get(key)); + } + return hashSet; + } + + @Override + public void generateData(T data, JsonObject jsonObject) { + // Write the key string for given data object + jsonObject.put(DataProviderConstants.KEY, getKeyMapper().key(data)); + } + + @Override + public void destroyData(T data) { + // Remove from active data set + activeData.remove(getKeyMapper().key(data)); + // Drop the registered key + getKeyMapper().remove(data); + } + } + + private Collection<TypedDataGenerator<T>> generators = new LinkedHashSet<TypedDataGenerator<T>>(); + protected ActiveDataHandler handler = new ActiveDataHandler(); + protected DataProviderClientRpc rpc; + + protected DataSource<T> dataSource; + private DataChangeHandler<T> dataChangeHandler; + private DetachListener detachListener; + private DataKeyMapper<T> keyMapper; + + protected DataProvider(DataSource<T> dataSource) { + addDataGenerator(handler); + this.dataSource = dataSource; + rpc = getRpcProxy(DataProviderClientRpc.class); + registerRpc(createRpc()); + dataChangeHandler = createDataChangeHandler(); + this.dataSource.addDataChangeHandler(dataChangeHandler); + keyMapper = createKeyMapper(); + } + + @Override + public void attach() { + super.attach(); + + if (detachListener == null) { + detachListener = new DetachListener() { + + @Override + public void detach(DetachEvent event) { + cleanUp(); + } + }; + getUI().addDetachListener(detachListener); + } + } + + @Override + public void setParent(ClientConnector parent) { + if (getParent() != null && parent == null) { + // Removing from parent, clean up. + cleanUp(); + } + + super.setParent(parent); + } + + /** + * Adds a {@link TypedDataGenerator} to this {@link DataProvider}. + * + * @param generator + * typed data generator + */ + public void addDataGenerator(TypedDataGenerator<T> generator) { + generators.add(generator); + } + + /** + * Removes a {@link TypedDataGenerator} from this {@link DataProvider}. + * + * @param generator + * typed data generator + */ + public void removeDataGenerator(TypedDataGenerator<T> generator) { + generators.remove(generator); + } + + /** + * Gets the {@link DataKeyMapper} used by this {@link DataProvider}. Key + * mapper can be used to map keys sent to the client-side back to their + * respective data objects. + * + * @return key mapper + */ + public DataKeyMapper<T> getKeyMapper() { + return keyMapper; + } + + /** + * Sends given collection of data objects to the client-side. + * + * @param firstIndex + * first index of pushed data + * @param data + * data objects to send as an iterable + */ + protected void pushData(long firstIndex, Iterable<T> data) { + JsonArray dataArray = Json.createArray(); + + int i = 0; + for (T item : data) { + dataArray.set(i++, getDataObject(item)); + } + + rpc.setData(firstIndex, dataArray); + handler.addActiveData(data); + handler.cleanUp(data); + } + + /** + * Creates the JsonObject for given data object. This method calls all data + * generators for it. + * + * @param data + * data object to be made into a json object + * @return json object representing the data object + */ + protected JsonObject getDataObject(T data) { + JsonObject dataObject = Json.createObject(); + + for (TypedDataGenerator<T> generator : generators) { + generator.generateData(data, dataObject); + } + + return dataObject; + } + + /** + * Drops data objects identified by given keys from memory. This will invoke + * {@link TypedDataGenerator#destroyData} for each of those objects. + * + * @param droppedKeys + * collection of dropped keys + */ + private void dropData(Collection<String> droppedKeys) { + for (String key : droppedKeys) { + assert key != null : "Bookkeepping failure. Dropping a null key"; + + T data = getKeyMapper().get(key); + assert data != null : "Bookkeepping failure. No data object to match key"; + + for (TypedDataGenerator<T> g : generators) { + g.destroyData(data); + } + } + } + + /** + * Clean up method for removing all listeners attached by the + * {@link DataProvider}. This method is called from {@link #remove()} or + * when the UI gets detached. + */ + protected void cleanUp() { + if (dataSource != null) { + dataSource.removeDataChangeHandler(dataChangeHandler); + dataChangeHandler = null; + } + if (detachListener != null) { + getUI().removeDetachListener(detachListener); + detachListener = null; + } + } + + /** + * Creates a {@link DataKeyMapper} to use with this {@link DataProvider}. + * <p> + * This method is called from the constructor. + * + * @return key mapper + */ + protected abstract DataKeyMapper<T> createKeyMapper(); + + /** + * Creates a {@link DataRequestRpc} used with this {@link DataProvider}. + * <p> + * This method is called from the constructor. + * + * @return data request rpc implementation + */ + protected abstract DataRequestRpc createRpc(); + + /** + * Creates a {@link DataChangeHandler} to use with the {@link DataSource}. + * <p> + * This method is called from the constructor. + * + * @return data change handler + */ + protected abstract DataChangeHandler<T> createDataChangeHandler(); +}
\ No newline at end of file diff --git a/server/src/main/java/com/vaadin/server/communication/data/typed/KeyMapper.java b/server/src/main/java/com/vaadin/server/communication/data/typed/KeyMapper.java new file mode 100644 index 0000000000..9a26882cd9 --- /dev/null +++ b/server/src/main/java/com/vaadin/server/communication/data/typed/KeyMapper.java @@ -0,0 +1,29 @@ +/* + * 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.communication.data.typed; + +/** + * Generic {@link DataKeyMapper} implementation based on + * {@link com.vaadin.server.KeyMapper}. Provides the interface on top of super + * class. + * + * @since + * @param <T> + * data type + */ +public class KeyMapper<T> extends com.vaadin.server.KeyMapper<T> implements + DataKeyMapper<T> { +}
\ No newline at end of file diff --git a/server/src/main/java/com/vaadin/server/communication/data/typed/SimpleDataProvider.java b/server/src/main/java/com/vaadin/server/communication/data/typed/SimpleDataProvider.java new file mode 100644 index 0000000000..8588e0315f --- /dev/null +++ b/server/src/main/java/com/vaadin/server/communication/data/typed/SimpleDataProvider.java @@ -0,0 +1,189 @@ +/* + * 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.communication.data.typed; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import com.vaadin.shared.data.DataRequestRpc; +import com.vaadin.shared.data.typed.DataProviderClientRpc; + +import elemental.json.Json; +import elemental.json.JsonArray; + +/** + * DataProvider for Collections. This class takes care of sending data objects + * stored in a Collection from the server-side to the client-side. + * <p> + * This is an implementation that does not provide any kind of lazy loading. All + * data is sent to the client-side on the initial client response. + * + * @since + */ +public class SimpleDataProvider<T> extends DataProvider<T> { + + /** + * Simple implementation of collection data provider communication. All data + * is sent by server automatically and no data is requested by client. + */ + protected class SimpleDataRequestRpc implements DataRequestRpc { + + @Override + public void requestRows(int firstRowIndex, int numberOfRows, + int firstCachedRowIndex, int cacheSize) { + throw new UnsupportedOperationException( + "Collection data provider sends all data from server." + + " It does not expect client to request anything."); + } + + @Override + public void dropRows(JsonArray keys) { + for (int i = 0; i < keys.length(); ++i) { + handler.dropActiveData(keys.getString(i)); + } + + // Use the whole data as the ones sent to the client. + handler.cleanUp(dataSource); + } + } + + private boolean reset = false; + private final Set<T> updatedData = new HashSet<T>(); + + /** + * Creates a new DataProvider with the given Collection. + * + * @param data + * collection of data to use + */ + protected SimpleDataProvider(DataSource<T> data) { + super(data); + } + + /** + * Initially and in the case of a reset all data should be pushed to the + * client. + */ + @Override + public void beforeClientResponse(boolean initial) { + super.beforeClientResponse(initial); + + if (reset) { + getRpcProxy(DataProviderClientRpc.class).reset(); + } + + if (initial || reset) { + pushData(0, dataSource); + } else if (!updatedData.isEmpty()) { + JsonArray dataArray = Json.createArray(); + int i = 0; + for (T data : updatedData) { + dataArray.set(i++, getDataObject(data)); + } + rpc.updateData(dataArray); + } + + reset = false; + updatedData.clear(); + } + + /** + * Informs the DataProvider that a data object has been added. It is assumed + * to be the last object in the collection. + * + * @param data + * data object added to collection + */ + protected void add(T data) { + rpc.add(getDataObject(data)); + handler.addActiveData(Collections.singleton(data)); + } + + /** + * Informs the DataProvider that a data object has been removed. + * + * @param data + * data object removed from collection + */ + protected void remove(T data) { + if (handler.getActiveData().contains(data)) { + rpc.drop(getKeyMapper().key(data)); + } + } + + /** + * Informs the DataProvider that the collection has changed. + */ + protected void reset() { + if (reset) { + return; + } + + reset = true; + markAsDirty(); + } + + /** + * Informs the DataProvider that a data object has been updated. + * + * @param data + * updated data object + */ + protected void refresh(T data) { + if (updatedData.isEmpty()) { + markAsDirty(); + } + + updatedData.add(data); + } + + @Override + protected DataKeyMapper<T> createKeyMapper() { + return new KeyMapper<T>(); + } + + @Override + protected DataRequestRpc createRpc() { + return new SimpleDataRequestRpc(); + } + + @Override + protected DataChangeHandler<T> createDataChangeHandler() { + return new DataChangeHandler<T>() { + + @Override + public void onDataChange() { + reset(); + } + + @Override + public void onDataAppend(T data) { + add(data); + } + + @Override + public void onDataRemove(T data) { + remove(data); + } + + @Override + public void onDataUpdate(T data) { + refresh(data); + } + }; + } +}
\ No newline at end of file diff --git a/server/src/main/java/com/vaadin/server/communication/data/typed/TypedDataGenerator.java b/server/src/main/java/com/vaadin/server/communication/data/typed/TypedDataGenerator.java new file mode 100644 index 0000000000..b21fe0699e --- /dev/null +++ b/server/src/main/java/com/vaadin/server/communication/data/typed/TypedDataGenerator.java @@ -0,0 +1,49 @@ +/* + * 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.communication.data.typed; + +import java.io.Serializable; + +import elemental.json.JsonObject; + +/** + * Simple typed data generator for {@link DataProvider}. + * + * @since + */ +public interface TypedDataGenerator<T> extends Serializable { + + /** + * Adds data for given object to {@link JsonObject}. This JsonObject will be + * sent to client-side DataSource. + * + * @param data + * data object + * @param jsonObject + * json object being sent to the client + */ + void generateData(T data, JsonObject jsonObject); + + /** + * Informs the {@link TypedDataGenerator} that given data has been dropped + * and is no longer needed. This method should clean up any unneeded + * information stored for this data. + * + * @param data + * dropped data + */ + public void destroyData(T data); +}
\ No newline at end of file diff --git a/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderClientRpc.java b/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderClientRpc.java new file mode 100644 index 0000000000..4b5824bda7 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderClientRpc.java @@ -0,0 +1,75 @@ +/* + * 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.shared.data.typed; + +import java.util.List; + +import com.vaadin.shared.communication.ClientRpc; + +import elemental.json.JsonArray; +import elemental.json.JsonObject; + +/** + * RPC interface used by DataProvider to send data to the client-side. + * + * @since + */ +public interface DataProviderClientRpc extends ClientRpc { + + /** + * Informs the client-side DataSource that all data has been invalidated. + */ + void reset(); + + /** + * Sets the data of the client-side DataSource to match the given data + * starting from given index. + * <p> + * <strong>Note:</strong> This method will override any existing data in the + * range starting from first index with the length of the data array. + * + * @param firstIndex + * first index to update + * @param data + * array of new data + */ + void setData(long firstIndex, JsonArray data); + + /** + * Adds a new data object to the client-side DataSource. The new data object + * is added at the end of the data source. + * + * @param dataObject + * single added data object + */ + void add(JsonObject dataObject); + + /** + * Removes data identified by given key from the client-side DataSource. + * + * @param key + * key identifying the object to be removed + */ + void drop(String key); + + /** + * Updates an array of objects based on their identifying key. + * + * @param data + * array of updated data + */ + void updateData(JsonArray data); +}
\ No newline at end of file diff --git a/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderConstants.java b/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderConstants.java new file mode 100644 index 0000000000..52fc225546 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/data/typed/DataProviderConstants.java @@ -0,0 +1,28 @@ +/* + * 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.shared.data.typed; + +import java.io.Serializable; + +/** + * Set of contants used by DataProvider. These are commonly used JsonObject keys + * which are considered to be reserved for internal use. + * + * @since + */ +public final class DataProviderConstants implements Serializable { + public static final String KEY = "k"; +}
\ No newline at end of file |