void restore() {
      freeze();
      var nodesToExpand = myExpandedPaths.stream().map(TreeExpansionMonitor.this::getLastNode).collect(Collectors.toUnmodifiableSet());
      var nodesToSelect = mySelectionNodes.stream().collect(Collectors.toUnmodifiableSet());
      var pathsToExpand = new HashSet<TreePath>();
      var pathsToSelect = new HashSet<TreePath>();
      TreeUtil.promiseVisit(myTree, path -> {
        if (!isValidModel()) {
          return TreeVisitor.Action.INTERRUPT;
        }
        var node = getLastNode(path);
        if (nodesToExpand.contains(node)) {
          pathsToExpand.add(path);
        }
        if (nodesToSelect.contains(node)) {
          pathsToSelect.add(path);
        }
        return TreeVisitor.Action.CONTINUE;
      }).onSuccess(ignored -> {
        TreeUtil.promiseExpand(myTree, pathsToExpand.stream().map(PathVisitor::new));
      }).onSuccess(ignored -> {
        TreeUtil.promiseSelect(myTree, pathsToSelect.stream().map(PathVisitor::new));
      }).onProcessed(ignored -> {
        if (isValidModel()) { // otherwise, there's another restoreAsync() running for the new model, it's responsible for unfreezing
          unfreeze();
        }
      });
    }
void restore()