Browse Source

Use key mapping to keep track of data on the client-side

This method fixes data removing to be based on the key mapping instead
of data content. Also the data clean up is now properly called when
dropping data objects.

Change-Id: I76a917968026f6c3b2693b52848448de92145fb1
feature/databinding
Teemu Suo-Anttila 8 years ago
parent
commit
38396def32

+ 96
- 12
client/src/com/vaadin/client/connectors/data/typed/DataSourceConnector.java View File

@@ -15,28 +15,41 @@
*/
package com.vaadin.client.connectors.data.typed;

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.data.HasDataSource;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.client.widget.grid.datasources.ListDataSource;
import com.vaadin.server.communication.data.typed.DataProvider;
import com.vaadin.shared.data.DataProviderClientRpc;
import com.vaadin.shared.data.DataProviderConstants;
import com.vaadin.shared.data.DataRequestRpc;
import com.vaadin.shared.ui.Connect;

import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;

/**
* A simple connector for DataProvider class.
* A simple connector for DataProvider class. Based on {@link ListDataSource}
* and does not support lazy loading or paging.
*
* @since
*/
@Connect(DataProvider.class)
public class DataSourceConnector extends AbstractExtensionConnector {

ListDataSource<JsonObject> ds = new ListDataSource<JsonObject>();
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) {
@@ -44,8 +57,12 @@ public class DataSourceConnector extends AbstractExtensionConnector {

@Override
public void resetSize(long size) {
// Server will provide the data we need.
ds.asList().clear();
// Inform the server-side that all keys are now dropped.
for (String key : keyToJson.keySet()) {
dropKey(key);
}
sendDroppedKeys();
}

@Override
@@ -54,12 +71,17 @@ public class DataSourceConnector extends AbstractExtensionConnector {
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(data.getObject((int) i));
l.add(object);
} else if (i + firstIndex < l.size()) {
l.set((int) (i + firstIndex), data.getObject((int) i));
int index = (int) (i + firstIndex);
dropKey(getKey(l.get(index)));
l.set(index, object);
}
keyToJson.put(getKey(object), object);
}
sendDroppedKeys();
}

@Override
@@ -68,13 +90,11 @@ public class DataSourceConnector extends AbstractExtensionConnector {
}

@Override
public void drop(JsonObject dataObject) {
List<JsonObject> l = ds.asList();
for (int i = 0; i < l.size(); ++i) {
if (l.get(i).toJson().equals(dataObject.toJson())) {
l.remove(i);
return;
}
public void drop(String key) {
if (keyToJson.containsKey(key)) {
ds.asList().remove(keyToJson.get(key));
dropKey(key);
sendDroppedKeys();
}
}
});
@@ -86,4 +106,68 @@ public class DataSourceConnector extends AbstractExtensionConnector {
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) {
if (keyToJson.containsKey(key)) {
droppedKeys.add(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;
}
}

+ 20
- 13
server/src/com/vaadin/server/communication/data/typed/DataProvider.java View File

@@ -187,8 +187,13 @@ public class DataProvider<T> extends AbstractExtension {
}

@Override
public void dropRows(JsonArray rowKeys) {
// FIXME: What should I do with these?
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(data);
}
}

@@ -328,24 +333,26 @@ public class DataProvider<T> extends AbstractExtension {
}

/**
* Informs the DataProvider that an item has been added. It is assumed to be
* the last item in the collection.
* Informs the DataProvider that a data object has been added. It is assumed
* to be the last object in the collection.
*
* @param item
* item added to collection
* @param data
* data object added to collection
*/
public void add(T item) {
rpc.add(getDataObject(item));
public void add(T data) {
rpc.add(getDataObject(data));
}

/**
* Informs the DataProvider that an item has been removed.
* Informs the DataProvider that a data object has been removed.
*
* @param item
* item removed from collection
* @param data
* data object removed from collection
*/
public void remove(T item) {
rpc.drop(getDataObject(item));
public void remove(T data) {
if (handler.getActiveData().contains(data)) {
rpc.drop(getKeyMapper().key(data));
}
}

}

+ 4
- 4
shared/src/com/vaadin/shared/data/DataProviderClientRpc.java View File

@@ -59,11 +59,11 @@ public interface DataProviderClientRpc extends ClientRpc {
void add(JsonObject dataObject);

/**
* Removes data from the client-side DataSource.
* Removes data identified by given key from the client-side DataSource.
*
* @param dataObject
* single removed data object
* @param key
* key identifying the object to be removed
*/
void drop(JsonObject dataObject);
void drop(String key);

}

Loading…
Cancel
Save