From e64a9e274aac159541a61b98f39e97cfb9ab4bc2 Mon Sep 17 00:00:00 2001 From: Jim Myers Date: Fri, 30 Jan 2026 09:54:19 -0500 Subject: [PATCH 1/3] Add synchronization, avoid sharing list across fmds, copy prov --- .../edu/harvard/iq/dataverse/Dataset.java | 16 +--------- .../harvard/iq/dataverse/DatasetVersion.java | 17 +---------- .../harvard/iq/dataverse/FileMetadata.java | 29 ++++++------------- 3 files changed, 11 insertions(+), 51 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataset.java b/src/main/java/edu/harvard/iq/dataverse/Dataset.java index e7e5903482c..bde1984e38f 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataset.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataset.java @@ -406,21 +406,7 @@ private DatasetVersion createNewDatasetVersion(Template template, FileMetadata f in a pre-save validation SEK 12/6/2021 */ for (FileMetadata fm : latestVersion.getFileMetadatas()) { - FileMetadata newFm = new FileMetadata(); - // TODO: - // the "category" will be removed, shortly. - // (replaced by multiple, tag-like categories of - // type DataFileCategory) -- L.A. beta 10 - //newFm.setCategory(fm.getCategory()); - // yep, these are the new categories: - newFm.setCategories(fm.getCategories()); - newFm.setDescription(fm.getDescription()); - newFm.setLabel(fm.getLabel()); - newFm.setDirectoryLabel(fm.getDirectoryLabel()); - newFm.setRestricted(fm.isRestricted()); - newFm.setDataFile(fm.getDataFile()); - newFm.setDatasetVersion(dsv); - newFm.setProvFreeForm(fm.getProvFreeForm()); + FileMetadata newFm = fm.createCopy(); newFm.setInPriorVersion(true); //fmVarMet would be updated in DCT diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java index 93b0ccfef61..adf64456ecc 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java @@ -706,22 +706,7 @@ public DatasetVersion cloneDatasetVersion(){ */ for (FileMetadata fm : this.getFileMetadatas()) { - FileMetadata newFm = new FileMetadata(); - // TODO: - // the "category" will be removed, shortly. - // (replaced by multiple, tag-like categories of - // type DataFileCategory) -- L.A. beta 10 - //newFm.setCategory(fm.getCategory()); - // yep, these are the new categories: - newFm.setCategories(fm.getCategories()); - newFm.setDescription(fm.getDescription()); - newFm.setLabel(fm.getLabel()); - newFm.setDirectoryLabel(fm.getDirectoryLabel()); - newFm.setRestricted(fm.isRestricted()); - newFm.setDataFile(fm.getDataFile()); - newFm.setDatasetVersion(dsv); - newFm.setProvFreeForm(fm.getProvFreeForm()); - + FileMetadata newFm = fm.createCopy(); dsv.getFileMetadatas().add(newFm); } diff --git a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java index b60b5afedd3..a50055cf0d1 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java +++ b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java @@ -168,6 +168,7 @@ public FileMetadata createCopy() { fmd.setLabel( getLabel() ); fmd.setRestricted( isRestricted() ); fmd.setDirectoryLabel(getDirectoryLabel()); + fmd.setProvFreeForm(getProvFreeForm()); return fmd; } @@ -245,38 +246,26 @@ public void setVarGroups(List varGroups) { public List getCategories() { if (fileCategories != null) { - /* - * fileCategories can sometimes be an - * org.eclipse.persistence.indirection.IndirectList When that happens, the - * comparator in the Collections.sort below is not called, possibly due to - * https://bugs.eclipse.org/bugs/show_bug.cgi?id=446236 which is Java 1.8+ - * specific Converting to an ArrayList solves the problem, but the longer term - * solution may be in avoiding the IndirectList or moving to a new version of - * the jar it is in. - */ - if (!(fileCategories instanceof ArrayList)) { - List newDFCs = new ArrayList(); - for (DataFileCategory fdc : fileCategories) { - newDFCs.add(fdc); + synchronized (this) { + if (!(fileCategories instanceof ArrayList)) { + fileCategories = new ArrayList<>(fileCategories); } - setCategories(newDFCs); + Collections.sort(fileCategories, FileMetadata.compareByNameWithSortCategories); } - Collections.sort(fileCategories, FileMetadata.compareByNameWithSortCategories); } return fileCategories; } - - public void setCategories(List fileCategories) { + + public synchronized void setCategories(List fileCategories) { this.fileCategories = fileCategories; } - - public void addCategory(DataFileCategory category) { + + public synchronized void addCategory(DataFileCategory category) { if (fileCategories == null) { fileCategories = new ArrayList<>(); } fileCategories.add(category); } - /** * Retrieve categories * @return From 435031c80a50058a46736d4b5dd7762c3031fd55 Mon Sep 17 00:00:00 2001 From: Jim Myers Date: Fri, 30 Jan 2026 11:36:13 -0500 Subject: [PATCH 2/3] make sure fmd is associated with correct version --- src/main/java/edu/harvard/iq/dataverse/Dataset.java | 4 +--- .../java/edu/harvard/iq/dataverse/DatasetVersion.java | 3 +-- .../java/edu/harvard/iq/dataverse/FileMetadata.java | 11 +++++------ .../command/impl/CreateDatasetVersionCommand.java | 10 ++++------ 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/main/java/edu/harvard/iq/dataverse/Dataset.java b/src/main/java/edu/harvard/iq/dataverse/Dataset.java index bde1984e38f..ba32c975c61 100644 --- a/src/main/java/edu/harvard/iq/dataverse/Dataset.java +++ b/src/main/java/edu/harvard/iq/dataverse/Dataset.java @@ -406,7 +406,7 @@ private DatasetVersion createNewDatasetVersion(Template template, FileMetadata f in a pre-save validation SEK 12/6/2021 */ for (FileMetadata fm : latestVersion.getFileMetadatas()) { - FileMetadata newFm = fm.createCopy(); + FileMetadata newFm = fm.createCopyInVersion(dsv); newFm.setInPriorVersion(true); //fmVarMet would be updated in DCT @@ -418,8 +418,6 @@ private DatasetVersion createNewDatasetVersion(Template template, FileMetadata f newFm.copyVarGroups(fm.getVarGroups()); } } - - dsv.getFileMetadatas().add(newFm); } if (latestVersion.getTermsOfUseAndAccess()!= null){ diff --git a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java index adf64456ecc..71f5c229e3d 100644 --- a/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java +++ b/src/main/java/edu/harvard/iq/dataverse/DatasetVersion.java @@ -706,8 +706,7 @@ public DatasetVersion cloneDatasetVersion(){ */ for (FileMetadata fm : this.getFileMetadatas()) { - FileMetadata newFm = fm.createCopy(); - dsv.getFileMetadatas().add(newFm); + fm.createCopyInVersion(dsv); } if (this.getTermsOfUseAndAccess()!= null){ diff --git a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java index a50055cf0d1..c87d37f41e3 100644 --- a/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java +++ b/src/main/java/edu/harvard/iq/dataverse/FileMetadata.java @@ -154,22 +154,21 @@ public class FileMetadata implements Serializable { private Collection variableMetadatas; /** - * Creates a copy of {@code this}, with identical business logic fields. - * E.g., {@link #label} would be duplicated; {@link #version} will not. + * Creates a copy of {@code this}, with identical business logic fields, making the bi-drectional connections to the specified version. * - * @return A copy of {@code this}, except for the DB-related data. + * @return A copy of {@code this} */ - public FileMetadata createCopy() { + public FileMetadata createCopyInVersion(DatasetVersion dsv) { FileMetadata fmd = new FileMetadata(); fmd.setCategories(new LinkedList<>(getCategories()) ); fmd.setDataFile( getDataFile() ); - fmd.setDatasetVersion( getDatasetVersion() ); + fmd.setDatasetVersion( dsv ); fmd.setDescription( getDescription() ); fmd.setLabel( getLabel() ); fmd.setRestricted( isRestricted() ); fmd.setDirectoryLabel(getDirectoryLabel()); fmd.setProvFreeForm(getProvFreeForm()); - + dsv.getFileMetadatas().add(fmd); return fmd; } diff --git a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetVersionCommand.java b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetVersionCommand.java index 6539ac27ea2..6e079b6c460 100644 --- a/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetVersionCommand.java +++ b/src/main/java/edu/harvard/iq/dataverse/engine/command/impl/CreateDatasetVersionCommand.java @@ -61,13 +61,11 @@ public DatasetVersion execute(CommandContext ctxt) throws CommandException { registerExternalVocabValuesIfAny(ctxt, newVersion); - List newVersionMetadatum = new ArrayList<>(latest.getFileMetadatas().size()); - for ( FileMetadata fmd : latest.getFileMetadatas() ) { - FileMetadata fmdCopy = fmd.createCopy(); - fmdCopy.setDatasetVersion(newVersion); - newVersionMetadatum.add( fmdCopy ); + List latestVersionMetadata = latest.getFileMetadatas(); + newVersion.setFileMetadatas(new ArrayList<>(latest.getFileMetadatas().size())); + for ( FileMetadata fmd : latestVersionMetadata ) { + fmd.createCopyInVersion(newVersion); } - newVersion.setFileMetadatas(newVersionMetadatum); //moving prepare Dataset here //because it includes validation and we need the validation From f1ea924d0b8a56b498399fc858f4406a6140efd9 Mon Sep 17 00:00:00 2001 From: Jim Myers Date: Fri, 30 Jan 2026 11:45:09 -0500 Subject: [PATCH 3/3] make test use new method --- .../dataverse/DatasetVersionDifferenceTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test/java/edu/harvard/iq/dataverse/DatasetVersionDifferenceTest.java b/src/test/java/edu/harvard/iq/dataverse/DatasetVersionDifferenceTest.java index cc27ba4cf87..4ca4a984c2a 100644 --- a/src/test/java/edu/harvard/iq/dataverse/DatasetVersionDifferenceTest.java +++ b/src/test/java/edu/harvard/iq/dataverse/DatasetVersionDifferenceTest.java @@ -76,7 +76,8 @@ public void testDifferencing() { datasetVersion2.setVersionState(DatasetVersion.VersionState.DRAFT); datasetVersion2.setTermsOfUseAndAccess(new TermsOfUseAndAccess()); datasetVersion2.getTermsOfUseAndAccess().setLicense(license); - + datasetVersion.setFileMetadatas(new ArrayList<>()); + // Published version's two files DataFile dataFile = new DataFile(); dataFile.setId(1L); @@ -88,19 +89,17 @@ public void testDifferencing() { FileMetadata fileMetadata2 = createFileMetadata(20L, datasetVersion, dataFile2, "file2.txt"); + List fileMetadatas = new ArrayList<>(Arrays.asList(fileMetadata1, fileMetadata2)); + datasetVersion.setFileMetadatas(fileMetadatas); + // Draft version - same two files with one label change - FileMetadata fileMetadata3 = fileMetadata1.createCopy(); + FileMetadata fileMetadata3 = fileMetadata1.createCopyInVersion(datasetVersion2); fileMetadata3.setId(30L); - FileMetadata fileMetadata4 = fileMetadata2.createCopy(); + FileMetadata fileMetadata4 = fileMetadata2.createCopyInVersion(datasetVersion2); fileMetadata4.setLabel("file3.txt"); fileMetadata4.setId(40L); - List fileMetadatas = new ArrayList<>(Arrays.asList(fileMetadata1, fileMetadata2)); - datasetVersion.setFileMetadatas(fileMetadatas); - List fileMetadatas2 = new ArrayList<>(Arrays.asList(fileMetadata3, fileMetadata4)); - datasetVersion2.setFileMetadatas(fileMetadatas2); - SimpleDateFormat dateFmt = new SimpleDateFormat("yyyyMMdd"); Date publicationDate; try {