diff --git a/flow-data/src/main/java/com/vaadin/flow/data/provider/ArrayUpdater.java b/flow-data/src/main/java/com/vaadin/flow/data/provider/ArrayUpdater.java index c83410d6ddb..59399266a1c 100644 --- a/flow-data/src/main/java/com/vaadin/flow/data/provider/ArrayUpdater.java +++ b/flow-data/src/main/java/com/vaadin/flow/data/provider/ArrayUpdater.java @@ -18,8 +18,6 @@ import java.io.Serializable; import java.util.List; -import com.vaadin.flow.internal.JsonCodec; - import elemental.json.JsonValue; /** @@ -47,19 +45,6 @@ public interface Update extends Serializable { */ void clear(int start, int length); - /** - * Clears {@code length} elements in array from the {@code start} - * position. - * - * @param start - * the start index - * @param length - * the number of elements to clear - * @param parentKey - * Parent item key that cleared range affects - */ - void clear(int start, int length, String parentKey); - /** * Sets the {@code items} at the {@code start} position. * @@ -70,18 +55,6 @@ public interface Update extends Serializable { */ void set(int start, List items); - /** - * Sets the {@code items} at the {@code start} position. - * - * @param start - * the start index - * @param items - * the items to set - * @param parentKey - * Parent item key where given items belongs to - */ - void set(int start, List items, String parentKey); - /** * Commits changes for the given {@code updateId}. * @@ -89,40 +62,6 @@ public interface Update extends Serializable { * the update identifier of the commit */ void commit(int updateId); - - /** - * Commits changes for the given {@code updateId} and parent key. - * - * @param updateId - * the update identifier of the commit for the target - * parentKey - * @param parentKey - * target parent key - * @param levelSize - * Total number of direct child items for the given parent - * key - */ - void commit(int updateId, String parentKey, int levelSize); - - /** - * Commits enqueued function calls added via - * {@link #enqueue(String, Serializable...)}. - */ - void commit(); - - /** - * Enqueue function call with the given arguments. - * - * @see JsonCodec JsonCodec for supported argument types - * @param name - * the name of the function to call, may contain dots to - * indicate a function on a property. - * @param arguments - * the arguments to pass to the function. Must be of a type - * supported by the communication mechanism, as defined by - * {@link JsonCodec} - */ - void enqueue(String name, Serializable... arguments); } /** diff --git a/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalArrayUpdater.java b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalArrayUpdater.java new file mode 100644 index 00000000000..06db11722d7 --- /dev/null +++ b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalArrayUpdater.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2018 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.flow.data.provider.hierarchy; + +import java.io.Serializable; +import java.util.List; + +import com.vaadin.flow.data.provider.ArrayUpdater; +import com.vaadin.flow.internal.JsonCodec; + +import elemental.json.JsonValue; + +/** + * Hierarchical array update strategy aware class. + * + * @author Vaadin Ltd + * @since 1.1 + * + */ +public interface HierarchicalArrayUpdater extends ArrayUpdater { + + /** + * Array updater strategy that is aware of hierarchical changes. + */ + public interface HierarchicalUpdate extends Update { + + /** + * Clears {@code length} elements in array from the {@code start} + * position. + * + * @param start + * the start index + * @param length + * the number of elements to clear + * @param parentKey + * Parent item key that cleared range affects + */ + void clear(int start, int length, String parentKey); + + /** + * Sets the {@code items} at the {@code start} position. + * + * @param start + * the start index + * @param items + * the items to set + * @param parentKey + * Parent item key where given items belongs to + */ + void set(int start, List items, String parentKey); + + /** + * Commits enqueued function calls added via + * {@link #enqueue(String, Serializable...)}. + */ + void commit(); + + /** + * Enqueue function call with the given arguments. + * + * @see JsonCodec JsonCodec for supported argument types + * @param name + * the name of the function to call, may contain dots to + * indicate a function on a property. + * @param arguments + * the arguments to pass to the function. Must be of a type + * supported by the communication mechanism, as defined by + * {@link JsonCodec} + */ + void enqueue(String name, Serializable... arguments); + + /** + * Commits changes for the given {@code updateId} and parent key. + * + * @param updateId + * the update identifier of the commit for the target + * parentKey + * @param parentKey + * target parent key + * @param levelSize + * Total number of direct child items for the given parent + * key + */ + void commit(int updateId, String parentKey, int levelSize); + + } + + @Override + HierarchicalUpdate startUpdate(int sizeChange); + +} diff --git a/flow-data/src/main/java/com/vaadin/flow/data/provider/CommunicationController.java b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicationController.java similarity index 89% rename from flow-data/src/main/java/com/vaadin/flow/data/provider/CommunicationController.java rename to flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicationController.java index 265b2437ff6..6856e2e4832 100644 --- a/flow-data/src/main/java/com/vaadin/flow/data/provider/CommunicationController.java +++ b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicationController.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations under * the License. */ -package com.vaadin.flow.data.provider; +package com.vaadin.flow.data.provider.hierarchy; import java.io.Serializable; import java.util.ArrayList; @@ -27,7 +27,9 @@ import java.util.stream.Stream; import com.vaadin.flow.data.provider.ArrayUpdater.Update; -import com.vaadin.flow.data.provider.hierarchy.HierarchyMapper; +import com.vaadin.flow.data.provider.DataGenerator; +import com.vaadin.flow.data.provider.DataKeyMapper; +import com.vaadin.flow.data.provider.hierarchy.HierarchicalArrayUpdater.HierarchicalUpdate; import com.vaadin.flow.function.SerializableBiFunction; import com.vaadin.flow.function.SerializableFunction; import com.vaadin.flow.internal.Range; @@ -37,22 +39,16 @@ import elemental.json.JsonValue; /** - * CommunicationController controls all Grid's communication to client. - *

- * TODO move this class to 'flow-data' module first. Then get rid of the - * {@link Update} in this class by replacing {@link Update#set(int, List)}, - * {@link Update#clear(int, int)} and {@link Update#commit(int)} methods with - * {@link Update#set(int, List, String)}, {@link Update#clear(int, int, String)} - * and {@link Update#commit(int, String, int)}. + * HierarchicalCommunicationController controls all the communication to client. * * @param * the target bean type */ -public class CommunicationController implements Serializable { +public class HierarchicalCommunicationController implements Serializable { private final DataKeyMapper keyMapper; private final DataGenerator dataGenerator; - private final SerializableFunction startUpdate; + private final SerializableFunction startUpdate; private final HierarchyMapper mapper; private final SerializableBiFunction> fetchItems; @@ -100,11 +96,10 @@ public class CommunicationController implements Serializable { * Function for fetching items for target parent and specified * range */ - public CommunicationController(String parentKey, - DataKeyMapper keyMapper, - HierarchyMapper mapper, + public HierarchicalCommunicationController(String parentKey, + DataKeyMapper keyMapper, HierarchyMapper mapper, DataGenerator dataGenerator, - SerializableFunction startUpdate, + SerializableFunction startUpdate, SerializableBiFunction> fetchItems) { this.parentKey = parentKey; this.keyMapper = keyMapper; @@ -135,7 +130,7 @@ public void flush() { activeStart = effectiveRequested.getStart(); // Phase 2: Collect changes to send - Update update = startUpdate.apply(assumedSize); + HierarchicalUpdate update = startUpdate.apply(assumedSize); boolean updated = collectChangesToSend(previousActive, effectiveRequested, update); @@ -162,7 +157,7 @@ public void setResendEntireRange(boolean resend) { } private boolean collectChangesToSend(final Range previousActive, - final Range effectiveRequested, Update update) { + final Range effectiveRequested, HierarchicalUpdate update) { boolean updated = false; if (assumeEmptyClient || resendEntireRange) { if (!assumeEmptyClient) { @@ -199,7 +194,7 @@ private boolean collectChangesToSend(final Range previousActive, return updated; } - private void set(Range effectiveRequested, Update update) { + private void set(Range effectiveRequested, HierarchicalUpdate update) { if (effectiveRequested.isEmpty() || activeKeyOrder.isEmpty() || effectiveRequested.getStart() >= assumedSize) { return; @@ -209,12 +204,11 @@ private void set(Range effectiveRequested, Update update) { getJsonItems(effectiveRequested)); } else { update.set(effectiveRequested.getStart(), - getJsonItems(effectiveRequested), - parentKey); + getJsonItems(effectiveRequested), parentKey); } } - private void clear(int start, int length, Update update) { + private void clear(int start, int length, HierarchicalUpdate update) { if (length == 0 || start >= assumedSize) { return; } @@ -259,7 +253,7 @@ private List activate(Range range) { // XXX Explicitly refresh anything that is updated List activeKeys = new ArrayList<>(range.length()); - + fetchItems.apply(parentKey, range).forEach(bean -> { boolean mapperHasKey = keyMapper.has(bean); String key = keyMapper.key(bean); @@ -273,7 +267,7 @@ private List activate(Range range) { } private void passivateInactiveKeys(Set oldActive, - List newActiveKeyOrder, Update update, + List newActiveKeyOrder, HierarchicalUpdate update, boolean updated) { /* * We cannot immediately unregister keys that we have asked the client @@ -283,8 +277,8 @@ private void passivateInactiveKeys(Set oldActive, */ if (updated) { int updateId = nextUpdateId++; - - if(parentKey == null) { + + if (parentKey == null) { update.commit(updateId); } else { update.commit(updateId, parentKey, assumedSize); diff --git a/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalDataCommunicator.java b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalDataCommunicator.java index bd0c3a4f350..6853c1dddb0 100644 --- a/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalDataCommunicator.java +++ b/flow-data/src/main/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalDataCommunicator.java @@ -24,15 +24,13 @@ import java.util.Optional; import java.util.stream.Stream; -import com.vaadin.flow.data.provider.ArrayUpdater; -import com.vaadin.flow.data.provider.ArrayUpdater.Update; -import com.vaadin.flow.data.provider.CommunicationController; import com.vaadin.flow.data.provider.CompositeDataGenerator; import com.vaadin.flow.data.provider.DataCommunicator; import com.vaadin.flow.data.provider.DataGenerator; import com.vaadin.flow.data.provider.DataProvider; import com.vaadin.flow.data.provider.KeyMapper; import com.vaadin.flow.data.provider.QuerySortOrder; +import com.vaadin.flow.data.provider.hierarchy.HierarchicalArrayUpdater.HierarchicalUpdate; import com.vaadin.flow.function.SerializableComparator; import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.function.SerializableSupplier; @@ -57,13 +55,13 @@ */ public class HierarchicalDataCommunicator extends DataCommunicator { - private final ArrayUpdater arrayUpdater; + private final HierarchicalArrayUpdater arrayUpdater; private final StateNode stateNode; private HierarchyMapper mapper; private DataGenerator dataGenerator; private final SerializableSupplier> uniqueKeyProviderSupplier; - private final Map> dataControllers = new HashMap<>(); + private final Map> dataControllers = new HashMap<>(); private KeyMapper uniqueKeyMapper = new KeyMapper() { @@ -104,7 +102,7 @@ protected String createKey() { * default key generator. */ public HierarchicalDataCommunicator(CompositeDataGenerator dataGenerator, - ArrayUpdater arrayUpdater, + HierarchicalArrayUpdater arrayUpdater, SerializableConsumer dataUpdater, StateNode stateNode, SerializableSupplier> uniqueKeyProviderSupplier) { super(dataGenerator, arrayUpdater, dataUpdater, stateNode); @@ -125,14 +123,14 @@ private void generateTreeData(T item, JsonObject jsonObject) { uniqueKeyProviderSupplier.get().apply(parent))); } - private void requestFlush(Update update) { + private void requestFlush(HierarchicalUpdate update) { SerializableConsumer flushRequest = context -> update .commit(); stateNode.runWhenAttached(ui -> ui.getInternals().getStateTree() .beforeClientResponse(stateNode, flushRequest)); } - private void requestFlush(CommunicationController update) { + private void requestFlush(HierarchicalCommunicationController update) { SerializableConsumer flushRequest = context -> update .flush(); stateNode.runWhenAttached(ui -> ui.getInternals().getStateTree() @@ -150,10 +148,10 @@ public void reset() { if (!dataControllers.isEmpty()) { dataControllers.values() - .forEach(CommunicationController::unregisterPassivatedKeys); + .forEach(HierarchicalCommunicationController::unregisterPassivatedKeys); dataControllers.clear(); - Update update = arrayUpdater + HierarchicalUpdate update = arrayUpdater .startUpdate(getHierarchyMapper().getRootSize()); update.enqueue("$connector.ensureHierarchy"); requestFlush(update); @@ -170,9 +168,9 @@ public Stream fetchFromProvider(int offset, int limit) { public void setParentRequestedRange(int start, int length, T parentItem) { String parentKey = uniqueKeyProviderSupplier.get().apply(parentItem); - CommunicationController controller = dataControllers.computeIfAbsent( + HierarchicalCommunicationController controller = dataControllers.computeIfAbsent( parentKey, - key -> new CommunicationController<>(parentKey, getKeyMapper(), + key -> new HierarchicalCommunicationController<>(parentKey, getKeyMapper(), mapper, dataGenerator, size -> arrayUpdater.startUpdate(getDataProviderSize()), (pkey, range) -> mapper.fetchChildItems( @@ -323,7 +321,7 @@ private Collection doCollapse(Collection items, boolean syncClient) { items.forEach(item -> { if (mapper.collapse(item)) { collapsedItems.add(item); - CommunicationController controller = dataControllers + HierarchicalCommunicationController controller = dataControllers .remove(getKeyMapper().key(item)); if (controller != null) { controller.unregisterPassivatedKeys(); @@ -331,7 +329,7 @@ private Collection doCollapse(Collection items, boolean syncClient) { } }); if (syncClient && !collapsedItems.isEmpty()) { - Update update = arrayUpdater + HierarchicalUpdate update = arrayUpdater .startUpdate(getHierarchyMapper().getRootSize()); update.enqueue("$connector.collapseItems", collapsedItems.stream() @@ -392,7 +390,7 @@ private Collection doExpand(Collection items, boolean syncClient) { } }); if (syncClient && !expandedItems.isEmpty()) { - Update update = arrayUpdater + HierarchicalUpdate update = arrayUpdater .startUpdate(getHierarchyMapper().getRootSize()); update.enqueue("$connector.expandItems", expandedItems.stream() diff --git a/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java b/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java index b1cdc01a25f..ee10c2b3072 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/provider/DataCommunicatorTest.java @@ -15,7 +15,6 @@ */ package com.vaadin.flow.data.provider; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; @@ -90,27 +89,6 @@ public void set(int start, List items) { public void commit(int updateId) { lastUpdateId = updateId; } - - @Override - public void clear(int start, int length, String parentKey) { - } - - @Override - public void set(int start, List items, - String parentKey) { - } - - @Override - public void commit(int updateId, String parentKey, int levelSize) { - } - - @Override - public void commit() { - } - - @Override - public void enqueue(String name, Serializable... arguments) { - } }; Mockito.when(arrayUpdater.startUpdate(Mockito.anyInt())) diff --git a/flow-data/src/test/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicatorTest.java b/flow-data/src/test/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicatorTest.java index 201fbbd3b98..b28a8575bc9 100644 --- a/flow-data/src/test/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicatorTest.java +++ b/flow-data/src/test/java/com/vaadin/flow/data/provider/hierarchy/HierarchicalCommunicatorTest.java @@ -25,9 +25,8 @@ import com.vaadin.flow.component.UI; import com.vaadin.flow.component.internal.UIInternals; -import com.vaadin.flow.data.provider.ArrayUpdater; -import com.vaadin.flow.data.provider.ArrayUpdater.Update; import com.vaadin.flow.data.provider.CompositeDataGenerator; +import com.vaadin.flow.data.provider.hierarchy.HierarchicalArrayUpdater.HierarchicalUpdate; import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.internal.StateNode; import com.vaadin.flow.internal.StateTree; @@ -51,7 +50,7 @@ public class HierarchicalCommunicatorTest { private final int pageSize = 50; private StateNode stateNode; - private class UpdateQueue implements Update { + private class UpdateQueue implements HierarchicalUpdate { @Override public void clear(int start, int length) { } @@ -69,13 +68,11 @@ public void enqueue(String name, Serializable... arguments) { } @Override - public void set(int start, List items, - String parentKey) { + public void set(int start, List items, String parentKey) { } @Override - public void clear(int start, int length, - String parentKey) { + public void clear(int start, int length, String parentKey) { } @Override @@ -87,9 +84,9 @@ public void commit() { } } - private final ArrayUpdater arrayUpdater = new ArrayUpdater() { + private final HierarchicalArrayUpdater arrayUpdater = new HierarchicalArrayUpdater() { @Override - public Update startUpdate(int sizeChange) { + public HierarchicalUpdate startUpdate(int sizeChange) { return new UpdateQueue(); } @@ -97,7 +94,7 @@ public Update startUpdate(int sizeChange) { public void initialize() { } }; - + @Before public void setUp() { ui = Mockito.mock(UI.class); @@ -113,10 +110,9 @@ public void setUp() { dataProvider = new TreeDataProvider<>(treeData); stateNode = Mockito.mock(StateNode.class); communicator = new HierarchicalDataCommunicator<>( - Mockito.mock(CompositeDataGenerator.class), - arrayUpdater, json -> { - }, - stateNode, () -> null); + Mockito.mock(CompositeDataGenerator.class), arrayUpdater, + json -> { + }, stateNode, () -> null); communicator.setDataProvider(dataProvider, null); } @@ -151,7 +147,7 @@ private void testItemRemove(String item, boolean refreshAll) { } else { dataProvider.refreshItem(item); } - + ArgumentCaptor attachCaptor = ArgumentCaptor .forClass(SerializableConsumer.class); Mockito.verify(stateNode, Mockito.times(4)) @@ -160,8 +156,7 @@ private void testItemRemove(String item, boolean refreshAll) { attachCaptor.getAllValues().forEach(consumer -> consumer.accept(ui)); Mockito.verify(stateTree, Mockito.times(4)) - .beforeClientResponse(Mockito.any(), - Mockito.any()); + .beforeClientResponse(Mockito.any(), Mockito.any()); } @Test