Change-Id: Id44af8373737734dac1149689f0e37bdfd3795d9feature/vaadin8-book
import com.vaadin.client.data.DataSource; | import com.vaadin.client.data.DataSource; | ||||
import com.vaadin.client.extensions.AbstractExtensionConnector; | import com.vaadin.client.extensions.AbstractExtensionConnector; | ||||
import com.vaadin.shared.data.DataRequestRpc; | import com.vaadin.shared.data.DataRequestRpc; | ||||
import com.vaadin.shared.data.typed.DataProviderClientRpc; | |||||
import com.vaadin.shared.data.typed.DataCommunicatorClientRpc; | |||||
import com.vaadin.shared.data.typed.DataProviderConstants; | import com.vaadin.shared.data.typed.DataProviderConstants; | ||||
import com.vaadin.shared.ui.Connect; | import com.vaadin.shared.ui.Connect; | ||||
import com.vaadin.tokka.server.communication.data.DataProvider; | |||||
import com.vaadin.tokka.server.communication.data.DataCommunicator; | |||||
import elemental.json.Json; | import elemental.json.Json; | ||||
import elemental.json.JsonArray; | import elemental.json.JsonArray; | ||||
import elemental.json.JsonObject; | import elemental.json.JsonObject; | ||||
/** | /** | ||||
* A connector for DataProvider class. | |||||
* A connector for DataCommunicator class. | |||||
* | * | ||||
* @since | * @since | ||||
*/ | */ | ||||
@Connect(DataProvider.class) | |||||
public class DataSourceConnector extends AbstractExtensionConnector { | |||||
@Connect(DataCommunicator.class) | |||||
public class DataCommunicatorConnector extends AbstractExtensionConnector { | |||||
public class VaadinDataSource extends AbstractRemoteDataSource<JsonObject> { | public class VaadinDataSource extends AbstractRemoteDataSource<JsonObject> { | ||||
private Set<String> droppedKeys = new HashSet<String>(); | private Set<String> droppedKeys = new HashSet<String>(); | ||||
protected VaadinDataSource() { | protected VaadinDataSource() { | ||||
registerRpc(DataProviderClientRpc.class, | |||||
new DataProviderClientRpc() { | |||||
registerRpc(DataCommunicatorClientRpc.class, | |||||
new DataCommunicatorClientRpc() { | |||||
@Override | @Override | ||||
public void reset(int size) { | public void reset(int size) { |
import com.vaadin.server.AbstractExtension; | import com.vaadin.server.AbstractExtension; | ||||
import com.vaadin.server.ClientConnector; | import com.vaadin.server.ClientConnector; | ||||
import com.vaadin.shared.data.DataRequestRpc; | import com.vaadin.shared.data.DataRequestRpc; | ||||
import com.vaadin.shared.data.typed.DataProviderClientRpc; | |||||
import com.vaadin.shared.data.typed.DataCommunicatorClientRpc; | |||||
import com.vaadin.shared.data.typed.DataProviderConstants; | import com.vaadin.shared.data.typed.DataProviderConstants; | ||||
import com.vaadin.shared.ui.grid.Range; | import com.vaadin.shared.ui.grid.Range; | ||||
import com.vaadin.tokka.event.Registration; | import com.vaadin.tokka.event.Registration; | ||||
* | * | ||||
* @since | * @since | ||||
*/ | */ | ||||
public class DataProvider<T> extends AbstractExtension { | |||||
public class DataCommunicator<T> extends AbstractExtension { | |||||
/** | /** | ||||
* Simple implementation of collection data provider communication. All data | * Simple implementation of collection data provider communication. All data | ||||
* longer needed. Data tracking is based on key string provided by | * longer needed. Data tracking is based on key string provided by | ||||
* {@link DataKeyMapper}. | * {@link DataKeyMapper}. | ||||
* <p> | * <p> | ||||
* When the {@link DataProvider} is pushing new data to the client-side via | |||||
* {@link DataProvider#pushData(long, Collection)}, | |||||
* When the {@link DataCommunicator} is pushing new data to the client-side via | |||||
* {@link DataCommunicator#pushData(long, Collection)}, | |||||
* {@link #addActiveData(Collection)} and {@link #cleanUp(Collection)} are | * {@link #addActiveData(Collection)} and {@link #cleanUp(Collection)} are | ||||
* called with the same parameter. In the clean up method any dropped data | * 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 | * objects that are not in the given collection will be cleaned up and | ||||
private Collection<TypedDataGenerator<T>> generators = new LinkedHashSet<TypedDataGenerator<T>>(); | private Collection<TypedDataGenerator<T>> generators = new LinkedHashSet<TypedDataGenerator<T>>(); | ||||
protected ActiveDataHandler handler = new ActiveDataHandler(); | protected ActiveDataHandler handler = new ActiveDataHandler(); | ||||
protected DataProviderClientRpc rpc; | |||||
protected DataCommunicatorClientRpc rpc; | |||||
protected DataSource<T> dataSource; | protected DataSource<T> dataSource; | ||||
private Registration dataChangeHandler; | private Registration dataChangeHandler; | ||||
private final Set<T> updatedData = new HashSet<T>(); | private final Set<T> updatedData = new HashSet<T>(); | ||||
private Range pushRows = Range.withLength(0, 40); | private Range pushRows = Range.withLength(0, 40); | ||||
public DataProvider(DataSource<T> dataSource) { | |||||
public DataCommunicator(DataSource<T> dataSource) { | |||||
addDataGenerator(handler); | addDataGenerator(handler); | ||||
this.dataSource = dataSource; | this.dataSource = dataSource; | ||||
rpc = getRpcProxy(DataProviderClientRpc.class); | |||||
rpc = getRpcProxy(DataCommunicatorClientRpc.class); | |||||
registerRpc(createRpc()); | registerRpc(createRpc()); | ||||
dataChangeHandler = this.dataSource | dataChangeHandler = this.dataSource | ||||
.addDataChangeHandler(createDataChangeHandler()); | .addDataChangeHandler(createDataChangeHandler()); | ||||
} | } | ||||
/** | /** | ||||
* Adds a {@link TypedDataGenerator} to this {@link DataProvider}. | |||||
* Adds a {@link TypedDataGenerator} to this {@link DataCommunicator}. | |||||
* | * | ||||
* @param generator | * @param generator | ||||
* typed data generator | * typed data generator | ||||
} | } | ||||
/** | /** | ||||
* Removes a {@link TypedDataGenerator} from this {@link DataProvider}. | |||||
* Removes a {@link TypedDataGenerator} from this {@link DataCommunicator}. | |||||
* | * | ||||
* @param generator | * @param generator | ||||
* typed data generator | * typed data generator | ||||
} | } | ||||
/** | /** | ||||
* Gets the {@link DataKeyMapper} used by this {@link DataProvider}. Key | |||||
* Gets the {@link DataKeyMapper} used by this {@link DataCommunicator}. Key | |||||
* mapper can be used to map keys sent to the client-side back to their | * mapper can be used to map keys sent to the client-side back to their | ||||
* respective data objects. | * respective data objects. | ||||
* | * | ||||
/** | /** | ||||
* Clean up method for removing all listeners attached by the | * Clean up method for removing all listeners attached by the | ||||
* {@link DataProvider}. This method is called from {@link #remove()} or | |||||
* {@link DataCommunicator}. This method is called from {@link #remove()} or | |||||
* when the UI gets detached. | * when the UI gets detached. | ||||
*/ | */ | ||||
protected void cleanUp() { | protected void cleanUp() { | ||||
} | } | ||||
/** | /** | ||||
* Creates a {@link DataKeyMapper} to use with this {@link DataProvider}. | |||||
* Creates a {@link DataKeyMapper} to use with this {@link DataCommunicator}. | |||||
* <p> | * <p> | ||||
* This method is called from the constructor. | * This method is called from the constructor. | ||||
* | * | ||||
} | } | ||||
/** | /** | ||||
* Creates a {@link DataRequestRpc} used with this {@link DataProvider}. | |||||
* Creates a {@link DataRequestRpc} used with this {@link DataCommunicator}. | |||||
* <p> | * <p> | ||||
* This method is called from the constructor. | * This method is called from the constructor. | ||||
* | * |
import elemental.json.JsonObject; | import elemental.json.JsonObject; | ||||
/** | /** | ||||
* Simple typed data generator for {@link DataProvider}. | |||||
* Simple typed data generator for {@link DataCommunicator}. | |||||
* | * | ||||
* @since | * @since | ||||
*/ | */ |
import com.vaadin.server.AbstractExtension; | import com.vaadin.server.AbstractExtension; | ||||
import com.vaadin.tokka.server.ListingExtension; | import com.vaadin.tokka.server.ListingExtension; | ||||
import com.vaadin.tokka.server.communication.data.DataProvider; | |||||
import com.vaadin.tokka.server.communication.data.DataCommunicator; | |||||
import com.vaadin.tokka.server.communication.data.SelectionModel; | import com.vaadin.tokka.server.communication.data.SelectionModel; | ||||
import com.vaadin.tokka.server.communication.data.TypedDataGenerator; | import com.vaadin.tokka.server.communication.data.TypedDataGenerator; | ||||
import com.vaadin.ui.AbstractComponent; | import com.vaadin.ui.AbstractComponent; | ||||
/** | /** | ||||
* Base class for Listing components. Provides common handling for | * Base class for Listing components. Provides common handling for | ||||
* {@link DataProvider}, {@link SelectionModel} and {@link TypedDataGenerator}s. | |||||
* {@link DataCommunicator}, {@link SelectionModel} and {@link TypedDataGenerator}s. | |||||
* | * | ||||
* @param <T> | * @param <T> | ||||
* listing data type | * listing data type | ||||
* @return the data object | * @return the data object | ||||
*/ | */ | ||||
protected T getData(String key) { | protected T getData(String key) { | ||||
DataProvider<T> dataProvider = getParent().getDataProvider(); | |||||
DataCommunicator<T> dataProvider = getParent().getDataCommunicator(); | |||||
if (dataProvider != null) { | if (dataProvider != null) { | ||||
return dataProvider.getKeyMapper().get(key); | return dataProvider.getKeyMapper().get(key); | ||||
} | } | ||||
* data object to refresh | * data object to refresh | ||||
*/ | */ | ||||
protected void refresh(T data) { | protected void refresh(T data) { | ||||
DataProvider<T> dataProvider = getParent().getDataProvider(); | |||||
DataCommunicator<T> dataProvider = getParent().getDataCommunicator(); | |||||
if (dataProvider != null) { | if (dataProvider != null) { | ||||
dataProvider.refresh(data); | dataProvider.refresh(data); | ||||
} | } | ||||
} | } | ||||
/* DataProvider for this Listing component */ | /* DataProvider for this Listing component */ | ||||
private DataProvider<T> dataProvider; | |||||
private DataCommunicator<T> dataCommunicator; | |||||
/* TypedDataGenerators used by this Listing */ | /* TypedDataGenerators used by this Listing */ | ||||
private Set<TypedDataGenerator<T>> generators = new LinkedHashSet<>(); | private Set<TypedDataGenerator<T>> generators = new LinkedHashSet<>(); | ||||
/* SelectionModel for this Listing */ | /* SelectionModel for this Listing */ | ||||
private SelectionModel<T> selectionModel; | private SelectionModel<T> selectionModel; | ||||
/** | /** | ||||
* Adds a {@link TypedDataGenerator} for the {@link DataProvider} of this | |||||
* Adds a {@link TypedDataGenerator} for the {@link DataCommunicator} of this | |||||
* Listing component. | * Listing component. | ||||
* | * | ||||
* @param generator | * @param generator | ||||
protected void addDataGenerator(TypedDataGenerator<T> generator) { | protected void addDataGenerator(TypedDataGenerator<T> generator) { | ||||
generators.add(generator); | generators.add(generator); | ||||
if (dataProvider != null) { | |||||
dataProvider.addDataGenerator(generator); | |||||
if (dataCommunicator != null) { | |||||
dataCommunicator.addDataGenerator(generator); | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Removed a {@link TypedDataGenerator} from the {@link DataProvider} of | |||||
* Removed a {@link TypedDataGenerator} from the {@link DataCommunicator} of | |||||
* this Listing component. | * this Listing component. | ||||
* | * | ||||
* @param generator | * @param generator | ||||
protected void removeDataGenerator(TypedDataGenerator<T> generator) { | protected void removeDataGenerator(TypedDataGenerator<T> generator) { | ||||
generators.remove(generator); | generators.remove(generator); | ||||
if (dataProvider != null) { | |||||
dataProvider.removeDataGenerator(generator); | |||||
if (dataCommunicator != null) { | |||||
dataCommunicator.removeDataGenerator(generator); | |||||
} | } | ||||
} | } | ||||
* @param dataProvider | * @param dataProvider | ||||
* new data provider | * new data provider | ||||
*/ | */ | ||||
protected void setDataProvider(DataProvider<T> dataProvider) { | |||||
if (this.dataProvider == dataProvider) { | |||||
protected void setDataCommunicator(DataCommunicator<T> dataProvider) { | |||||
if (this.dataCommunicator == dataProvider) { | |||||
return; | return; | ||||
} | } | ||||
if (this.dataProvider != null) { | |||||
this.dataProvider.remove(); | |||||
if (this.dataCommunicator != null) { | |||||
this.dataCommunicator.remove(); | |||||
} | } | ||||
this.dataProvider = dataProvider; | |||||
this.dataCommunicator = dataProvider; | |||||
if (dataProvider != null) { | if (dataProvider != null) { | ||||
addExtension(dataProvider); | addExtension(dataProvider); | ||||
} | } | ||||
/** | /** | ||||
* Get the {@link DataProvider} of this Listing component. | |||||
* Get the {@link DataCommunicator} of this Listing component. | |||||
* | * | ||||
* @return data provider | * @return data provider | ||||
*/ | */ | ||||
protected DataProvider<T> getDataProvider() { | |||||
return dataProvider; | |||||
protected DataCommunicator<T> getDataCommunicator() { | |||||
return dataCommunicator; | |||||
} | } | ||||
@SuppressWarnings("unchecked") | @SuppressWarnings("unchecked") |
import java.util.Map; | import java.util.Map; | ||||
import java.util.function.Function; | import java.util.function.Function; | ||||
import com.vaadin.tokka.server.communication.data.DataProvider; | |||||
import com.vaadin.tokka.server.communication.data.DataCommunicator; | |||||
import com.vaadin.tokka.server.communication.data.DataSource; | import com.vaadin.tokka.server.communication.data.DataSource; | ||||
import com.vaadin.tokka.server.communication.data.SingleSelection; | import com.vaadin.tokka.server.communication.data.SingleSelection; | ||||
import com.vaadin.tokka.ui.components.AbstractListing; | import com.vaadin.tokka.ui.components.AbstractListing; | ||||
@Override | @Override | ||||
public void setDataSource(DataSource<T> data) { | public void setDataSource(DataSource<T> data) { | ||||
this.dataSource = data; | this.dataSource = data; | ||||
setDataProvider(new DataProvider<>(data)); | |||||
setDataCommunicator(new DataCommunicator<>(data)); | |||||
} | } | ||||
@Override | @Override |
import java.util.function.Function; | import java.util.function.Function; | ||||
import com.vaadin.shared.data.typed.DataProviderConstants; | import com.vaadin.shared.data.typed.DataProviderConstants; | ||||
import com.vaadin.tokka.server.communication.data.DataProvider; | |||||
import com.vaadin.tokka.server.communication.data.DataCommunicator; | |||||
import com.vaadin.tokka.server.communication.data.DataSource; | import com.vaadin.tokka.server.communication.data.DataSource; | ||||
import com.vaadin.tokka.server.communication.data.SingleSelection; | import com.vaadin.tokka.server.communication.data.SingleSelection; | ||||
import com.vaadin.tokka.server.communication.data.TypedDataGenerator; | import com.vaadin.tokka.server.communication.data.TypedDataGenerator; | ||||
public void setDataSource(DataSource<T> data) { | public void setDataSource(DataSource<T> data) { | ||||
dataSource = data; | dataSource = data; | ||||
if (dataSource != null) { | if (dataSource != null) { | ||||
setDataProvider(new DataProvider<>(dataSource)); | |||||
setDataCommunicator(new DataCommunicator<>(dataSource)); | |||||
} else { | } else { | ||||
setDataProvider(null); | |||||
setDataCommunicator(null); | |||||
} | } | ||||
} | } | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.tokka.server.communication.data.AbstractDataSource; | import com.vaadin.tokka.server.communication.data.AbstractDataSource; | ||||
import com.vaadin.tokka.server.communication.data.DataProvider; | |||||
import com.vaadin.tokka.server.communication.data.DataCommunicator; | |||||
import com.vaadin.tokka.server.communication.data.DataSource; | import com.vaadin.tokka.server.communication.data.DataSource; | ||||
import com.vaadin.tokka.ui.components.AbstractListing; | import com.vaadin.tokka.ui.components.AbstractListing; | ||||
import com.vaadin.tokka.ui.components.AbstractListing.AbstractListingExtension; | import com.vaadin.tokka.ui.components.AbstractListing.AbstractListingExtension; | ||||
@Override | @Override | ||||
public void setDataSource(DataSource<String> data) { | public void setDataSource(DataSource<String> data) { | ||||
this.data = data; | this.data = data; | ||||
setDataProvider(new DataProvider<>(data)); | |||||
setDataCommunicator(new DataCommunicator<>(data)); | |||||
} | } | ||||
@Override | @Override | ||||
CountGenerator countGenerator = new CountGenerator(); | CountGenerator countGenerator = new CountGenerator(); | ||||
countGenerator.extend(testComponent); | countGenerator.extend(testComponent); | ||||
testComponent.getDataProvider().beforeClientResponse(true); | |||||
testComponent.getDataCommunicator().beforeClientResponse(true); | |||||
assertEquals("Generator was not called.", 1, countGenerator.callCount); | assertEquals("Generator was not called.", 1, countGenerator.callCount); | ||||
} | } | ||||
countGenerator.extend(testComponent); | countGenerator.extend(testComponent); | ||||
countGenerator.remove(); | countGenerator.remove(); | ||||
testComponent.getDataProvider().beforeClientResponse(true); | |||||
testComponent.getDataCommunicator().beforeClientResponse(true); | |||||
assertEquals("Generator was called.", 0, countGenerator.callCount); | assertEquals("Generator was called.", 0, countGenerator.callCount); | ||||
} | } |
* | * | ||||
* @since | * @since | ||||
*/ | */ | ||||
public interface DataProviderClientRpc extends ClientRpc { | |||||
public interface DataCommunicatorClientRpc extends ClientRpc { | |||||
/** | /** | ||||
* Informs the client-side DataSource that all data has been invalidated. | * Informs the client-side DataSource that all data has been invalidated. |