From 000325b758fed495359e49aeb1daf8cc240e4e7b Mon Sep 17 00:00:00 2001 From: Logan Drescher Date: Fri, 15 Nov 2024 11:45:22 -0500 Subject: [PATCH] Added convenience methods to JhdfUtils --- .../vcell/cli/run/hdf5/Jhdf5UtilsTest.java | 23 ++++ .../cbit/vcell/export/server/JhdfUtils.java | 103 ++++++++++++++---- 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/vcell-cli/src/test/java/org/vcell/cli/run/hdf5/Jhdf5UtilsTest.java b/vcell-cli/src/test/java/org/vcell/cli/run/hdf5/Jhdf5UtilsTest.java index 357ef04e89..c45a6602f0 100644 --- a/vcell-cli/src/test/java/org/vcell/cli/run/hdf5/Jhdf5UtilsTest.java +++ b/vcell-cli/src/test/java/org/vcell/cli/run/hdf5/Jhdf5UtilsTest.java @@ -2,8 +2,10 @@ import cbit.vcell.export.server.JhdfUtils; import io.jhdf.HdfFile; +import io.jhdf.WritableDatasetImpl; import io.jhdf.WritableHdfFile; import io.jhdf.api.Dataset; +import io.jhdf.api.WritableGroup; import io.jhdf.api.WritiableDataset; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Tag; @@ -111,4 +113,25 @@ public void testStringAttributes() throws IOException { } } + + @Test + public void testAddingAndGettingGroupByPath() throws IOException { + Path tempFile = Files.createTempFile(this.getClass().getSimpleName(), ".hdf5"); + try(WritableHdfFile writableHdfFile = HdfFile.write(tempFile)){ + WritableGroup subGroup = JhdfUtils.addGroupByPath(writableHdfFile, "/path/to", true); + Assertions.assertNotNull(JhdfUtils.getGroupByPath(writableHdfFile, "path/to")); + WritableGroup newGroup = JhdfUtils.addGroupByPath(subGroup, "the"); + Assertions.assertThrows(IllegalArgumentException.class, + () -> JhdfUtils.addGroupByPath(writableHdfFile, "path/to/the/fictitious/group")); + newGroup.putDataset("dataset", new double[] {0.1, 0.2, 0.3}); + Assertions.assertThrows(IllegalArgumentException.class, () -> JhdfUtils.addGroupByPath(writableHdfFile, "path/to/the/dataset")); + WritableGroup alsoNewGroup = JhdfUtils.getGroupByPath(writableHdfFile, "path/to/the"); + Assertions.assertEquals(newGroup, alsoNewGroup); + Assertions.assertThrows(IllegalArgumentException.class, ()-> JhdfUtils.getGroupByPath(writableHdfFile, "path/to/the/dataset")); + WritableDatasetImpl dataset = JhdfUtils.getDatasetByPath(writableHdfFile, "path/to/the/dataset"); + WritableDatasetImpl alsoDataset = JhdfUtils.getDatasetByPath(alsoNewGroup, "dataset"); + Assertions.assertEquals(dataset, alsoDataset); + Assertions.assertThrows(IllegalArgumentException.class, ()-> JhdfUtils.getDatasetByPath(subGroup, "the")); + } + } } diff --git a/vcell-core/src/main/java/cbit/vcell/export/server/JhdfUtils.java b/vcell-core/src/main/java/cbit/vcell/export/server/JhdfUtils.java index 1f18222fe2..c223202636 100644 --- a/vcell-core/src/main/java/cbit/vcell/export/server/JhdfUtils.java +++ b/vcell-core/src/main/java/cbit/vcell/export/server/JhdfUtils.java @@ -1,5 +1,8 @@ package cbit.vcell.export.server; +import io.jhdf.WritableDatasetImpl; +import io.jhdf.api.Attribute; +import io.jhdf.api.WritableGroup; import io.jhdf.HdfFile; import io.jhdf.api.Dataset; import io.jhdf.api.Group; @@ -7,6 +10,7 @@ import io.jhdf.api.WritableNode; import io.jhdf.object.datatype.CompoundDataType; +import java.util.Arrays; import java.util.List; public class JhdfUtils { @@ -173,35 +177,88 @@ public static void putAttribute(WritableNode node, String name, double[] value) node.putAttribute(name, value); } - public static List getChildren(HdfFile hdfFile, Group group) { - return hdfFile.getChildren().values().stream() - .filter(node -> node.getParent() == group).toList(); - } - - public static List getChildGroups(HdfFile hdfFile, Group group) { - return hdfFile.getChildren().values().stream() - .filter(node -> node.getParent() == group) - .filter(node -> node instanceof Group) - .map(node -> (Group)node).toList(); + public static WritableGroup addGroupByPath(WritableGroup startingPoint, String path){ + return JhdfUtils.addGroupByPath(startingPoint, path, false); } - public static List getChildDatasets(HdfFile hdfFile, Group group) { - return hdfFile.getChildren().values().stream() - .filter(node -> node.getParent() == group) - .filter(node -> node instanceof Dataset) - .map(node -> (Dataset)node).toList(); + /** + * Adds one (or more) groups to the starting point, with the goal of creating a group at the end of a path. + * Note that with the current implementation, if the group already exists, it will simply be returned. + * + * @param startingPoint starting group to path from + * @param path the relative path from the starting point to the desired group to add + * @param makeParentPaths allows the algorithm to add in any missing parent groups needed to make the target group + * @return the group at the end of the path + */ + public static WritableGroup addGroupByPath(WritableGroup startingPoint, String path, boolean makeParentPaths){ + if (startingPoint == null) throw new IllegalArgumentException("startingPoint can not be null!"); + if (path == null) throw new IllegalArgumentException("path can not be null!"); + WritableGroup currentGroup = startingPoint; + String[] components = path.split("/"); + for (int i = 0; i < components.length ; i++) { + String component = components[i]; + if ("".equals(component)) continue; + Node nextChild = currentGroup.getChild(component); + if (nextChild == null) { + if ((i != components.length - 1) && !makeParentPaths) + throw new IllegalArgumentException("Parent group `" + component + "` does not exist!"); + nextChild = currentGroup.putGroup(component); + } + if (!(nextChild instanceof WritableGroup writableGroup)) + throw new IllegalArgumentException("`" + nextChild.getPath() + "` is not a writable group!"); + currentGroup = writableGroup; + } + return currentGroup; } - public static String[] getCompoundDatasetMemberNames(Dataset cds) { - if (!cds.isCompound()) { - throw new IllegalArgumentException("Dataset is not compound."); + /** + * Returns the group at the provided relative path from the starting point. + * + * @param startingPoint starting group to path from + * @param path the relative path from the starting point to the desired group + * @return the group at the end of the path + */ + public static WritableGroup getGroupByPath(WritableGroup startingPoint, String path){ + if (startingPoint == null) throw new IllegalArgumentException("startingPoint can not be null!"); + WritableGroup currentGroup = startingPoint; + for (String component : path.split("/")) { + Node nextChild = currentGroup.getChild(component); + if (nextChild == null) throw new IllegalArgumentException("Parent group `" + component + "` does not exist!"); + if (!(nextChild instanceof WritableGroup writableGroup)) + throw new IllegalArgumentException("`" + nextChild.getPath() + "` is not a writable group!"); + currentGroup = writableGroup; } - if (cds.getDataType() instanceof CompoundDataType compoundDataType) { - return compoundDataType.getMembers().stream() - .map(CompoundDataType.CompoundDataMember::getName) - .toArray(String[]::new); + return currentGroup; + } + + /** + * Returns the dataset at the provided relative path from the starting point. + * + * @param startingPoint starting group to path from + * @param path the relative path from the starting point to the desired group + * @return the group at the end of the path + */ + public static WritableDatasetImpl getDatasetByPath(WritableGroup startingPoint, String path){ + if (startingPoint == null) throw new IllegalArgumentException("startingPoint can not be null!"); + if (path == null) throw new IllegalArgumentException("path can not be null!"); + String[] pathComponents = path.split("/"); + if (pathComponents.length == 0) throw new IllegalArgumentException("Illegal path provided: not enough terms!"); + String datasetName = pathComponents[pathComponents.length - 1]; + WritableGroup parent; + if (pathComponents.length == 1){ + parent = startingPoint; } else { - throw new IllegalArgumentException("Dataset is not compound."); + String parentPath = String.join("/", Arrays.copyOf(pathComponents, pathComponents.length - 1)); + parent = JhdfUtils.getGroupByPath(startingPoint, parentPath); } + if (!(parent.getChild(datasetName) instanceof WritableDatasetImpl writableDataset)) + throw new IllegalArgumentException("`" + datasetName + "` is not a writable dataset!"); + return writableDataset; + } + + public static String[] getCompoundDatasetMemberNames(Dataset cds) { + if (!cds.isCompound() || !(cds.getDataType() instanceof CompoundDataType compoundDataType)) + throw new IllegalArgumentException("Dataset is not compound."); + return compoundDataType.getMembers().stream().map(CompoundDataType.CompoundDataMember::getName).toArray(String[]::new); } }