Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java +49 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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) { Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/MainNodesHtmlGenerator.java +6 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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"); Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/MoveOrCopyNodeModalHtmlGenerator.java +14 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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; Loading vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java +24 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading @@ -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) { Loading @@ -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())); Loading Loading @@ -192,4 +208,8 @@ public class NodeInfo { public boolean isDeletable() { return deletable; } public boolean isLink() { return link; } } vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesHtmlGenerator.java +22 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading Loading @@ -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 { Loading @@ -83,4 +93,12 @@ public abstract class NodesHtmlGenerator { parentElement.append(" "); } 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
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/controller/NodesController.java +49 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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) { Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/MainNodesHtmlGenerator.java +6 −3 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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"); Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/MoveOrCopyNodeModalHtmlGenerator.java +14 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; } Loading @@ -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; Loading
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodeInfo.java +24 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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); Loading @@ -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) { Loading @@ -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())); Loading Loading @@ -192,4 +208,8 @@ public class NodeInfo { public boolean isDeletable() { return deletable; } public boolean isLink() { return link; } }
vospace-ui-backend/src/main/java/it/inaf/ia2/vospace/ui/service/NodesHtmlGenerator.java +22 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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() { Loading Loading @@ -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 { Loading @@ -83,4 +93,12 @@ public abstract class NodesHtmlGenerator { parentElement.append(" "); } 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; } }