// childMap is only used for finding parents of items and clean up on
// removing children of expanded nodes.
private Map<T, Set<T>> childMap = new HashMap<>();
+ private Map<Object, T> parentIdMap = new HashMap<>();
private final HierarchicalDataProvider<T, F> provider;
private F filter;
private T getParentOfItem(T item) {
Objects.requireNonNull(item, "Can not find the parent of null");
- Object itemId = getDataProvider().getId(item);
- for (Entry<T, Set<T>> entry : childMap.entrySet()) {
- if (entry.getValue().stream().map(getDataProvider()::getId)
- .anyMatch(id -> id.equals(itemId))) {
- return entry.getKey();
- }
- }
- return null;
+ return parentIdMap.get(getDataProvider().getId(item));
}
/**
}
}
expandedItemIds.remove(id);
- invalidatedChildren.stream().map(getDataProvider()::getId)
- .forEach(this::removeChildren);
+ invalidatedChildren.stream().map(getDataProvider()::getId).forEach(x -> {
+ removeChildren(x);
+ parentIdMap.remove(x);
+ });
}
/**
: getDataProvider().getId(parent));
} else {
childMap.put(parent, new HashSet<>(childList));
+ childList.forEach(x -> parentIdMap.put(getDataProvider().getId(x), parent));
}
}
return combineParentAndChildStreams(parent,
@Override
public void destroyAllData() {
childMap.clear();
+ parentIdMap.clear();
}
}
import com.vaadin.data.provider.TreeDataProvider;
import com.vaadin.server.SerializablePredicate;
import com.vaadin.shared.Range;
-import com.vaadin.shared.data.DataCommunicatorClientRpc;
-
-import elemental.json.JsonArray;
public class HierarchyMapperWithDataTest {
@BeforeClass
public static void setupData() {
- testData = generateTestData();
+ testData = generateTestData(ROOT_COUNT, PARENT_COUNT, LEAF_COUNT);
roots = testData.stream().filter(item -> item.getParent() == null)
.collect(Collectors.toList());
data.addItems(roots,
}
}
- private static List<Node> generateTestData() {
+ static List<Node> generateTestData(int rootCount, int parentCount, int leafCount) {
List<Node> nodes = new ArrayList<>();
- for (int i = 0; i < ROOT_COUNT; ++i) {
+ for (int i = 0; i < rootCount; ++i) {
Node root = new Node();
nodes.add(root);
- for (int j = 0; j < PARENT_COUNT; ++j) {
+ for (int j = 0; j < parentCount; ++j) {
Node parent = new Node(root);
nodes.add(parent);
- for (int k = 0; k < LEAF_COUNT; ++k) {
+ for (int k = 0; k < leafCount; ++k) {
nodes.add(new Node(parent));
}
}
--- /dev/null
+package com.vaadin.data.provider.hierarchical;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.vaadin.data.TreeData;
+import com.vaadin.data.provider.HierarchyMapper;
+import com.vaadin.data.provider.TreeDataProvider;
+import com.vaadin.server.SerializablePredicate;
+import com.vaadin.shared.Range;
+
+public class HierarchyMapperWithNumerousDataTest {
+
+ private static final int ROOT_COUNT = 1;
+ private static final int PARENT_COUNT = 100000;
+
+ private static TreeData<Node> data = new TreeData<>();
+ private TreeDataProvider<Node> provider;
+ private HierarchyMapper<Node, SerializablePredicate<Node>> mapper;
+ private static List<Node> testData;
+ private static List<Node> roots;
+ private int mapSize = ROOT_COUNT;
+
+ @BeforeClass
+ public static void setupData() {
+ testData = HierarchyMapperWithDataTest.generateTestData(ROOT_COUNT, PARENT_COUNT, 0);
+ roots = testData.stream().filter(item -> item.getParent() == null)
+ .collect(Collectors.toList());
+ data.addItems(roots,
+ parent -> testData.stream().filter(
+ item -> Objects.equals(item.getParent(), parent))
+ .collect(Collectors.toList()));
+ }
+
+ @Before
+ public void setup() {
+ provider = new TreeDataProvider<>(data);
+ mapper = new HierarchyMapper<>(provider);
+ }
+
+ /**
+ * Test for non-logarithmic {@code getParentOfItem} implementations
+ * 100000 entries and 1 second should be enought to make it run even
+ * on slow machines and weed out linear solutions
+ */
+ @Test(timeout = 1000)
+ public void expandRootNode() {
+ Assert.assertEquals("Map size should be equal to root node count",
+ ROOT_COUNT, mapper.getTreeSize());
+ expand(testData.get(0));
+ Assert.assertEquals("Should be root count + once parent count",
+ ROOT_COUNT + PARENT_COUNT, mapper.getTreeSize());
+ checkMapSize();
+ }
+
+ private void expand(Node node) {
+ insertRows(mapper.doExpand(node, mapper.getIndexOf(node)));
+ }
+
+ public void insertRows(Range range) {
+ Assert.assertTrue("Index not in range",
+ 0 <= range.getStart() && range.getStart() <= mapSize);
+ mapSize += range.length();
+ }
+
+ private void checkMapSize() {
+ Assert.assertEquals("Map size not properly updated",
+ mapper.getTreeSize(), mapSize);
+ }
+}