Commit fbbe963a authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Supported link nodes in node listing

parent d5a6e295
Loading
Loading
Loading
Loading
Loading
+49 −2
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ import it.inaf.ia2.vospace.ui.service.MainNodesHtmlGenerator;
import it.inaf.ia2.vospace.ui.service.MoveOrCopyNodeModalHtmlGenerator;
import it.inaf.oats.vospace.datamodel.NodeUtils;
import static it.inaf.oats.vospace.datamodel.NodeUtils.urlEncodePath;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -27,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
import net.ivoa.xml.uws.v1.ExecutionPhase;
import net.ivoa.xml.uws.v1.JobSummary;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Param;
import net.ivoa.xml.vospace.v2.Property;
@@ -74,7 +76,9 @@ public class NodesController extends BaseController {

        listNodeData.setWritable(NodeUtils.checkIfWritable(node, principal.getName(), principal.getGroups()));

        MainNodesHtmlGenerator htmlGenerator = new MainNodesHtmlGenerator(node, principal, authority);
        List<Node> linkedNodes = getLinkedNodes(node, false);

        MainNodesHtmlGenerator htmlGenerator = new MainNodesHtmlGenerator(node, principal, authority, linkedNodes);
        listNodeData.setHtml(htmlGenerator.generateNodes());

        return ResponseEntity.ok(listNodeData);
@@ -91,12 +95,55 @@ public class NodesController extends BaseController {

        listNodeData.setWritable(NodeUtils.checkIfWritable(node, principal.getName(), principal.getGroups()));

        MoveOrCopyNodeModalHtmlGenerator htmlGenerator = new MoveOrCopyNodeModalHtmlGenerator(node, targetNodes, principal, authority);
        List<Node> linkedNodes = getLinkedNodes(node, true);

        MoveOrCopyNodeModalHtmlGenerator htmlGenerator = new MoveOrCopyNodeModalHtmlGenerator(node, targetNodes, principal, authority, linkedNodes);
        listNodeData.setHtml(htmlGenerator.generateNodes());

        return ResponseEntity.ok(listNodeData);
    }

    private List<Node> getLinkedNodes(Node node, boolean onlyDirectories) throws Exception {

        List<Node> linkedNodes = new ArrayList<>();
        if (node instanceof ContainerNode) {
            ContainerNode container = (ContainerNode) node;
            List<LinkNode> linksToLoad = container.getNodes().stream().filter(n -> n instanceof LinkNode)
                    .map(n -> (LinkNode) n).collect(Collectors.toList());

            // it is necessary to load link nodes metadata to understand if the linked node represents
            // a container, a VOSpace file or an external file
            List<CompletableFuture<Node>> nodesCalls = new ArrayList<>();

            for (LinkNode linkNode : linksToLoad) {
                String prefix = "vos://" + authority;
                if (linkNode.getTarget().startsWith(prefix)) {
                    String linkPath = linkNode.getTarget().substring(prefix.length());
                    nodesCalls.add(CompletableFuture.supplyAsync(() -> client.getNode(linkPath), Runnable::run)
                            .exceptionally(ex -> null)); // null is returned in case of broken link
                } else {
                    linkedNodes.add(linkNode);
                }
            }

            CompletableFuture.allOf(nodesCalls.toArray(CompletableFuture[]::new)).join();

            for (CompletableFuture<Node> nodeCall : nodesCalls) {
                Node linkedNode = nodeCall.get();

                if (linkedNode != null) {
                    if (linkedNode instanceof ContainerNode) {
                        linkedNodes.add(linkedNode);
                    } else if (!onlyDirectories) {
                        linkedNodes.add(linkedNode);
                    }
                }
            }
        }

        return linkedNodes;
    }

    @PostMapping(value = "/folder")
    public void newFolder(@RequestBody Map<String, Object> params) {

+6 −3
Original line number Diff line number Diff line
@@ -16,8 +16,8 @@ import org.jsoup.nodes.Element;

public class MainNodesHtmlGenerator extends NodesHtmlGenerator {

    public MainNodesHtmlGenerator(Node node, User user, String authority) {
        super(node, user, authority);
    public MainNodesHtmlGenerator(Node node, User user, String authority, List<Node> linkedNodes) {
        super(node, user, authority, linkedNodes);
    }

    @Override
@@ -29,7 +29,10 @@ public class MainNodesHtmlGenerator extends NodesHtmlGenerator {

    @Override
    protected void addChild(Node child, Element containerElement) {
        NodeInfo nodeInfo = new NodeInfo(child, user, authority);

        Node linkedNode = getLinkedNode(child);

        NodeInfo nodeInfo = new NodeInfo(child, user, authority, linkedNode);

        Element row = containerElement.appendElement("tr");

+14 −3
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ package it.inaf.ia2.vospace.ui.service;

import it.inaf.ia2.aa.data.User;
import java.util.List;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
@@ -15,8 +16,8 @@ public class MoveOrCopyNodeModalHtmlGenerator extends NodesHtmlGenerator {

    private final List<String> targetNodes;

    public MoveOrCopyNodeModalHtmlGenerator(Node node, List<String> targetNodes, User user, String authority) {
        super(node, user, authority);
    public MoveOrCopyNodeModalHtmlGenerator(Node node, List<String> targetNodes, User user, String authority, List<Node> linkedNodes) {
        super(node, user, authority, linkedNodes);
        this.targetNodes = targetNodes;
    }

@@ -30,7 +31,17 @@ public class MoveOrCopyNodeModalHtmlGenerator extends NodesHtmlGenerator {

    @Override
    protected void addChild(Node child, Element containerElement) {
        NodeInfo nodeInfo = new NodeInfo(child, user, authority);

        Node linkedNode = null;
        if (child instanceof LinkNode) {
            linkedNode = getLinkedNode(child);
            if (linkedNode == null) {
                // linked node is a file
                return;
            }
        }

        NodeInfo nodeInfo = new NodeInfo(child, user, authority, linkedNode);

        if (!nodeInfo.isFolder() || targetNodes.contains(nodeInfo.getPath())) {
            return;
+24 −4
Original line number Diff line number Diff line
@@ -14,7 +14,9 @@ import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Collectors;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.DataNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import net.ivoa.xml.vospace.v2.Property;
import org.slf4j.Logger;
@@ -26,10 +28,10 @@ public class NodeInfo {

    private final String authority;

    private final String path;
    private String path;
    private final String name;
    private final String size;
    private final String type;
    private String type;
    private final String creator;
    private final String groupRead;
    private final String groupWrite;
@@ -39,8 +41,9 @@ public class NodeInfo {
    private final boolean busy;
    private final boolean writable;
    private final boolean deletable;
    private final boolean link;

    public NodeInfo(Node node, User user, String authority) {
    public NodeInfo(Node node, User user, String authority, Node linkedNode) {
        this.authority = authority;
        this.path = getPath(node);
        this.name = URLDecoder.decode(path.substring(path.lastIndexOf("/") + 1), StandardCharsets.UTF_8);
@@ -55,6 +58,15 @@ public class NodeInfo {
        this.busy = isBusy(node);
        this.writable = NodeUtils.checkIfWritable(node, user.getName(), user.getGroups()) && !busy;
        this.deletable = writable && !sticky && !asyncTrans;
        this.link = linkedNode != null;
        if (linkedNode != null) {
            String prefix = "vos://" + authority;
            String target = ((LinkNode) node).getTarget();
            if (linkedNode instanceof ContainerNode) {
                this.path = decodePath(target, prefix);
            }
            this.type = linkedNode.getType();
        }
    }

    private String getPath(Node node) {
@@ -67,7 +79,11 @@ public class NodeInfo {
            throw new VOSpaceException("Node authority is different from configured one! Configured is " + authority + ", but node URI is " + uri);
        }

        // returns decoded path
        return decodePath(uri, prefix);
    }

    private String decodePath(String uri, String prefix) {

        return String.join("/", Arrays.stream(uri.substring(prefix.length()).split("/"))
                .map(p -> URLDecoder.decode(p, StandardCharsets.UTF_8))
                .collect(Collectors.toList()));
@@ -192,4 +208,8 @@ public class NodeInfo {
    public boolean isDeletable() {
        return deletable;
    }

    public boolean isLink() {
        return link;
    }
}
+22 −4
Original line number Diff line number Diff line
@@ -6,7 +6,9 @@
package it.inaf.ia2.vospace.ui.service;

import it.inaf.ia2.aa.data.User;
import java.util.List;
import net.ivoa.xml.vospace.v2.ContainerNode;
import net.ivoa.xml.vospace.v2.LinkNode;
import net.ivoa.xml.vospace.v2.Node;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@@ -18,13 +20,15 @@ public abstract class NodesHtmlGenerator {

    protected final User user;
    protected final String authority;
    private final List<Node> linkedNodes;

    private Element containerElement;

    protected NodesHtmlGenerator(Node node, User user, String authority) {
    protected NodesHtmlGenerator(Node node, User user, String authority, List<Node> linkedNodes) {
        this.parentNode = node;
        this.user = user;
        this.authority = authority;
        this.linkedNodes = linkedNodes;
    }

    public String generateNodes() {
@@ -67,7 +71,13 @@ public abstract class NodesHtmlGenerator {
        Element icon = parentElement.appendElement("span");
        icon.addClass("icon");

        if (nodeInfo.isLink()) {
            if (nodeInfo.isFolder()) {
                icon.addClass("folder-link-icon");
            } else {
                icon.addClass("link-icon");
            }
        } else if (nodeInfo.isFolder()) {
            if (nodeInfo.isAsyncTrans()) {
                icon.addClass("folder-x-icon");
            } else {
@@ -83,4 +93,12 @@ public abstract class NodesHtmlGenerator {

        parentElement.append("&nbsp;");
    }

    protected Node getLinkedNode(Node node) {
        if (node instanceof LinkNode) {
            return linkedNodes.stream().filter(n -> ((LinkNode) node)
                    .getTarget().equals(n.getUri())).findFirst().orElse(null);
        }
        return null;
    }
}
Loading