diff --git a/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataEntity.java b/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataEntity.java index 93ca2ae8..e6e28f8f 100644 --- a/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataEntity.java +++ b/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataEntity.java @@ -46,11 +46,12 @@ public DataEntity(AbstractDataEntityBuilder entityBuilder) { /** * Adds an author ID to the entity. - * + *

* Calling this multiple times will add multiple author IDs. * * @param id the identifier of the author. */ + @SuppressWarnings("unused") public void addAuthorId(String id) { this.addIdProperty("author", id); } @@ -115,11 +116,15 @@ abstract static class AbstractDataEntityBuilder authors = new ArrayList<>(); /** - * Sets the location of the data entity. - * + * Sets the location of the data entity to make a copy from when writing the crate. + *

+ * Use this if you want to copy the associated file to the crate. + * Do not use it if the file should already be considered (e.g. + * as part of a DataSetEntity). + *

* If the ID has not been set manually in beforehand, it will be derived * from the path. Use {@link #setId(String)} to override it or set it in - * beforehand. Note that another call of {@link #setLocation(Path)} will + * beforehand. Note that another call of this method will * not override the ID as it has been set by the previous call! * * @param path the location of the data. May be null, in which case @@ -153,7 +158,7 @@ public T setLocationWithExceptions(Path path) throws IllegalArgumentException { /** * Same as {@link #setLocation(Path)} but instead of associating this * entity with a file, it will point to some place on the internet. - * + *

* Via the specification, this means the uri will be set as the ID. This * call is therefore equivalent to {@link #setId(String)}. * @@ -208,7 +213,7 @@ public T setContentLocation(String id) { /** * Data Entity builder class that allows for easier data entity creation. - * + *

* If not explicitly mentioned, all methods avoid Exceptions and will * silently ignore null-parameters, in which case nothing will happen. Use * the available *WithExceptions-methods in case you need them. diff --git a/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataSetEntity.java b/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataSetEntity.java index 97d302f7..832d9819 100644 --- a/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataSetEntity.java +++ b/src/main/java/edu/kit/datamanager/ro_crate/entities/data/DataSetEntity.java @@ -12,6 +12,7 @@ import net.lingala.zip4j.ZipFile; import net.lingala.zip4j.exception.ZipException; import net.lingala.zip4j.io.outputstream.ZipOutputStream; +import net.lingala.zip4j.model.ZipParameters; /** * A helping class for the creating of Data entities of type Dataset. @@ -45,14 +46,20 @@ public void removeFromHasPart(String str) { @Override public void saveToZip(ZipFile zipFile) throws ZipException { if (this.getPath() != null) { - zipFile.addFolder(this.getPath().toFile()); + ZipParameters parameters = new ZipParameters(); + parameters.setRootFolderNameInZip(this.getId()); + parameters.setIncludeRootFolder(false); + zipFile.addFolder(this.getPath().toFile(), parameters); } } @Override - public void saveToStream(ZipOutputStream zipOutputStream) throws ZipException, IOException { + public void saveToStream(ZipOutputStream zipOutputStream) throws IOException { if (this.getPath() != null) { - ZipUtil.addFolderToZipStream(zipOutputStream, this.getPath().toAbsolutePath().toString(), this.getPath().getFileName().toString()); + ZipUtil.addFolderToZipStream( + zipOutputStream, + this.getPath().toAbsolutePath().toString(), + this.getId()); } } diff --git a/src/main/java/edu/kit/datamanager/ro_crate/util/ZipUtil.java b/src/main/java/edu/kit/datamanager/ro_crate/util/ZipUtil.java index 36841318..c1da0137 100644 --- a/src/main/java/edu/kit/datamanager/ro_crate/util/ZipUtil.java +++ b/src/main/java/edu/kit/datamanager/ro_crate/util/ZipUtil.java @@ -13,9 +13,24 @@ */ public class ZipUtil { - public static void addFolderToZipStream(ZipOutputStream zipOutputStream, File folder, String parentPath) throws IOException { + /** + * Adds a folder and its contents to a ZipOutputStream. + * + * @param zipOutputStream The ZipOutputStream to which the folder will be added. + * @param folder The folder to be added. + * @param parentPath The path in the zip file where the folder will be added. + * @throws IOException If an I/O error occurs. + */ + public static void addFolderToZipStream( + ZipOutputStream zipOutputStream, + File folder, + String parentPath + ) throws IOException { if (!folder.exists() || !folder.isDirectory()) { - throw new IllegalArgumentException("The provided folder path is not a valid directory: " + folder.getAbsolutePath()); + throw new IllegalArgumentException( + "The provided folder path is not a valid directory: %s" + .formatted(folder.getAbsolutePath()) + ); } File[] files = folder.listFiles(); @@ -33,11 +48,34 @@ public static void addFolderToZipStream(ZipOutputStream zipOutputStream, File fo } } - public static void addFolderToZipStream(ZipOutputStream zipOutputStream, String folderPath, String parentPath) throws IOException { + /** + * Adds a folder and its contents to a ZipOutputStream. + * @param zipOutputStream The ZipOutputStream to which the folder will be added. + * @param folderPath The path of the folder to be added. + * @param parentPath The path in the zip file where the folder will be added. + * @throws IOException If an I/O error occurs. + */ + public static void addFolderToZipStream( + ZipOutputStream zipOutputStream, + String folderPath, + String parentPath + ) throws IOException { addFolderToZipStream(zipOutputStream, new File(folderPath), parentPath); } - public static void addFileToZipStream(ZipOutputStream zipOutputStream, File file, String zipEntryPath) throws IOException { + /** + * Adds a file to a ZipOutputStream. + * + * @param zipOutputStream The ZipOutputStream to which the file will be added. + * @param file The file to be added. + * @param zipEntryPath The path in the zip file where the file will be added. + * @throws IOException If an I/O error occurs. + */ + public static void addFileToZipStream( + ZipOutputStream zipOutputStream, + File file, + String zipEntryPath + ) throws IOException { ZipParameters zipParameters = new ZipParameters(); zipParameters.setFileNameInZip(zipEntryPath); zipOutputStream.putNextEntry(zipParameters); diff --git a/src/test/java/edu/kit/datamanager/ro_crate/writer/CrateWriterTest.java b/src/test/java/edu/kit/datamanager/ro_crate/writer/CrateWriterTest.java index 0e6e51e0..429fc450 100644 --- a/src/test/java/edu/kit/datamanager/ro_crate/writer/CrateWriterTest.java +++ b/src/test/java/edu/kit/datamanager/ro_crate/writer/CrateWriterTest.java @@ -50,7 +50,15 @@ void testFilesBeingAdjusted(@TempDir Path tempDir) throws IOException { Path writtenCrate = tempDir.resolve("written-crate"); Path extractionPath = tempDir.resolve("checkMe"); { - RoCrate builtCrate = getCrateWithFileAndDir(pathToFile, pathToDir).build(); + RoCrate builtCrate = getCrateWithFileAndDir(pathToFile, pathToDir) + .addDataEntity(new DataSetEntity.DataSetBuilder() + .addProperty("name", "Subdir") + .addProperty("description", "Some subdir") + .setLocationWithExceptions(pathToDir.resolve("subdir")) + .setId("lots_of_little_files/subdir-renamed/") + .build() + ) + .build(); this.saveCrate(builtCrate, writtenCrate); this.ensureCrateIsExtractedIn(writtenCrate, extractionPath); } @@ -80,6 +88,20 @@ void testFilesBeingAdjusted(@TempDir Path tempDir) throws IOException { Files.isDirectory(extractionPath.resolve("lots_of_little_files/")), "The directory 'lots_of_little_files' should be present" ); + assertTrue( + Files.isDirectory(extractionPath.resolve("lots_of_little_files/").resolve("subdir")), + "The directory 'lots_of_little_files/subdir' should be present" + ); + + /* + * As we added another DataSetEntity with location, the subdir should have a renamed copy as well + * Note: If this behavior is to be changed later on, we possibly need to change the documentation + * of {@link AbstractDataEntityBuilder#setLocation(Path)}. + */ + assertTrue( + Files.isDirectory(extractionPath.resolve("lots_of_little_files/").resolve("subdir-renamed")), + "The directory 'lots_of_little_files/subdir' should be present" + ); } /**