From a1a77b5492992324b63cf3951a8f0181551e8b6f Mon Sep 17 00:00:00 2001 From: tysonlt Date: Tue, 13 Jul 2021 13:03:34 +1000 Subject: [PATCH 01/38] added support for 'relationships' manifest --- .../app/itemimport/ItemImportCLITool.java | 7 + .../app/itemimport/ItemImportServiceImpl.java | 136 +++++++++++++++++- .../itemimport/service/ItemImportService.java | 5 + 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java index 7cad97df31..07c9eab8d9 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java @@ -94,6 +94,7 @@ public class ItemImportCLITool { options.addOption("R", "resume", false, "resume a failed import (add only)"); options.addOption("q", "quiet", false, "don't display metadata"); + options.addOption("l", "relationships", false, "process relationships manifest"); options.addOption("h", "help", false, "help"); @@ -107,6 +108,7 @@ public class ItemImportCLITool { String[] collections = null; // db ID or handles boolean isTest = false; boolean isResume = false; + boolean processRelationships = false; boolean useWorkflow = false; boolean useWorkflowSendEmail = false; boolean isQuiet = false; @@ -184,6 +186,10 @@ public class ItemImportCLITool { collections = line.getOptionValues('c'); } + if (line.hasOption('l')) { //relationships + processRelationships = true; + } + if (line.hasOption('R')) { isResume = true; System.out @@ -303,6 +309,7 @@ public class ItemImportCLITool { myloader.setResume(isResume); myloader.setUseWorkflow(useWorkflow); myloader.setUseWorkflowSendEmail(useWorkflowSendEmail); + myloader.setProcessRelationships(processRelationships); myloader.setQuiet(isQuiet); // create a context diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index c89b2d0723..98270b04fc 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -44,7 +44,6 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; - import org.apache.commons.collections4.ComparatorUtils; import org.apache.commons.io.FileDeleteStrategy; import org.apache.commons.io.FileUtils; @@ -68,6 +67,8 @@ import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchemaEnum; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; @@ -77,6 +78,8 @@ import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -151,6 +154,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected WorkflowService workflowService; @Autowired(required = true) protected ConfigurationService configurationService; + @Autowired(required = true) + protected RelationshipService relationshipService; + @Autowired(required = true) + protected RelationshipTypeService relationshipTypeService; protected String tempWorkDir; @@ -159,6 +166,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected boolean useWorkflow = false; protected boolean useWorkflowSendEmail = false; protected boolean isQuiet = false; + protected boolean processRelationships = false; @Override public void afterPropertiesSet() throws Exception { @@ -211,10 +219,13 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // create the mapfile File outFile = null; PrintWriter mapOut = null; + try { Map skipItems = new HashMap<>(); // set of items to skip if in 'resume' // mode + Map itemMap = new HashMap<>(); //remember which folder item was imported from + System.out.println("Adding items from directory: " + sourceDir); log.debug("Adding items from directory: " + sourceDir); System.out.println("Generating mapfile: " + mapFile); @@ -274,12 +285,23 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } else { clist = mycollections; } + Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template); + + if (processRelationships) { + itemMap.put(dircontents[i], item); + } + c.uncacheEntity(item); System.out.println(i + " " + dircontents[i]); } } + if (processRelationships) { + //now that all items are imported, iterate again to link relationships + addRelationships(c, sourceDir, itemMap); + } + } finally { if (mapOut != null) { mapOut.flush(); @@ -288,6 +310,112 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } + protected void addRelationships(Context c, String sourceDir, Map itemMap) throws Exception { + + System.out.println("Linking relationships"); + + for (Map.Entry itemEntry : itemMap.entrySet()) { + + String folderName = itemEntry.getKey(); + String path = sourceDir + File.separatorChar + folderName; + Item leftItem = itemEntry.getValue(); + + System.out.println("Adding relationships from directory "+ folderName); + + //look for a 'relationship' manifest + Map relationships = processRelationshipFile(path, "relationships"); + if (!relationships.isEmpty()) { + + for (Map.Entry relEntry : relationships.entrySet()) { + + Integer relationshipId = relEntry.getKey(); + String mappedItemFolder = relEntry.getValue(); + Item rightItem = itemMap.get(mappedItemFolder); + + RelationshipType relationshipType = null; + try { + relationshipType = relationshipTypeService.find(c, relationshipId.intValue()); + } catch (Exception e) { + System.out.println("\tERROR: relationship type "+ relationshipId +" not found."); + throw e; + } + + Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); + + System.out.println("\tAdded relationship to " + rightItem.getHandle()); + + } + + } + + } + + } + + protected Map processRelationshipFile(String path, String filename) throws Exception { + + File file = new File(path + File.separatorChar + filename); + Map result = new HashMap(); + + if (file.exists()) { + + System.out.println("\tProcessing relationships file: " + filename); + + BufferedReader br = null; + try { + br = new BufferedReader(new FileReader(file)); + String line = null; + while ((line = br.readLine()) != null) { + line = line.trim(); + if ("".equals(line)) { + continue; + } + + int relationshipId; + String folderName = null; + + //format: + StringTokenizer st = new StringTokenizer(line); + + if (st.hasMoreTokens()) { + try { + relationshipId = Integer.valueOf(st.nextToken()); + } catch (NumberFormatException e) { + throw new Exception("Bad mapfile line:\n" + line); + } + } else { + throw new Exception("Bad mapfile line:\n" + line); + } + + if (st.hasMoreTokens()) { + folderName = st.nextToken(); + } else { + throw new Exception("Bad mapfile line:\n" + line); + } + + result.put(relationshipId, folderName); + + } + + } catch (FileNotFoundException e) { + System.out.println("\tNo relationships file found."); + } finally { + if (br != null) { + try { + br.close(); + } catch (IOException e) { + System.out.println("Non-critical problem releasing resources."); + } + } + } + + } else { + System.out.println("\tNo relationships file found."); + } + + return result; + } + @Override public void replaceItems(Context c, List mycollections, String sourceDir, String mapFile, boolean template) throws Exception { @@ -1823,4 +1951,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea public void setQuiet(boolean isQuiet) { this.isQuiet = isQuiet; } + + @Override + public void setProcessRelationships(boolean processRelationships) { + this.processRelationships = processRelationships; + } + } diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java index af333764b5..ab4473ad08 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java @@ -229,6 +229,11 @@ public interface ItemImportService { */ public void setUseWorkflowSendEmail(boolean useWorkflowSendMail); + /** + * @param processRelationships whether to look for a relationships manifest + */ + public void setProcessRelationships(boolean processRelationships); + /** * Set quiet flag * From c35fba249a1610169dd1ae37a5ead6ea54c5d09e Mon Sep 17 00:00:00 2001 From: tysonlt Date: Tue, 13 Jul 2021 13:33:18 +1000 Subject: [PATCH 02/38] allow item lookup by uuid, handle, or import folder name --- .../app/itemimport/ItemImportServiceImpl.java | 57 +++++++++++++++---- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 98270b04fc..61be85f79e 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -310,6 +310,15 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } + /** + * Add relationships from a 'relationships' manifest file. + * + * Each line in the file contains a relationship type id and an item identifier in the following format: + * + * + * + * The input_item_folder should refer the folder name of another item in this import batch. + */ protected void addRelationships(Context c, String sourceDir, Map itemMap) throws Exception { System.out.println("Linking relationships"); @@ -328,21 +337,24 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea for (Map.Entry relEntry : relationships.entrySet()) { - Integer relationshipId = relEntry.getKey(); - String mappedItemFolder = relEntry.getValue(); - Item rightItem = itemMap.get(mappedItemFolder); + Integer relationshipTypeId = relEntry.getKey(); + String itemIdentifier = relEntry.getValue(); RelationshipType relationshipType = null; try { - relationshipType = relationshipTypeService.find(c, relationshipId.intValue()); + relationshipType = relationshipTypeService.find(c, relationshipTypeId.intValue()); } catch (Exception e) { - System.out.println("\tERROR: relationship type "+ relationshipId +" not found."); + System.out.println("\tERROR: relationship type "+ relationshipTypeId +" not found."); throw e; } - Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); + Item rightItem = resolveRelatedItem(c, itemMap, itemIdentifier); + if (null == rightItem) { + throw new Exception("\tERROR: could not find item for "+ itemIdentifier); + } - System.out.println("\tAdded relationship to " + rightItem.getHandle()); + Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); + System.out.println("\tAdded relationship (type: "+ relationshipTypeId +") to "+ rightItem.getHandle()); } @@ -352,6 +364,27 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } + protected Item resolveRelatedItem(Context c, Map itemMap, String itemIdentifier) throws Exception { + + Item item = null; + + if (itemMap.containsKey(itemIdentifier)) { + //identifier refers to a folder name in this import batch + item = itemMap.get(itemIdentifier); + + } else if (itemIdentifier.indexOf('/') != -1) { + //resolve by handle + item = (Item) handleService.resolveToObject(c, itemIdentifier); + + } else { + //try to resolve by UUID + item = itemService.findByIdOrLegacyId(c, itemIdentifier); + } + + return item; + + } + protected Map processRelationshipFile(String path, String filename) throws Exception { File file = new File(path + File.separatorChar + filename); @@ -371,15 +404,15 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea continue; } - int relationshipId; - String folderName = null; + int relationshipTypeId; + String itemIdentifier = null; //format: StringTokenizer st = new StringTokenizer(line); if (st.hasMoreTokens()) { try { - relationshipId = Integer.valueOf(st.nextToken()); + relationshipTypeId = Integer.valueOf(st.nextToken()); } catch (NumberFormatException e) { throw new Exception("Bad mapfile line:\n" + line); } @@ -388,12 +421,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } if (st.hasMoreTokens()) { - folderName = st.nextToken(); + itemIdentifier = st.nextToken(); } else { throw new Exception("Bad mapfile line:\n" + line); } - result.put(relationshipId, folderName); + result.put(relationshipTypeId, itemIdentifier); } From 2455171a58f797a2a8bbb57335a0afc4b67143f2 Mon Sep 17 00:00:00 2001 From: tysonlt Date: Tue, 13 Jul 2021 14:06:47 +1000 Subject: [PATCH 03/38] support multiple relationships of the same type --- .../app/itemimport/ItemImportServiceImpl.java | 117 +++++++++++------- 1 file changed, 75 insertions(+), 42 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 61be85f79e..daab4e13d9 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -310,15 +310,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } - /** - * Add relationships from a 'relationships' manifest file. - * - * Each line in the file contains a relationship type id and an item identifier in the following format: - * - * - * - * The input_item_folder should refer the folder name of another item in this import batch. - */ + /** + * Add relationships from a 'relationships' manifest file. + * + * @param c Context + * @param sourceDir The parent import source directory + * @param itemMap Item imported in this batch, keyed by their import subfolder + * @throws Exception + */ protected void addRelationships(Context c, String sourceDir, Map itemMap) throws Exception { System.out.println("Linking relationships"); @@ -332,13 +331,13 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea System.out.println("Adding relationships from directory "+ folderName); //look for a 'relationship' manifest - Map relationships = processRelationshipFile(path, "relationships"); + Map> relationships = processRelationshipFile(path, "relationships"); if (!relationships.isEmpty()) { - for (Map.Entry relEntry : relationships.entrySet()) { + for (Map.Entry> relEntry : relationships.entrySet()) { Integer relationshipTypeId = relEntry.getKey(); - String itemIdentifier = relEntry.getValue(); + List identifierList = relEntry.getValue(); RelationshipType relationshipType = null; try { @@ -348,13 +347,17 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea throw e; } - Item rightItem = resolveRelatedItem(c, itemMap, itemIdentifier); - if (null == rightItem) { - throw new Exception("\tERROR: could not find item for "+ itemIdentifier); - } + for (String itemIdentifier : identifierList) { - Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); - System.out.println("\tAdded relationship (type: "+ relationshipTypeId +") to "+ rightItem.getHandle()); + Item rightItem = resolveRelatedItem(c, itemMap, itemIdentifier); + if (null == rightItem) { + throw new Exception("\tERROR: could not find item for "+ itemIdentifier); + } + + Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); + System.out.println("\tAdded relationship (type: "+ relationshipTypeId +") to "+ rightItem.getHandle()); + + } } @@ -364,31 +367,24 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } - protected Item resolveRelatedItem(Context c, Map itemMap, String itemIdentifier) throws Exception { - - Item item = null; - - if (itemMap.containsKey(itemIdentifier)) { - //identifier refers to a folder name in this import batch - item = itemMap.get(itemIdentifier); - - } else if (itemIdentifier.indexOf('/') != -1) { - //resolve by handle - item = (Item) handleService.resolveToObject(c, itemIdentifier); - - } else { - //try to resolve by UUID - item = itemService.findByIdOrLegacyId(c, itemIdentifier); - } - - return item; - - } - - protected Map processRelationshipFile(String path, String filename) throws Exception { + /** + * Read the relationship manifest file. + * + * Each line in the file contains a relationship type id and an item identifier in the following format: + * + * + * + * The input_item_folder should refer the folder name of another item in this import batch. + * + * @param path The main import folder path. + * @param filename The name of the manifest file to check ('relationships') + * @return Map of found relationships + * @throws Exception + */ + protected Map> processRelationshipFile(String path, String filename) throws Exception { File file = new File(path + File.separatorChar + filename); - Map result = new HashMap(); + Map> result = new HashMap<>(); if (file.exists()) { @@ -426,7 +422,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea throw new Exception("Bad mapfile line:\n" + line); } - result.put(relationshipTypeId, itemIdentifier); + if (!result.containsKey(relationshipTypeId)) { + result.put(relationshipTypeId, new ArrayList<>()); + } + + result.get(relationshipTypeId).add(itemIdentifier); } @@ -449,6 +449,39 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea return result; } + /** + * Resolve an item identifier referred to in the relationships manifest file. + * + * The import item map will be checked first to see if the identifier refers to an item folder + * that was just imported. Next it will try to find the item by handle or UUID. + * + * @param c Context + * @param itemMap Item imported in this batch, keyed by their import subfolder + * @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or another import subfolder) + * @return Item if found, or null. + * @throws Exception + */ + protected Item resolveRelatedItem(Context c, Map itemMap, String itemIdentifier) throws Exception { + + Item item = null; + + if (itemMap.containsKey(itemIdentifier)) { + //identifier refers to a folder name in this import batch + item = itemMap.get(itemIdentifier); + + } else if (itemIdentifier.indexOf('/') != -1) { + //resolve by handle + item = (Item) handleService.resolveToObject(c, itemIdentifier); + + } else { + //try to resolve by UUID + item = itemService.findByIdOrLegacyId(c, itemIdentifier); + } + + return item; + + } + @Override public void replaceItems(Context c, List mycollections, String sourceDir, String mapFile, boolean template) throws Exception { From 4972ee3f9817bcfb37dd37ec17fbd6deb1a15391 Mon Sep 17 00:00:00 2001 From: tysonlt Date: Tue, 13 Jul 2021 14:54:48 +1000 Subject: [PATCH 04/38] populate item map with skipped items --- .../org/dspace/app/itemimport/ItemImportServiceImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index daab4e13d9..9c28890762 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -266,6 +266,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea for (int i = 0; i < dircontents.length; i++) { if (skipItems.containsKey(dircontents[i])) { System.out.println("Skipping import of " + dircontents[i]); + + if (processRelationships) { + //we still need the item in the map for relationship linking + String skippedHandle = skipItems.get(dircontents[i]); + Item skippedItem = (Item) handleService.resolveToObject(c, skippedHandle); + itemMap.put(dircontents[i], skippedItem); + } + } else { List clist; if (directoryFileCollections) { From e53ed6151a6f5fb3bd7f78fb6f90207734104277 Mon Sep 17 00:00:00 2001 From: tysonlt Date: Wed, 14 Jul 2021 13:01:03 +1000 Subject: [PATCH 05/38] lookup relationship by type, allow entity lookup by meta --- .../app/itemimport/ItemImportServiceImpl.java | 189 +++++++++++++----- .../dspace/app/util/RelationshipUtils.java | 50 +++++ 2 files changed, 194 insertions(+), 45 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 9c28890762..10ffd6fb86 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -54,6 +54,7 @@ import org.apache.logging.log4j.Logger; import org.apache.xpath.XPathAPI; import org.dspace.app.itemimport.service.ItemImportService; import org.dspace.app.util.LocalSchemaFilenameFilter; +import org.dspace.app.util.RelationshipUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.service.AuthorizeService; @@ -67,6 +68,7 @@ import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchemaEnum; +import org.dspace.content.MetadataValue; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.WorkspaceItem; @@ -78,6 +80,7 @@ import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.MetadataValueService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.content.service.WorkspaceItemService; @@ -158,6 +161,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected RelationshipService relationshipService; @Autowired(required = true) protected RelationshipTypeService relationshipTypeService; + @Autowired(required = true) + protected MetadataValueService metadataValueService; protected String tempWorkDir; @@ -168,6 +173,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected boolean isQuiet = false; protected boolean processRelationships = false; + //remember which folder item was imported from + Map itemFolderMap = null; + @Override public void afterPropertiesSet() throws Exception { tempWorkDir = configurationService.getProperty("org.dspace.app.batchitemimport.work.dir"); @@ -224,7 +232,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Map skipItems = new HashMap<>(); // set of items to skip if in 'resume' // mode - Map itemMap = new HashMap<>(); //remember which folder item was imported from + itemFolderMap = new HashMap<>(); System.out.println("Adding items from directory: " + sourceDir); log.debug("Adding items from directory: " + sourceDir); @@ -271,7 +279,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea //we still need the item in the map for relationship linking String skippedHandle = skipItems.get(dircontents[i]); Item skippedItem = (Item) handleService.resolveToObject(c, skippedHandle); - itemMap.put(dircontents[i], skippedItem); + itemFolderMap.put(dircontents[i], skippedItem); } } else { @@ -297,7 +305,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template); if (processRelationships) { - itemMap.put(dircontents[i], item); + itemFolderMap.put(dircontents[i], item); } c.uncacheEntity(item); @@ -307,7 +315,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea if (processRelationships) { //now that all items are imported, iterate again to link relationships - addRelationships(c, sourceDir, itemMap); + addRelationships(c, sourceDir); } } finally { @@ -323,47 +331,75 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * * @param c Context * @param sourceDir The parent import source directory - * @param itemMap Item imported in this batch, keyed by their import subfolder * @throws Exception */ - protected void addRelationships(Context c, String sourceDir, Map itemMap) throws Exception { + protected void addRelationships(Context c, String sourceDir) throws Exception { System.out.println("Linking relationships"); - for (Map.Entry itemEntry : itemMap.entrySet()) { + for (Map.Entry itemEntry : itemFolderMap.entrySet()) { String folderName = itemEntry.getKey(); String path = sourceDir + File.separatorChar + folderName; - Item leftItem = itemEntry.getValue(); + Item item = itemEntry.getValue(); System.out.println("Adding relationships from directory "+ folderName); //look for a 'relationship' manifest - Map> relationships = processRelationshipFile(path, "relationships"); + Map> relationships = processRelationshipFile(path, "relationships"); if (!relationships.isEmpty()) { - for (Map.Entry> relEntry : relationships.entrySet()) { + for (Map.Entry> relEntry : relationships.entrySet()) { - Integer relationshipTypeId = relEntry.getKey(); + String relationshipType = relEntry.getKey(); List identifierList = relEntry.getValue(); - RelationshipType relationshipType = null; - try { - relationshipType = relationshipTypeService.find(c, relationshipTypeId.intValue()); - } catch (Exception e) { - System.out.println("\tERROR: relationship type "+ relationshipTypeId +" not found."); - throw e; - } - for (String itemIdentifier : identifierList) { - Item rightItem = resolveRelatedItem(c, itemMap, itemIdentifier); - if (null == rightItem) { - throw new Exception("\tERROR: could not find item for "+ itemIdentifier); + //find referenced item + Item relationItem = resolveRelatedItem(c, itemIdentifier); + if (null == relationItem) { + throw new Exception("Could not find item for "+ itemIdentifier); } - Relationship relationship = relationshipService.create(c, leftItem, rightItem, relationshipType, -1, -1); - System.out.println("\tAdded relationship (type: "+ relationshipTypeId +") to "+ rightItem.getHandle()); + //get entity type of entity and item + String itemEntityType = getEntityType(item); + String relatedEntityType = getEntityType(relationItem); + + //find matching relationship type + List relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName(c, relationshipType); + RelationshipType foundRelationshipType = RelationshipUtils.matchRelationshipType(relTypes, relatedEntityType, itemEntityType, relationshipType); + if (foundRelationshipType == null) { + throw new Exception("No Relationship type found for:\n" + + "Target type: " + relatedEntityType + "\n" + + "Origin referer type: " + itemEntityType + "\n" + + "with typeName: " + relationshipType + ); + } + + boolean left = false; + if (foundRelationshipType.getLeftwardType().equalsIgnoreCase(relationshipType)) { + left = true; + } + + // Placeholder items for relation placing + Item leftItem = null; + Item rightItem = null; + if (left) { + leftItem = item; + rightItem = relationItem; + } else { + leftItem = relationItem; + rightItem = item; + } + + // Create the relationship + int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem); + int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem); + Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace); + relationshipService.update(c, persistedRelationship); + + System.out.println("\tAdded relationship (type: "+ foundRelationshipType.getID() +") from "+ leftItem.getHandle() +" to "+ rightItem.getHandle()); } @@ -375,12 +411,22 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } + /** + * Get the item's entity type from meta. + * + * @param item + * @return + */ + protected String getEntityType(Item item) throws Exception { + return itemService.getMetadata(item, "dspace", "entity", "type", Item.ANY).get(0).getValue(); + } + /** * Read the relationship manifest file. * * Each line in the file contains a relationship type id and an item identifier in the following format: * - * + * relation. * * The input_item_folder should refer the folder name of another item in this import batch. * @@ -389,10 +435,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * @return Map of found relationships * @throws Exception */ - protected Map> processRelationshipFile(String path, String filename) throws Exception { + protected Map> processRelationshipFile(String path, String filename) throws Exception { File file = new File(path + File.separatorChar + filename); - Map> result = new HashMap<>(); + Map> result = new HashMap<>(); if (file.exists()) { @@ -408,33 +454,31 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea continue; } - int relationshipTypeId; + String relationshipType = null; String itemIdentifier = null; - //format: StringTokenizer st = new StringTokenizer(line); if (st.hasMoreTokens()) { - try { - relationshipTypeId = Integer.valueOf(st.nextToken()); - } catch (NumberFormatException e) { - throw new Exception("Bad mapfile line:\n" + line); + relationshipType= st.nextToken(); + if (relationshipType.split("\\.").length > 1) { + relationshipType = relationshipType.split("\\.")[1]; } } else { throw new Exception("Bad mapfile line:\n" + line); } if (st.hasMoreTokens()) { - itemIdentifier = st.nextToken(); + itemIdentifier = st.nextToken("").trim(); } else { throw new Exception("Bad mapfile line:\n" + line); } - if (!result.containsKey(relationshipTypeId)) { - result.put(relationshipTypeId, new ArrayList<>()); + if (!result.containsKey(relationshipType)) { + result.put(relationshipType, new ArrayList<>()); } - result.get(relationshipTypeId).add(itemIdentifier); + result.get(relationshipType).add(itemIdentifier); } @@ -464,26 +508,81 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * that was just imported. Next it will try to find the item by handle or UUID. * * @param c Context - * @param itemMap Item imported in this batch, keyed by their import subfolder * @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or another import subfolder) * @return Item if found, or null. * @throws Exception */ - protected Item resolveRelatedItem(Context c, Map itemMap, String itemIdentifier) throws Exception { + protected Item resolveRelatedItem(Context c, String itemIdentifier) throws Exception { - Item item = null; + if (itemIdentifier.contains(":")) { - if (itemMap.containsKey(itemIdentifier)) { - //identifier refers to a folder name in this import batch - item = itemMap.get(itemIdentifier); + if (itemIdentifier.startsWith("folderName:") || itemIdentifier.startsWith("rowName:")) { + //identifier refers to a folder name in this import + int i = itemIdentifier.indexOf(":"); + String folderName = itemIdentifier.substring(i + 1); + if (itemFolderMap.containsKey(folderName)) { + return itemFolderMap.get(folderName); + } + + } else { + + //lookup by meta value + int i = itemIdentifier.indexOf(":"); + String metaKey = itemIdentifier.substring(0, i); + String metaValue = itemIdentifier.substring(i + 1); + return findItemByMetaValue(c, metaKey, metaValue); + + } } else if (itemIdentifier.indexOf('/') != -1) { //resolve by handle - item = (Item) handleService.resolveToObject(c, itemIdentifier); + return (Item) handleService.resolveToObject(c, itemIdentifier); } else { //try to resolve by UUID - item = itemService.findByIdOrLegacyId(c, itemIdentifier); + return itemService.findByIdOrLegacyId(c, itemIdentifier); + } + + return null; + + } + + /** + * Lookup an item by a (unique) meta value. + * + * @param metaKey + * @param metaValue + * @return Item + * @throws Exception if single item not found. + */ + protected Item findItemByMetaValue(Context c, String metaKey, String metaValue) throws Exception { + + Item item = null; + + String mf[] = metaKey.split("\\."); + if (mf.length < 2) { + throw new Exception("Bad metadata field in reference: '" + metaKey + "' (expected syntax is schema.element[.qualifier])"); + } + String schema = mf[0]; + String element = mf[1]; + String qualifier = mf.length == 2 ? null : mf[2]; + try { + MetadataField mfo = metadataFieldService.findByElement(c, schema, element, qualifier); + Iterator mdv = metadataValueService.findByFieldAndValue(c, mfo, metaValue); + if (mdv.hasNext()) { + MetadataValue mdvVal = mdv.next(); + UUID uuid = mdvVal.getDSpaceObject().getID(); + if (mdv.hasNext()) { + throw new Exception("Ambiguous reference; multiple matches in db: " + metaKey); + } + item = itemService.find(c, uuid); + } + } catch (SQLException e) { + throw new Exception("Error looking up item by metadata reference: " + metaKey, e); + } + + if (item == null) { + throw new Exception("Item not found by metadata reference: " + metaKey); } return item; diff --git a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java new file mode 100644 index 0000000000..a7f38d610e --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java @@ -0,0 +1,50 @@ +package org.dspace.app.util; + +import java.util.List; + +import org.dspace.content.RelationshipType; + +public class RelationshipUtils { + + /** + * Matches two Entity types to a Relationship Type from a set of Relationship Types. + * + * @param relTypes set of Relationship Types. + * @param targetType entity type of target. + * @param originType entity type of origin referer. + * @return null or matched Relationship Type. + */ + public static RelationshipType matchRelationshipType(List relTypes, String targetType, String originType, String originTypeName) { + RelationshipType foundRelationshipType = null; + if (originTypeName.split("\\.").length > 1) { + originTypeName = originTypeName.split("\\.")[1]; + } + for (RelationshipType relationshipType : relTypes) { + // Is origin type leftward or righward + boolean isLeft = false; + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType)) { + isLeft = true; + } + if (isLeft) { + // Validate typeName reference + if (!relationshipType.getLeftwardType().equalsIgnoreCase(originTypeName)) { + continue; + } + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) && + relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) { + foundRelationshipType = relationshipType; + } + } else { + if (!relationshipType.getRightwardType().equalsIgnoreCase(originTypeName)) { + continue; + } + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) && + relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) { + foundRelationshipType = relationshipType; + } + } + } + return foundRelationshipType; + } + +} From a9f339724c6804724110fbac86782cb4aecfb4dc Mon Sep 17 00:00:00 2001 From: tysonlt Date: Wed, 14 Jul 2021 15:14:21 +1000 Subject: [PATCH 06/38] tweak comments and progress message --- .../org/dspace/app/itemimport/ItemImportServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 10ffd6fb86..9f0d142905 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -399,7 +399,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace); relationshipService.update(c, persistedRelationship); - System.out.println("\tAdded relationship (type: "+ foundRelationshipType.getID() +") from "+ leftItem.getHandle() +" to "+ rightItem.getHandle()); + System.out.println("\tAdded relationship (type: "+ relationshipType +") from "+ leftItem.getHandle() +" to "+ rightItem.getHandle()); } @@ -505,7 +505,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * Resolve an item identifier referred to in the relationships manifest file. * * The import item map will be checked first to see if the identifier refers to an item folder - * that was just imported. Next it will try to find the item by handle or UUID. + * that was just imported. Next it will try to find the item by handle or UUID, or by a unique + * meta value. * * @param c Context * @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or another import subfolder) From 16ffffc3a73472910efc7e059311e70ea4f4f067 Mon Sep 17 00:00:00 2001 From: tysonlt Date: Thu, 15 Jul 2021 11:32:13 +1000 Subject: [PATCH 07/38] fix checkstyle violations --- .../app/itemimport/ItemImportServiceImpl.java | 47 +++++----- .../dspace/app/util/RelationshipUtils.java | 87 +++++++++++-------- 2 files changed, 76 insertions(+), 58 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 9f0d142905..f2916bc8a7 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -44,6 +44,7 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; + import org.apache.commons.collections4.ComparatorUtils; import org.apache.commons.io.FileDeleteStrategy; import org.apache.commons.io.FileUtils; @@ -232,7 +233,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Map skipItems = new HashMap<>(); // set of items to skip if in 'resume' // mode - itemFolderMap = new HashMap<>(); + itemFolderMap = new HashMap<>(); System.out.println("Adding items from directory: " + sourceDir); log.debug("Adding items from directory: " + sourceDir); @@ -336,21 +337,21 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected void addRelationships(Context c, String sourceDir) throws Exception { System.out.println("Linking relationships"); - + for (Map.Entry itemEntry : itemFolderMap.entrySet()) { String folderName = itemEntry.getKey(); String path = sourceDir + File.separatorChar + folderName; Item item = itemEntry.getValue(); - System.out.println("Adding relationships from directory "+ folderName); + System.out.println("Adding relationships from directory " + folderName); //look for a 'relationship' manifest Map> relationships = processRelationshipFile(path, "relationships"); if (!relationships.isEmpty()) { for (Map.Entry> relEntry : relationships.entrySet()) { - + String relationshipType = relEntry.getKey(); List identifierList = relEntry.getValue(); @@ -359,16 +360,19 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea //find referenced item Item relationItem = resolveRelatedItem(c, itemIdentifier); if (null == relationItem) { - throw new Exception("Could not find item for "+ itemIdentifier); - } + throw new Exception("Could not find item for " + itemIdentifier); + } //get entity type of entity and item String itemEntityType = getEntityType(item); String relatedEntityType = getEntityType(relationItem); //find matching relationship type - List relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName(c, relationshipType); - RelationshipType foundRelationshipType = RelationshipUtils.matchRelationshipType(relTypes, relatedEntityType, itemEntityType, relationshipType); + List relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName( + c, relationshipType); + RelationshipType foundRelationshipType = RelationshipUtils.matchRelationshipType( + relTypes, relatedEntityType, itemEntityType, relationshipType); + if (foundRelationshipType == null) { throw new Exception("No Relationship type found for:\n" + "Target type: " + relatedEntityType + "\n" + @@ -396,10 +400,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea // Create the relationship int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem); int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem); - Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace); + Relationship persistedRelationship = relationshipService.create( + c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace); relationshipService.update(c, persistedRelationship); - System.out.println("\tAdded relationship (type: "+ relationshipType +") from "+ leftItem.getHandle() +" to "+ rightItem.getHandle()); + System.out.println("\tAdded relationship (type: " + relationshipType + ") from " + + leftItem.getHandle() + " to " + rightItem.getHandle()); } @@ -460,14 +466,14 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea StringTokenizer st = new StringTokenizer(line); if (st.hasMoreTokens()) { - relationshipType= st.nextToken(); + relationshipType = st.nextToken(); if (relationshipType.split("\\.").length > 1) { relationshipType = relationshipType.split("\\.")[1]; } } else { throw new Exception("Bad mapfile line:\n" + line); } - + if (st.hasMoreTokens()) { itemIdentifier = st.nextToken("").trim(); } else { @@ -475,9 +481,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } if (!result.containsKey(relationshipType)) { - result.put(relationshipType, new ArrayList<>()); - } - + result.put(relationshipType, new ArrayList<>()); + } + result.get(relationshipType).add(itemIdentifier); } @@ -493,7 +499,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } } - + } else { System.out.println("\tNo relationships file found."); } @@ -509,11 +515,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea * meta value. * * @param c Context - * @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or another import subfolder) + * @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or import subfolder) * @return Item if found, or null. * @throws Exception */ - protected Item resolveRelatedItem(Context c, String itemIdentifier) throws Exception { + protected Item resolveRelatedItem(Context c, String itemIdentifier) throws Exception { if (itemIdentifier.contains(":")) { @@ -524,7 +530,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea if (itemFolderMap.containsKey(folderName)) { return itemFolderMap.get(folderName); } - + } else { //lookup by meta value @@ -562,7 +568,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea String mf[] = metaKey.split("\\."); if (mf.length < 2) { - throw new Exception("Bad metadata field in reference: '" + metaKey + "' (expected syntax is schema.element[.qualifier])"); + throw new Exception("Bad metadata field in reference: '" + metaKey + + "' (expected syntax is schema.element[.qualifier])"); } String schema = mf[0]; String element = mf[1]; diff --git a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java index a7f38d610e..8a8ac00c7c 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java +++ b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java @@ -1,3 +1,10 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ package org.dspace.app.util; import java.util.List; @@ -6,45 +13,49 @@ import org.dspace.content.RelationshipType; public class RelationshipUtils { + private RelationshipUtils() { + } + /** * Matches two Entity types to a Relationship Type from a set of Relationship Types. - * + * * @param relTypes set of Relationship Types. - * @param targetType entity type of target. - * @param originType entity type of origin referer. - * @return null or matched Relationship Type. - */ - public static RelationshipType matchRelationshipType(List relTypes, String targetType, String originType, String originTypeName) { - RelationshipType foundRelationshipType = null; - if (originTypeName.split("\\.").length > 1) { - originTypeName = originTypeName.split("\\.")[1]; - } - for (RelationshipType relationshipType : relTypes) { - // Is origin type leftward or righward - boolean isLeft = false; - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType)) { - isLeft = true; - } - if (isLeft) { - // Validate typeName reference - if (!relationshipType.getLeftwardType().equalsIgnoreCase(originTypeName)) { - continue; - } - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) && - relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) { - foundRelationshipType = relationshipType; - } - } else { - if (!relationshipType.getRightwardType().equalsIgnoreCase(originTypeName)) { - continue; - } - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) && - relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) { - foundRelationshipType = relationshipType; - } - } - } - return foundRelationshipType; - } - + * @param targetType entity type of target. + * @param originType entity type of origin referer. + * @return null or matched Relationship Type. + */ + public static RelationshipType matchRelationshipType(List relTypes, String targetType, + String originType, String originTypeName) { + RelationshipType foundRelationshipType = null; + if (originTypeName.split("\\.").length > 1) { + originTypeName = originTypeName.split("\\.")[1]; + } + for (RelationshipType relationshipType : relTypes) { + // Is origin type leftward or righward + boolean isLeft = false; + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType)) { + isLeft = true; + } + if (isLeft) { + // Validate typeName reference + if (!relationshipType.getLeftwardType().equalsIgnoreCase(originTypeName)) { + continue; + } + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) + && relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) { + foundRelationshipType = relationshipType; + } + } else { + if (!relationshipType.getRightwardType().equalsIgnoreCase(originTypeName)) { + continue; + } + if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) + && relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) { + foundRelationshipType = relationshipType; + } + } + } + return foundRelationshipType; + } + } From 127e427bbe1eb99bef0a5ca4b35d8b5c53c58526 Mon Sep 17 00:00:00 2001 From: tysonlt Date: Wed, 25 Aug 2021 11:45:20 +1000 Subject: [PATCH 08/38] Changes requested in PR 3322 --- .../dspace/app/itemimport/ItemImportCLITool.java | 2 +- .../org/dspace/app/util/RelationshipUtils.java | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java index 07c9eab8d9..31f74e89db 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java @@ -94,7 +94,7 @@ public class ItemImportCLITool { options.addOption("R", "resume", false, "resume a failed import (add only)"); options.addOption("q", "quiet", false, "don't display metadata"); - options.addOption("l", "relationships", false, "process relationships manifest"); + options.addOption("l", "relationships", false, "process relationships manifest (add only)"); options.addOption("h", "help", false, "help"); diff --git a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java index 8a8ac00c7c..8df14c7d6d 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java +++ b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java @@ -17,11 +17,19 @@ public class RelationshipUtils { } /** - * Matches two Entity types to a Relationship Type from a set of Relationship Types. + * Matches two Entity types to a Relationship Type from a set of Relationship Types. * - * @param relTypes set of Relationship Types. - * @param targetType entity type of target. - * @param originType entity type of origin referer. + * Given a list of Relationship Types, this method will find a Relationship Type that + * is configured between the originType and the targetType, with the matching originTypeName. + * It will match a relationship between these two entities in either direction (eg leftward + * or rightward). + * + * Example: originType = Author, targetType = Publication, originTypeName = isAuthorOfPublication. + * + * @param relTypes set of Relationship Types in which to find a match. + * @param targetType entity type of target (eg. Publication). + * @param originType entity type of origin referer (eg. Author). + * @param originTypeName the name of the relationship (eg. isAuthorOfPublication) * @return null or matched Relationship Type. */ public static RelationshipType matchRelationshipType(List relTypes, String targetType, From 3512318ce176a1b73769f71dbb424856d5338165 Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Fri, 3 Sep 2021 17:06:31 +1000 Subject: [PATCH 09/38] fix checkstyle violations --- .../src/main/java/org/dspace/app/util/RelationshipUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java index 8df14c7d6d..c63d2fdfdf 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java +++ b/dspace-api/src/main/java/org/dspace/app/util/RelationshipUtils.java @@ -19,12 +19,12 @@ public class RelationshipUtils { /** * Matches two Entity types to a Relationship Type from a set of Relationship Types. * - * Given a list of Relationship Types, this method will find a Relationship Type that + * Given a list of Relationship Types, this method will find a Relationship Type that * is configured between the originType and the targetType, with the matching originTypeName. * It will match a relationship between these two entities in either direction (eg leftward * or rightward). * - * Example: originType = Author, targetType = Publication, originTypeName = isAuthorOfPublication. + * Example: originType = Author, targetType = Publication, originTypeName = isAuthorOfPublication. * * @param relTypes set of Relationship Types in which to find a match. * @param targetType entity type of target (eg. Publication). From 0fa5ef914f6a0922b31ce12cd622db01c6b54beb Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Fri, 3 Sep 2021 17:07:27 +1000 Subject: [PATCH 10/38] remove relationships option (always enabled) --- .../java/org/dspace/app/itemimport/ItemImportCLITool.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java index 31f74e89db..7cad97df31 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java @@ -94,7 +94,6 @@ public class ItemImportCLITool { options.addOption("R", "resume", false, "resume a failed import (add only)"); options.addOption("q", "quiet", false, "don't display metadata"); - options.addOption("l", "relationships", false, "process relationships manifest (add only)"); options.addOption("h", "help", false, "help"); @@ -108,7 +107,6 @@ public class ItemImportCLITool { String[] collections = null; // db ID or handles boolean isTest = false; boolean isResume = false; - boolean processRelationships = false; boolean useWorkflow = false; boolean useWorkflowSendEmail = false; boolean isQuiet = false; @@ -186,10 +184,6 @@ public class ItemImportCLITool { collections = line.getOptionValues('c'); } - if (line.hasOption('l')) { //relationships - processRelationships = true; - } - if (line.hasOption('R')) { isResume = true; System.out @@ -309,7 +303,6 @@ public class ItemImportCLITool { myloader.setResume(isResume); myloader.setUseWorkflow(useWorkflow); myloader.setUseWorkflowSendEmail(useWorkflowSendEmail); - myloader.setProcessRelationships(processRelationships); myloader.setQuiet(isQuiet); // create a context From db3d4ed374aa98977f961a6c9522bb882975f155 Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Fri, 3 Sep 2021 17:10:53 +1000 Subject: [PATCH 11/38] always process relationships, less noisy output --- .../app/itemimport/ItemImportServiceImpl.java | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index f2916bc8a7..9214fc0570 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -276,12 +276,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea if (skipItems.containsKey(dircontents[i])) { System.out.println("Skipping import of " + dircontents[i]); - if (processRelationships) { - //we still need the item in the map for relationship linking - String skippedHandle = skipItems.get(dircontents[i]); - Item skippedItem = (Item) handleService.resolveToObject(c, skippedHandle); - itemFolderMap.put(dircontents[i], skippedItem); - } + //we still need the item in the map for relationship linking + String skippedHandle = skipItems.get(dircontents[i]); + Item skippedItem = (Item) handleService.resolveToObject(c, skippedHandle); + itemFolderMap.put(dircontents[i], skippedItem); } else { List clist; @@ -305,19 +303,15 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template); - if (processRelationships) { - itemFolderMap.put(dircontents[i], item); - } + itemFolderMap.put(dircontents[i], item); c.uncacheEntity(item); System.out.println(i + " " + dircontents[i]); } } - if (processRelationships) { - //now that all items are imported, iterate again to link relationships - addRelationships(c, sourceDir); - } + //now that all items are imported, iterate again to link relationships + addRelationships(c, sourceDir); } finally { if (mapOut != null) { @@ -336,16 +330,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea */ protected void addRelationships(Context c, String sourceDir) throws Exception { - System.out.println("Linking relationships"); - for (Map.Entry itemEntry : itemFolderMap.entrySet()) { String folderName = itemEntry.getKey(); String path = sourceDir + File.separatorChar + folderName; Item item = itemEntry.getValue(); - System.out.println("Adding relationships from directory " + folderName); - //look for a 'relationship' manifest Map> relationships = processRelationshipFile(path, "relationships"); if (!relationships.isEmpty()) { @@ -500,8 +490,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea } } - } else { - System.out.println("\tNo relationships file found."); } return result; From ad0c19230d541773dc5e2cbc117850e590d6585b Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Fri, 3 Sep 2021 17:11:47 +1000 Subject: [PATCH 12/38] Abstract relationship lookup into RelationshipUtils --- .../dspace/app/bulkedit/MetadataImport.java | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java index 0db0cc45be..3443f7199d 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java @@ -25,6 +25,7 @@ import javax.annotation.Nullable; import org.apache.commons.cli.ParseException; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; +import org.dspace.app.util.RelationshipUtils; import org.dspace.authority.AuthorityValue; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; @@ -1793,36 +1794,7 @@ public class MetadataImport extends DSpaceRunnable relTypes, String targetType, String originType, String originTypeName) { - RelationshipType foundRelationshipType = null; - if (originTypeName.split("\\.").length > 1) { - originTypeName = originTypeName.split("\\.")[1]; - } - for (RelationshipType relationshipType : relTypes) { - // Is origin type leftward or righward - boolean isLeft = false; - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType)) { - isLeft = true; - } - if (isLeft) { - // Validate typeName reference - if (!relationshipType.getLeftwardType().equalsIgnoreCase(originTypeName)) { - continue; - } - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) && - relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) { - foundRelationshipType = relationshipType; - } - } else { - if (!relationshipType.getRightwardType().equalsIgnoreCase(originTypeName)) { - continue; - } - if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) && - relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) { - foundRelationshipType = relationshipType; - } - } - } - return foundRelationshipType; + return RelationshipUtils.matchRelationshipType(relTypes, targetType, originType, originTypeName); } } From 72fab650121dbfdbee5c871c43e70ab8ddd721ee Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 12 Jul 2021 12:25:34 -0400 Subject: [PATCH 13/38] w2p-80200 Retain UUIDs of DSpace objects when using packager --- .../content/CheckExistingUUIDGenerator.java | 33 +++++++++++++++ .../java/org/dspace/content/Collection.java | 4 ++ .../dspace/content/CollectionServiceImpl.java | 30 ++++++++++---- .../java/org/dspace/content/Community.java | 5 +++ .../dspace/content/CommunityServiceImpl.java | 39 ++++++++++++++---- .../java/org/dspace/content/DSpaceObject.java | 10 ++++- .../main/java/org/dspace/content/Item.java | 5 +++ .../org/dspace/content/ItemServiceImpl.java | 41 +++++++++++++++++++ .../content/WorkspaceItemServiceImpl.java | 14 ++++++- .../packager/AbstractMETSDisseminator.java | 3 -- .../packager/AbstractMETSIngester.java | 23 ++++++++++- .../dspace/content/packager/PackageUtils.java | 40 +++++++++++++++--- .../content/service/CollectionService.java | 22 ++++++++-- .../content/service/CommunityService.java | 29 +++++++++++++ .../dspace/content/service/ItemService.java | 14 +++++++ .../content/service/WorkspaceItemService.java | 17 ++++++++ 16 files changed, 295 insertions(+), 34 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java diff --git a/dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java b/dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java new file mode 100644 index 0000000000..c9ed9c1c58 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java @@ -0,0 +1,33 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.content; + +import java.io.Serializable; +import java.util.UUID; + +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.UUIDGenerator; + +/** + * Allows DSpaceObjects to provide a pre-determined UUID + * + * @author April Herron + */ +public class CheckExistingUUIDGenerator extends UUIDGenerator { + + @Override + public Serializable generate(SharedSessionContractImplementor session, Object object) { + if (object instanceof DSpaceObject) { + UUID uuid = ((DSpaceObject) object).getPredefinedUUID(); + if (uuid != null) { + return uuid; + } + } + return super.generate(session, object); + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java index 0658cc2d93..b826487083 100644 --- a/dspace-api/src/main/java/org/dspace/content/Collection.java +++ b/dspace-api/src/main/java/org/dspace/content/Collection.java @@ -14,6 +14,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import javax.annotation.Nonnull; import javax.persistence.Cacheable; import javax.persistence.CascadeType; @@ -103,6 +104,9 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor protected Collection() { } + protected Collection(UUID uuid) { + this.predefinedUUID = uuid; + } @Override public String getName() { diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java index 96ba571803..b652fa9b3f 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java @@ -129,12 +129,23 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public Collection create(Context context, Community community, String handle) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { + return create(context, community, handle, null); + } + + @Override + public Collection create(Context context, Community community, + String handle, UUID uuid) throws SQLException, AuthorizeException { if (community == null) { throw new IllegalArgumentException("Community cannot be null when creating a new collection."); } - Collection newCollection = collectionDAO.create(context, new Collection()); + Collection newCollection; + if (uuid != null) { + newCollection = collectionDAO.create(context, new Collection(uuid)); + } else { + newCollection = collectionDAO.create(context, new Collection()); + } //Add our newly created collection to our community, authorization checks occur in THIS method communityService.addCollection(context, community, newCollection); @@ -146,9 +157,10 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i authorizeService.createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.READ, null); // now create the default policies for submitted items authorizeService - .createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_ITEM_READ, null); + .createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_ITEM_READ, null); authorizeService - .createResourcePolicy(context, newCollection, anonymousGroup, null, Constants.DEFAULT_BITSTREAM_READ, null); + .createResourcePolicy(context, newCollection, anonymousGroup, null, + Constants.DEFAULT_BITSTREAM_READ, null); collectionDAO.save(context, newCollection); @@ -164,12 +176,12 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i } context.addEvent(new Event(Event.CREATE, Constants.COLLECTION, - newCollection.getID(), newCollection.getHandle(), - getIdentifiers(context, newCollection))); + newCollection.getID(), newCollection.getHandle(), + getIdentifiers(context, newCollection))); log.info(LogHelper.getHeader(context, "create_collection", - "collection_id=" + newCollection.getID()) - + ",handle=" + newCollection.getHandle()); + "collection_id=" + newCollection.getID()) + + ",handle=" + newCollection.getHandle()); return newCollection; } @@ -951,7 +963,7 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i * Finds all Indexed Collections where the current user has submit rights. If the user is an Admin, * this is all Indexed Collections. Otherwise, it includes those collections where * an indexed "submit" policy lists either the eperson or one of the eperson's groups - * + * * @param context DSpace context * @param discoverQuery * @param community parent community, could be null diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java index 810caaf4fd..a1b0ec547d 100644 --- a/dspace-api/src/main/java/org/dspace/content/Community.java +++ b/dspace-api/src/main/java/org/dspace/content/Community.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.UUID; import javax.persistence.Cacheable; import javax.persistence.CascadeType; import javax.persistence.Column; @@ -96,6 +97,10 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport } + protected Community(UUID uuid) { + this.predefinedUUID = uuid; + } + void addSubCommunity(Community subCommunity) { subCommunities.add(subCommunity); setModified(); diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java index ac60e7788e..b61c33dab8 100644 --- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java @@ -86,13 +86,24 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public Community create(Community parent, Context context, String handle) throws SQLException, AuthorizeException { + return create(parent, context, handle, null); + } + + @Override + public Community create(Community parent, Context context, String handle, + UUID uuid) throws SQLException, AuthorizeException { if (!(authorizeService.isAdmin(context) || - (parent != null && authorizeService.authorizeActionBoolean(context, parent, Constants.ADD)))) { + (parent != null && authorizeService.authorizeActionBoolean(context, parent, Constants.ADD)))) { throw new AuthorizeException( - "Only administrators can create communities"); + "Only administrators can create communities"); } - Community newCommunity = communityDAO.create(context, new Community()); + Community newCommunity; + if (uuid != null) { + newCommunity = communityDAO.create(context, new Community(uuid)); + } else { + newCommunity = communityDAO.create(context, new Community()); + } if (parent != null) { parent.addSubCommunity(newCommunity); @@ -129,8 +140,8 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp } log.info(LogHelper.getHeader(context, "create_community", - "community_id=" + newCommunity.getID()) - + ",handle=" + newCommunity.getHandle()); + "community_id=" + newCommunity.getID()) + + ",handle=" + newCommunity.getHandle()); return newCommunity; } @@ -383,17 +394,29 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public Community createSubcommunity(Context context, Community parentCommunity) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { return createSubcommunity(context, parentCommunity, null); } + @Override public Community createSubcommunity(Context context, Community parentCommunity, String handle) - throws SQLException, AuthorizeException { + throws SQLException, AuthorizeException { + return createSubcommunity(context, parentCommunity, handle, null); + } + + @Override + public Community createSubcommunity(Context context, Community parentCommunity, String handle, + UUID uuid) throws SQLException, AuthorizeException { // Check authorisation authorizeService.authorizeAction(context, parentCommunity, Constants.ADD); - Community c = create(parentCommunity, context, handle); + Community c; + if (uuid != null) { + c = create(parentCommunity, context, handle, uuid); + } else { + c = create(parentCommunity, context, handle); + } addSubcommunity(context, parentCommunity, c); return c; diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java index b740a6b82d..9829fa9003 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java @@ -38,8 +38,8 @@ import org.hibernate.annotations.GenericGenerator; @Table(name = "dspaceobject") public abstract class DSpaceObject implements Serializable, ReloadableEntity { @Id - @GeneratedValue(generator = "system-uuid") - @GenericGenerator(name = "system-uuid", strategy = "uuid2") + @GeneratedValue(generator = "check-existing-uuid") + @GenericGenerator(name = "check-existing-uuid", strategy = "org.dspace.content.CheckExistingUUIDGenerator") @Column(name = "uuid", unique = true, nullable = false, insertable = true, updatable = false) protected java.util.UUID id; @@ -76,6 +76,12 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntity implements It return item; } + @Override + public Item create(Context context, WorkspaceItem workspaceItem, + UUID uuid) throws SQLException, AuthorizeException { + if (workspaceItem.getItem() != null) { + throw new IllegalArgumentException( + "Attempting to create an item for a workspace item that already contains an item"); + } + Item item = createItem(context, uuid); + workspaceItem.setItem(item); + + + log.info(LogManager.getHeader(context, "create_item", "item_id=" + + item.getID())); + + return item; + } + @Override public Item createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException { if (collection == null || collection.getTemplateItem() != null) { @@ -418,6 +435,30 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It return bitstreamList; } + protected Item createItem(Context context, UUID uuid) throws SQLException, AuthorizeException { + Item item; + if (uuid != null) { + item = itemDAO.create(context, new Item(uuid)); + } else { + item = itemDAO.create(context, new Item()); + } + // set discoverable to true (default) + item.setDiscoverable(true); + + // Call update to give the item a last modified date. OK this isn't + // amazingly efficient but creates don't happen that often. + context.turnOffAuthorisationSystem(); + update(context, item); + context.restoreAuthSystemState(); + + context.addEvent(new Event(Event.CREATE, Constants.ITEM, item.getID(), + null, getIdentifiers(context, item))); + + log.info(LogManager.getHeader(context, "create_item", "item_id=" + item.getID())); + + return item; + } + protected Item createItem(Context context) throws SQLException, AuthorizeException { Item item = itemDAO.create(context, new Item()); // set discoverable to true (default) diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java index 7675d298d6..d1a761268c 100644 --- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java @@ -12,6 +12,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.UUID; import org.apache.logging.log4j.Logger; import org.dspace.app.util.DCInputsReaderException; @@ -80,6 +81,12 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { @Override public WorkspaceItem create(Context context, Collection collection, boolean template) + throws AuthorizeException, SQLException { + return create(context, collection, null, template); + } + + @Override + public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template) throws AuthorizeException, SQLException { // Check the user has permission to ADD to the collection authorizeService.authorizeAction(context, collection, Constants.ADD); @@ -89,7 +96,12 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService { // Create an item - Item item = itemService.create(context, workspaceItem); + Item item; + if (uuid != null) { + item = itemService.create(context, workspaceItem, uuid); + } else { + item = itemService.create(context, workspaceItem); + } item.setSubmitter(context.getCurrentUser()); // Now create the policies for the submitter to modify item and contents diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java index 2f90dae354..471b9ba27c 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java @@ -777,9 +777,6 @@ public abstract class AbstractMETSDisseminator Mets mets = new Mets(); String identifier = "DB-ID-" + dso.getID(); - if (dso.getHandle() != null) { - identifier = dso.getHandle().replace('/', '-'); - } // this ID should be globally unique (format: DSpace_[objType]_[handle with slash replaced with a dash]) mets.setID("DSpace_" + Constants.typeText[dso.getType()] + "_" + identifier); diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java index 67e20581ef..9a7fffdec5 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java @@ -16,6 +16,7 @@ import java.net.URLConnection; import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -409,6 +410,7 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester { // get handle from manifest handle = getObjectHandle(manifest); } + UUID uuid = getObjectID(manifest); // -- Step 2 -- // Create our DSpace Object based on info parsed from manifest, and @@ -416,7 +418,7 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester { DSpaceObject dso; try { dso = PackageUtils.createDSpaceObject(context, parent, - type, handle, params); + type, handle, uuid, params); } catch (SQLException sqle) { throw new PackageValidationException("Exception while ingesting " + pkgFile.getPath(), sqle); @@ -727,7 +729,6 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester { // retrieve path/name of file in manifest String path = METSManifest.getFileName(mfile); - // extract the file input stream from package (or retrieve // externally, if it is an externally referenced file) InputStream fileStream = getFileInputStream(pkgFile, params, path); @@ -1506,4 +1507,22 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester { */ public abstract String getConfigurationName(); + public UUID getObjectID(METSManifest manifest) + throws PackageValidationException { + Element mets = manifest.getMets(); + String idStr = mets.getAttributeValue("ID"); + if (idStr == null || idStr.length() == 0) { + throw new PackageValidationException("Manifest is missing the required mets@ID attribute."); + } + if (idStr.contains("DB-ID-")) { + idStr = idStr.substring(idStr.lastIndexOf("DB-ID-") + 6, idStr.length()); + } + try { + return UUID.fromString(idStr); + } catch (IllegalArgumentException ignored) { + //do nothing + } + return null; + } + } diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java index c127b48af9..9e7d870076 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -447,6 +448,7 @@ public class PackageUtils { * @param parent Parent Object * @param type Type of new Object * @param handle Handle of new Object (may be null) + * @param uuid * @param params Properties-style list of options (interpreted by each packager). * @return newly created DSpace Object (or null) * @throws AuthorizeException if authorization error @@ -454,29 +456,55 @@ public class PackageUtils { * @throws IOException if IO error */ public static DSpaceObject createDSpaceObject(Context context, DSpaceObject parent, int type, String handle, - PackageParameters params) + UUID uuid, PackageParameters params) throws AuthorizeException, SQLException, IOException { DSpaceObject dso = null; switch (type) { case Constants.COLLECTION: - dso = collectionService.create(context, (Community) parent, handle); + Collection collection = collectionService.find(context, uuid); + if (collection != null) { + dso = collectionService.create(context, (Community) parent, handle); + } else { + dso = collectionService.create(context, (Community) parent, handle, uuid); + + } return dso; case Constants.COMMUNITY: // top-level community? if (parent == null || parent.getType() == Constants.SITE) { - dso = communityService.create(null, context, handle); + Community community = communityService.find(context, uuid); + if (community != null) { + dso = communityService.create(null, context, handle); + } else { + dso = communityService.create(null, context, handle, uuid); + } } else { - dso = communityService.createSubcommunity(context, ((Community) parent), handle); + Community community = communityService.find(context, uuid); + if (community != null) { + dso = communityService.createSubcommunity(context, ((Community) parent), handle); + } else { + dso = communityService.createSubcommunity(context, ((Community) parent), handle, uuid); + } } return dso; case Constants.ITEM: //Initialize a WorkspaceItem //(Note: Handle is not set until item is finished) - WorkspaceItem wsi = workspaceItemService - .create(context, (Collection) parent, params.useCollectionTemplate()); + Item item = itemService.find(context, uuid); + if (item != null) { + return item; + } + + WorkspaceItem wsi = null; + if (!params.replaceModeEnabled()) { + wsi = workspaceItemService.create(context, (Collection)parent, params.useCollectionTemplate()); + } else { + wsi = workspaceItemService.create(context, (Collection)parent, + uuid, params.useCollectionTemplate()); + } // Please note that we are returning an Item which is *NOT* yet in the Archive, // and doesn't yet have a handle assigned. diff --git a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java index 67d45939d5..2580e74b99 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java @@ -12,6 +12,7 @@ import java.io.InputStream; import java.sql.SQLException; import java.util.List; import java.util.Map; +import java.util.UUID; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; @@ -60,6 +61,21 @@ public interface CollectionService public Collection create(Context context, Community community, String handle) throws SQLException, AuthorizeException; + /** + * Create a new collection with the supplied handle and ID. + * Once created the collection is added to the given community + * + * @param context DSpace context object + * @param community DSpace Community (parent) + * @param handle the pre-determined Handle to assign to the new collection + * @param uuid the pre-determined UUID to assign to the new collection + * @return the newly created collection + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public Collection create(Context context, Community community, String handle, UUID uuid) throws SQLException, + AuthorizeException; + /** * Get all collections in the system. These are alphabetically sorted by * collection name. @@ -308,7 +324,7 @@ public interface CollectionService throws java.sql.SQLException; /** - * + * * @param context DSpace Context * @param group EPerson Group * @return the collection, if any, that has the specified group as administrators or submitters @@ -349,7 +365,7 @@ public interface CollectionService * NOTE: for better performance, this method retrieves its results from an * index (cache) and does not query the database directly. * This means that results may be stale or outdated until DS-4524 is resolved" - * + * * @param q limit the returned collection to those with metadata values matching the query terms. * The terms are used to make also a prefix query on SOLR so it can be used to implement * an autosuggest feature over the collection name @@ -369,7 +385,7 @@ public interface CollectionService * NOTE: for better performance, this method retrieves its results from an index (cache) * and does not query the database directly. * This means that results may be stale or outdated until DS-4524 is resolved." - * + * * @param q limit the returned collection to those with metadata values matching the query terms. * The terms are used to make also a prefix query on SOLR so it can be used to implement * an autosuggest feature over the collection name diff --git a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java index 54512bb9f5..e7b6212665 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.List; +import java.util.UUID; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; @@ -53,6 +54,20 @@ public interface CommunityService extends DSpaceObjectService, DSpace public Community create(Community parent, Context context, String handle) throws SQLException, AuthorizeException; + /** + * Create a new top-level community, with a new ID. + * + * @param parent parent community + * @param context DSpace context object + * @param handle the pre-determined Handle to assign to the new community + * @param uuid the pre-determined uuid to assign to the new community + * @return the newly created community + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public Community create(Community parent, Context context, + String handle, UUID uuid) throws SQLException, AuthorizeException; + /** * Get a list of all communities in the system. These are alphabetically @@ -202,6 +217,20 @@ public interface CommunityService extends DSpaceObjectService, DSpace public Community createSubcommunity(Context context, Community parentCommunity, String handle) throws SQLException, AuthorizeException; + /** + * Create a new sub-community within this community. + * + * @param context context + * @param handle the pre-determined Handle to assign to the new community + * @param parentCommunity parent community + * @param uuid the pre-determined UUID to assign to the new community + * @return the new community + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public Community createSubcommunity(Context context, Community parentCommunity, String handle, UUID uuid) + throws SQLException, AuthorizeException; + /** * Add an existing community as a subcommunity to the community * diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java index 2a38488f7a..3353eb9dec 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java @@ -55,6 +55,20 @@ public interface ItemService */ public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException; + /** + * Create a new item, with a provided ID. This method is not public, + * since items need to be created as workspace items. Authorisation is the + * responsibility of the caller. + * + * @param context DSpace context object + * @param workspaceItem in progress workspace item + * @param uuid the pre-determined UUID to assign to the new item + * @return the newly created item + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public Item create(Context context, WorkspaceItem workspaceItem, UUID uuid) throws SQLException, AuthorizeException; + /** * Create an empty template item for this collection. If one already exists, * no action is taken. Caution: Make sure you call update on diff --git a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java index 3ee381706c..8f572f6108 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.Map; +import java.util.UUID; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; @@ -55,6 +56,22 @@ public interface WorkspaceItemService extends InProgressSubmissionServicetrue, the workspace item starts as a copy + * of the collection's template item + * @return the newly created workspace item + * @throws SQLException if database error + * @throws AuthorizeException if authorization error + */ + public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template) + throws AuthorizeException, SQLException; + public WorkspaceItem create(Context c, WorkflowItem wfi) throws SQLException, AuthorizeException; From 80211961c0ecc6f5206f3e0483e47e17bf381265 Mon Sep 17 00:00:00 2001 From: Chris Wilper Date: Thu, 15 Jul 2021 14:32:16 -0400 Subject: [PATCH 14/38] w2p-80200 Begin IT for packager export/import with UUID support --- .../org/dspace/app/packager/PackagerIT.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java new file mode 100644 index 0000000000..12044cf941 --- /dev/null +++ b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -0,0 +1,64 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.packager; + +import java.io.File; + +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; +import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.ItemBuilder; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.service.ItemService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + + +// See CsvImportIT for other examples involving rels +public class PackagerIT extends AbstractEntityIntegrationTest { + + @Autowired + private ItemService itemService; + + @Test + public void packagerExportUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + // Create a new Publication (which is an Article) + Item article = ItemBuilder.createItem(context, col1) + .withTitle("Article") + .withIssueDate("2017-10-17") + .withEntityType("Publication") + .build(); + + File tempFile = File.createTempFile("packagerExportTest", "zip"); + try { + performExportScript(article.getHandle(), tempFile); + // TODO: verify the file has the uuid in the right place + } finally { + tempFile.delete(); + } + } + + @Test + public void packagerImportUUIDTest() { + + } + + private void performExportScript(String handle, File outputFile) throws Exception { + runDSpaceScript("packager", "-d", "-e", "admin@email.com", "-i", handle, "aip", outputFile.getPath()); + } +} From f0ae18645da632026dd61f647132542cec9b4772 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Fri, 16 Jul 2021 09:41:03 -0400 Subject: [PATCH 15/38] Test file for export and import of packager --- .../org/dspace/app/packager/PackagerIT.java | 107 ++++++++++++++---- 1 file changed, 87 insertions(+), 20 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java index 12044cf941..3b08fa3e80 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -7,18 +7,30 @@ */ package org.dspace.app.packager; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import java.io.File; +import java.io.IOException; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import org.dspace.app.rest.test.AbstractEntityIntegrationTest; -import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; +import org.dspace.builder.CollectionBuilder; +import org.dspace.builder.CommunityBuilder; import org.dspace.builder.ItemBuilder; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; +import org.dspace.content.crosswalk.MetadataValidationException; +import org.dspace.content.packager.METSManifest; import org.dspace.content.service.ItemService; +import org.jdom.Element; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; - +import org.springframework.core.annotation.Order; // See CsvImportIT for other examples involving rels public class PackagerIT extends AbstractEntityIntegrationTest { @@ -27,38 +39,93 @@ public class PackagerIT extends AbstractEntityIntegrationTest { private ItemService itemService; @Test + @Order(1) public void packagerExportUUIDTest() throws Exception { context.turnOffAuthorisationSystem(); - parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); - Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); - Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Community child1 = null; + Collection col1 = null; + Item article = null; + createTemplate(child1, col1, article); - // Create a new Publication (which is an Article) - Item article = ItemBuilder.createItem(context, col1) - .withTitle("Article") - .withIssueDate("2017-10-17") - .withEntityType("Publication") - .build(); - - File tempFile = File.createTempFile("packagerExportTest", "zip"); + File tempFile = File.createTempFile("packagerExportTest", ".zip"); try { performExportScript(article.getHandle(), tempFile); - // TODO: verify the file has the uuid in the right place + assertTrue(tempFile.length() > 0); + String idStr = getID(tempFile); + assertEquals(idStr, article.getID().toString()); + } catch (Exception e) { + throw new Exception(e); } finally { tempFile.delete(); } } @Test - public void packagerImportUUIDTest() { + @Order(2) + public void packagerImportUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + Community child1 = null; + Collection col1 = null; + Item article = null; + createTemplate(child1, col1, article); + File tempFile = File.createTempFile("packagerExportTest", ".zip"); + try { + performExportScript(article.getHandle(), tempFile); + String idStr = getID(tempFile); + itemService.delete(context, article); + performImportScript(tempFile); + System.out.println(idStr); + Item item = itemService.find(context, UUID.fromString(idStr)); + assertNotNull(item); + } catch (Exception e) { + throw new Exception(e); + } finally { + tempFile.delete(); + } } + private void createTemplate(Community child1, Collection col1, Item article) { + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + // Create a new Publication (which is an Article) + article = ItemBuilder.createItem(context, col1) + .withTitle("Article") + .withIssueDate("2017-10-17") + .withEntityType("Publication") + .build(); + } + + private String getID(File tempFile) throws IOException, MetadataValidationException { + METSManifest manifest = null; + System.out.println(tempFile.getAbsolutePath()); + ZipFile zip = new ZipFile(tempFile); + ZipEntry manifestEntry = zip.getEntry(METSManifest.MANIFEST_FILE); + if (manifestEntry != null) { + // parse the manifest and sanity-check it. + manifest = METSManifest.create(zip.getInputStream(manifestEntry), + false, "AIP"); + } + Element mets = manifest.getMets(); + String idStr = mets.getAttributeValue("ID"); + if (idStr.contains("DB-ID-")) { + idStr = idStr.substring(idStr.lastIndexOf("DB-ID-") + 6, idStr.length()); + } + return idStr; + } + + private void performExportScript(String handle, File outputFile) throws Exception { - runDSpaceScript("packager", "-d", "-e", "admin@email.com", "-i", handle, "aip", outputFile.getPath()); + runDSpaceScript("packager", "-d", "-e", "admin@email.com", "-i", handle, "-t", "AIP", outputFile.getPath()); + } + + private void performImportScript(File outputFile) throws Exception { + runDSpaceScript("packager", "-r", "-f", "-u", "-e", "admin@email.com", "-t", "AIP", outputFile.getPath()); } } From cc63bbe02df9d5b28483e338335c49be37a71e8e Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Fri, 16 Jul 2021 09:53:21 -0400 Subject: [PATCH 16/38] quick fix for Item not being initialized --- .../src/test/java/org/dspace/app/packager/PackagerIT.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java index 3b08fa3e80..11e9462b85 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -45,7 +45,7 @@ public class PackagerIT extends AbstractEntityIntegrationTest { Community child1 = null; Collection col1 = null; Item article = null; - createTemplate(child1, col1, article); + article = createTemplate(child1, col1, article); File tempFile = File.createTempFile("packagerExportTest", ".zip"); try { @@ -67,7 +67,8 @@ public class PackagerIT extends AbstractEntityIntegrationTest { Community child1 = null; Collection col1 = null; Item article = null; - createTemplate(child1, col1, article); + article = createTemplate(child1, col1, article); + File tempFile = File.createTempFile("packagerExportTest", ".zip"); try { @@ -85,7 +86,7 @@ public class PackagerIT extends AbstractEntityIntegrationTest { } } - private void createTemplate(Community child1, Collection col1, Item article) { + private Item createTemplate(Community child1, Collection col1, Item article) { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") .build(); @@ -100,6 +101,7 @@ public class PackagerIT extends AbstractEntityIntegrationTest { .withIssueDate("2017-10-17") .withEntityType("Publication") .build(); + return article; } private String getID(File tempFile) throws IOException, MetadataValidationException { From 22c9b769508ec2890ca0728f55e3fcc080c04731 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Fri, 16 Jul 2021 16:20:38 -0400 Subject: [PATCH 17/38] move to dspace-api --- .../org/dspace/app/packager/PackagerIT.java | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) rename {dspace-server-webapp => dspace-api}/src/test/java/org/dspace/app/packager/PackagerIT.java (76%) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java similarity index 76% rename from dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java rename to dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 11e9462b85..432bc1547d 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -17,7 +17,7 @@ import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import org.dspace.app.rest.test.AbstractEntityIntegrationTest; +import org.dspace.AbstractIntegrationTestWithDatabase; import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; import org.dspace.builder.ItemBuilder; @@ -25,27 +25,21 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.crosswalk.MetadataValidationException; +import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.METSManifest; import org.dspace.content.service.ItemService; import org.jdom.Element; import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; // See CsvImportIT for other examples involving rels -public class PackagerIT extends AbstractEntityIntegrationTest { +public class PackagerIT extends AbstractIntegrationTestWithDatabase { - @Autowired - private ItemService itemService; + private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @Test - @Order(1) public void packagerExportUUIDTest() throws Exception { context.turnOffAuthorisationSystem(); - Community child1 = null; - Collection col1 = null; - Item article = null; - article = createTemplate(child1, col1, article); + Item article = createTemplate(); File tempFile = File.createTempFile("packagerExportTest", ".zip"); try { @@ -61,13 +55,9 @@ public class PackagerIT extends AbstractEntityIntegrationTest { } @Test - @Order(2) public void packagerImportUUIDTest() throws Exception { context.turnOffAuthorisationSystem(); - Community child1 = null; - Collection col1 = null; - Item article = null; - article = createTemplate(child1, col1, article); + Item article = createTemplate(); File tempFile = File.createTempFile("packagerExportTest", ".zip"); @@ -76,7 +66,6 @@ public class PackagerIT extends AbstractEntityIntegrationTest { String idStr = getID(tempFile); itemService.delete(context, article); performImportScript(tempFile); - System.out.println(idStr); Item item = itemService.find(context, UUID.fromString(idStr)); assertNotNull(item); } catch (Exception e) { @@ -86,27 +75,25 @@ public class PackagerIT extends AbstractEntityIntegrationTest { } } - private Item createTemplate(Community child1, Collection col1, Item article) { + private Item createTemplate() { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") .build(); - child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) .withName("Sub Community") .build(); - col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); // Create a new Publication (which is an Article) - article = ItemBuilder.createItem(context, col1) + return ItemBuilder.createItem(context, col1) .withTitle("Article") .withIssueDate("2017-10-17") .withEntityType("Publication") .build(); - return article; } private String getID(File tempFile) throws IOException, MetadataValidationException { METSManifest manifest = null; - System.out.println(tempFile.getAbsolutePath()); ZipFile zip = new ZipFile(tempFile); ZipEntry manifestEntry = zip.getEntry(METSManifest.MANIFEST_FILE); if (manifestEntry != null) { @@ -124,10 +111,12 @@ public class PackagerIT extends AbstractEntityIntegrationTest { private void performExportScript(String handle, File outputFile) throws Exception { - runDSpaceScript("packager", "-d", "-e", "admin@email.com", "-i", handle, "-t", "AIP", outputFile.getPath()); + runDSpaceScript("packager", "-d", "-e", "admin@email.com", "-i", handle, "-t", + "AIP", outputFile.getPath()); } private void performImportScript(File outputFile) throws Exception { - runDSpaceScript("packager", "-r", "-f", "-u", "-e", "admin@email.com", "-t", "AIP", outputFile.getPath()); + runDSpaceScript("packager", "-r", "-f", "-u", "-e", "admin@email.com", "-t", + "AIP", outputFile.getPath()); } } From b24da56ca2fd6ad515a0d65092bd813a4f83cc81 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 19 Jul 2021 11:20:10 -0400 Subject: [PATCH 18/38] remove left over comment --- dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 432bc1547d..3ae92730af 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -31,7 +31,6 @@ import org.dspace.content.service.ItemService; import org.jdom.Element; import org.junit.Test; -// See CsvImportIT for other examples involving rels public class PackagerIT extends AbstractIntegrationTestWithDatabase { private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); From cdeb22ed7beb7dd1086100ed76a6e4f436131003 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 19 Jul 2021 11:25:18 -0400 Subject: [PATCH 19/38] Make tests more concise and remove catch blocks --- .../org/dspace/app/packager/PackagerIT.java | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 3ae92730af..11fe4119e2 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -34,20 +34,21 @@ import org.junit.Test; public class PackagerIT extends AbstractIntegrationTestWithDatabase { private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + protected Community child1; + protected Collection col1; + protected Item article; + File tempFile; @Test public void packagerExportUUIDTest() throws Exception { context.turnOffAuthorisationSystem(); - Item article = createTemplate(); - - File tempFile = File.createTempFile("packagerExportTest", ".zip"); + createTemplate(); + createFiles(); try { performExportScript(article.getHandle(), tempFile); assertTrue(tempFile.length() > 0); - String idStr = getID(tempFile); + String idStr = getID(); assertEquals(idStr, article.getID().toString()); - } catch (Exception e) { - throw new Exception(e); } finally { tempFile.delete(); } @@ -56,42 +57,43 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { @Test public void packagerImportUUIDTest() throws Exception { context.turnOffAuthorisationSystem(); - Item article = createTemplate(); - - - File tempFile = File.createTempFile("packagerExportTest", ".zip"); + createTemplate(); + createFiles(); try { performExportScript(article.getHandle(), tempFile); - String idStr = getID(tempFile); + String idStr = getID(); itemService.delete(context, article); performImportScript(tempFile); Item item = itemService.find(context, UUID.fromString(idStr)); assertNotNull(item); - } catch (Exception e) { - throw new Exception(e); } finally { tempFile.delete(); } } - private Item createTemplate() { + protected void createTemplate() { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") .build(); - Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) .withName("Sub Community") .build(); - Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); // Create a new Publication (which is an Article) - return ItemBuilder.createItem(context, col1) + article = ItemBuilder.createItem(context, col1) .withTitle("Article") .withIssueDate("2017-10-17") .withEntityType("Publication") .build(); } - private String getID(File tempFile) throws IOException, MetadataValidationException { + protected void createFiles() throws IOException { + tempFile = File.createTempFile("packagerExportTest", ".zip"); + } + + private String getID() throws IOException, MetadataValidationException { + //this method gets the UUID from the mets file thats stored in the attribute element METSManifest manifest = null; ZipFile zip = new ZipFile(tempFile); ZipEntry manifestEntry = zip.getEntry(METSManifest.MANIFEST_FILE); From e1f798fd827d741b766d1eebe47a1d31ddd8f173 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 30 Aug 2021 14:38:25 -0400 Subject: [PATCH 20/38] w2p-80200 Add new tests for each dspace object, cleaned up java docs and authrorization inside of create --- .../java/org/dspace/content/Collection.java | 7 +++ .../java/org/dspace/content/Community.java | 6 ++ .../java/org/dspace/content/DSpaceObject.java | 7 ++- .../main/java/org/dspace/content/Item.java | 6 ++ .../org/dspace/content/ItemServiceImpl.java | 2 + ...ator.java => PredefinedUUIDGenerator.java} | 2 +- .../dspace/content/service/ItemService.java | 10 ++- .../org/dspace/app/packager/PackagerIT.java | 63 +++++++++++++++++++ dspace/modules/dspace-replicate | 1 + 9 files changed, 95 insertions(+), 9 deletions(-) rename dspace-api/src/main/java/org/dspace/content/{CheckExistingUUIDGenerator.java => PredefinedUUIDGenerator.java} (93%) create mode 160000 dspace/modules/dspace-replicate diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java index b826487083..ffec3b45cc 100644 --- a/dspace-api/src/main/java/org/dspace/content/Collection.java +++ b/dspace-api/src/main/java/org/dspace/content/Collection.java @@ -104,6 +104,13 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor protected Collection() { } + + /** + * Takes a pre-determined UUID to be passed to the object to allow for the + * restoration of previously defined UUID's. + * + * @param uuid Takes a uuid to be passed to the Pre-Defined UUID Generator + */ protected Collection(UUID uuid) { this.predefinedUUID = uuid; } diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java index a1b0ec547d..d05ab50d93 100644 --- a/dspace-api/src/main/java/org/dspace/content/Community.java +++ b/dspace-api/src/main/java/org/dspace/content/Community.java @@ -97,6 +97,12 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport } + /** + * Takes a pre-determined UUID to be passed to the object to allow for the + * restoration of previously defined UUID's. + * + * @param uuid Takes a uuid to be passed to the Pre-Defined UUID Generator + */ protected Community(UUID uuid) { this.predefinedUUID = uuid; } diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java index 9829fa9003..fccf51af01 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObject.java @@ -38,8 +38,8 @@ import org.hibernate.annotations.GenericGenerator; @Table(name = "dspaceobject") public abstract class DSpaceObject implements Serializable, ReloadableEntity { @Id - @GeneratedValue(generator = "check-existing-uuid") - @GenericGenerator(name = "check-existing-uuid", strategy = "org.dspace.content.CheckExistingUUIDGenerator") + @GeneratedValue(generator = "predefined-uuid") + @GenericGenerator(name = "predefined-uuid", strategy = "org.dspace.content.PredefinedUUIDGenerator") @Column(name = "uuid", unique = true, nullable = false, insertable = true, updatable = false) protected java.util.UUID id; @@ -76,6 +76,9 @@ public abstract class DSpaceObject implements Serializable, ReloadableEntity implements It @Override public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException { + authorizeService.authorizeAction(context, workspaceItem.getCollection(), Constants.ADD); if (workspaceItem.getItem() != null) { throw new IllegalArgumentException( "Attempting to create an item for a workspace item that already contains an item"); @@ -193,6 +194,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Override public Item create(Context context, WorkspaceItem workspaceItem, UUID uuid) throws SQLException, AuthorizeException { + authorizeService.authorizeAction(context, workspaceItem.getCollection(), Constants.ADD); if (workspaceItem.getItem() != null) { throw new IllegalArgumentException( "Attempting to create an item for a workspace item that already contains an item"); diff --git a/dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java b/dspace-api/src/main/java/org/dspace/content/PredefinedUUIDGenerator.java similarity index 93% rename from dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java rename to dspace-api/src/main/java/org/dspace/content/PredefinedUUIDGenerator.java index c9ed9c1c58..aa4a8ea542 100644 --- a/dspace-api/src/main/java/org/dspace/content/CheckExistingUUIDGenerator.java +++ b/dspace-api/src/main/java/org/dspace/content/PredefinedUUIDGenerator.java @@ -18,7 +18,7 @@ import org.hibernate.id.UUIDGenerator; * * @author April Herron */ -public class CheckExistingUUIDGenerator extends UUIDGenerator { +public class PredefinedUUIDGenerator extends UUIDGenerator { @Override public Serializable generate(SharedSessionContractImplementor session, Object object) { diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java index 3353eb9dec..167b9dbb79 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java @@ -43,9 +43,8 @@ public interface ItemService public Thumbnail getThumbnail(Context context, Item item, boolean requireOriginal) throws SQLException; /** - * Create a new item, with a new internal ID. This method is not public, - * since items need to be created as workspace items. Authorisation is the - * responsibility of the caller. + * Create a new item, with a new internal ID. Authorization is done + * inside of this method. * * @param context DSpace context object * @param workspaceItem in progress workspace item @@ -56,9 +55,8 @@ public interface ItemService public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException; /** - * Create a new item, with a provided ID. This method is not public, - * since items need to be created as workspace items. Authorisation is the - * responsibility of the caller. + * Create a new item, with a provided ID. Authorisation is done + * inside of this method. * * @param context DSpace context object * @param workspaceItem in progress workspace item diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 11fe4119e2..f09b30fb31 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -13,10 +13,12 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; +import java.util.Iterator; import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import com.google.common.collect.Iterators; import org.dspace.AbstractIntegrationTestWithDatabase; import org.dspace.builder.CollectionBuilder; import org.dspace.builder.CommunityBuilder; @@ -27,13 +29,20 @@ import org.dspace.content.Item; import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.METSManifest; +import org.dspace.content.service.CollectionService; +import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; import org.jdom.Element; import org.junit.Test; public class PackagerIT extends AbstractIntegrationTestWithDatabase { private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); + private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); + private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); + protected ConfigurationService configService = DSpaceServicesFactory.getInstance().getConfigurationService(); protected Community child1; protected Collection col1; protected Item article; @@ -60,6 +69,7 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { createTemplate(); createFiles(); try { + //Item performExportScript(article.getHandle(), tempFile); String idStr = getID(); itemService.delete(context, article); @@ -71,6 +81,59 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { } } + @Test + public void packagerImportColUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + createTemplate(); + createFiles(); + configService.setProperty("upload.temp.dir",tempFile.getParent()); + try { + performExportScript(col1.getHandle(), tempFile); + String idStr = getID(); + collectionService.delete(context, col1); + performImportScript(tempFile); + Collection collection = collectionService.find(context, UUID.fromString(idStr)); + assertNotNull(collection); + } finally { + tempFile.delete(); + } + } + + @Test + public void packagerImportComUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + createTemplate(); + createFiles(); + configService.setProperty("upload.temp.dir",tempFile.getParent()); + try { + //Community + performExportScript(child1.getHandle(), tempFile); + String idStr = getID(); + communityService.delete(context, child1); + performImportScript(tempFile); + Community community = communityService.find(context, UUID.fromString(idStr)); + assertNotNull(community); + } finally { + tempFile.delete(); + } + } + + @Test + public void packagerUUIDAlreadyExistTest() throws Exception { + context.turnOffAuthorisationSystem(); + createTemplate(); + createFiles(); + try { + //Item should be overwritten if UUID already Exists + performExportScript(article.getHandle(), tempFile); + performImportScript(tempFile); + Iterator items = itemService.findByCollection(context, col1); + assertEquals(1, Iterators.size(items)); + } finally { + tempFile.delete(); + } + } + protected void createTemplate() { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") diff --git a/dspace/modules/dspace-replicate b/dspace/modules/dspace-replicate new file mode 160000 index 0000000000..5c19e3e515 --- /dev/null +++ b/dspace/modules/dspace-replicate @@ -0,0 +1 @@ +Subproject commit 5c19e3e515960d714ead13a2013103135ea0bf3a From 85cbd4b31f4d8b32d4dbb07e775a54cc152c23b5 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 30 Aug 2021 14:42:56 -0400 Subject: [PATCH 21/38] w2p-80200 submodule accidentally pushed --- dspace/modules/dspace-replicate | 1 - 1 file changed, 1 deletion(-) delete mode 160000 dspace/modules/dspace-replicate diff --git a/dspace/modules/dspace-replicate b/dspace/modules/dspace-replicate deleted file mode 160000 index 5c19e3e515..0000000000 --- a/dspace/modules/dspace-replicate +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5c19e3e515960d714ead13a2013103135ea0bf3a From 829fc7d112b6fd91fac73faeab682ef6ed64b184 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Tue, 7 Sep 2021 16:33:32 -0400 Subject: [PATCH 22/38] w2p-80200 Tests for no force export and fix to spy on authorize service --- .../dspace/content/CommunityServiceImpl.java | 7 ++-- .../org/dspace/content/ItemServiceImpl.java | 26 ++++++-------- .../org/dspace/app/packager/PackagerIT.java | 36 +++++++++++++++++++ .../org/dspace/content/WorkspaceItemTest.java | 11 +++++- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java index b61c33dab8..53cfb34282 100644 --- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java @@ -412,11 +412,8 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp authorizeService.authorizeAction(context, parentCommunity, Constants.ADD); Community c; - if (uuid != null) { - c = create(parentCommunity, context, handle, uuid); - } else { - c = create(parentCommunity, context, handle); - } + c = create(parentCommunity, context, handle, uuid); + addSubcommunity(context, parentCommunity, c); return c; diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index b435df4d4e..2244d4b149 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -176,34 +176,28 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Override public Item create(Context context, WorkspaceItem workspaceItem) throws SQLException, AuthorizeException { - authorizeService.authorizeAction(context, workspaceItem.getCollection(), Constants.ADD); - if (workspaceItem.getItem() != null) { - throw new IllegalArgumentException( - "Attempting to create an item for a workspace item that already contains an item"); - } - Item item = createItem(context); - workspaceItem.setItem(item); - - - log.info(LogHelper.getHeader(context, "create_item", "item_id=" - + item.getID())); - - return item; + return create(context, workspaceItem, null); } @Override public Item create(Context context, WorkspaceItem workspaceItem, UUID uuid) throws SQLException, AuthorizeException { - authorizeService.authorizeAction(context, workspaceItem.getCollection(), Constants.ADD); + Collection collection = workspaceItem.getCollection(); + authorizeService.authorizeAction(context, collection, Constants.ADD); if (workspaceItem.getItem() != null) { throw new IllegalArgumentException( "Attempting to create an item for a workspace item that already contains an item"); } - Item item = createItem(context, uuid); + Item item = null; + if (uuid != null) { + item = createItem(context, uuid); + } else { + item = createItem(context); + } workspaceItem.setItem(item); - log.info(LogManager.getHeader(context, "create_item", "item_id=" + log.info(LogHelper.getHeader(context, "create_item", "item_id=" + item.getID())); return item; diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index f09b30fb31..037404ef40 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -8,7 +8,9 @@ package org.dspace.app.packager; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; @@ -26,12 +28,15 @@ import org.dspace.builder.ItemBuilder; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.MetadataValidationException; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.METSManifest; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; +import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; +import org.dspace.content.service.WorkspaceItemService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.jdom.Element; @@ -42,6 +47,9 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); + private WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + protected static final InstallItemService installItemService = ContentServiceFactory.getInstance() + .getInstallItemService(); protected ConfigurationService configService = DSpaceServicesFactory.getInstance().getConfigurationService(); protected Community child1; protected Collection col1; @@ -134,6 +142,29 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { } } + @Test + public void packagerUUIDAlreadyExistWithoutForceTest() throws Exception { + context.turnOffAuthorisationSystem(); + createTemplate(); + createFiles(); + try { + //should fail to restore the item because the uuid already exists. + performExportScript(article.getHandle(), tempFile); + UUID id = article.getID(); + itemService.delete(context, article); + WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false); + installItemService.installItem(context, workspaceItem, "123456789/100"); + performImportNoForceScript(tempFile); + Iterator items = itemService.findByCollection(context, col1); + Item testItem = items.next(); + assertFalse(items.hasNext()); //check to make sure there is only 1 item + assertSame("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as + // it would have the old handle. + } finally { + tempFile.delete(); + } + } + protected void createTemplate() { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") @@ -179,6 +210,11 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { "AIP", outputFile.getPath()); } + private void performImportNoForceScript(File outputFile) throws Exception { + runDSpaceScript("packager", "-r", "-u", "-e", "admin@email.com", "-t", + "AIP", outputFile.getPath()); + } + private void performImportScript(File outputFile) throws Exception { runDSpaceScript("packager", "-r", "-f", "-u", "-e", "admin@email.com", "-t", "AIP", outputFile.getPath()); diff --git a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java index 609768bf67..43afbead70 100644 --- a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java @@ -14,6 +14,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; @@ -33,12 +35,15 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.ItemService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Constants; +import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; import org.springframework.test.util.ReflectionTestUtils; /** @@ -46,6 +51,7 @@ import org.springframework.test.util.ReflectionTestUtils; * * @author pvillega */ +@RunWith(MockitoJUnitRunner.class) public class WorkspaceItemTest extends AbstractUnitTest { /** @@ -98,6 +104,7 @@ public class WorkspaceItemTest extends AbstractUnitTest { // "Wire" our spy to be used by the current loaded object services // (To ensure these services use the spy instead of the real service) ReflectionTestUtils.setField(workspaceItemService, "authorizeService", authorizeServiceSpy); + ReflectionTestUtils.setField(itemService, "authorizeService", authorizeServiceSpy); ReflectionTestUtils.setField(collectionService, "authorizeService", authorizeServiceSpy); ReflectionTestUtils.setField(communityService, "authorizeService", authorizeServiceSpy); } catch (AuthorizeException ex) { @@ -158,7 +165,9 @@ public class WorkspaceItemTest extends AbstractUnitTest { @Test public void testCreateAuth() throws Exception { // Allow Collection ADD perms - doNothing().when(authorizeServiceSpy).authorizeAction(context, collection, Constants.ADD); + //doNothing().when(authorizeServiceSpy).authorizeAction(context, collection, Constants.ADD); + doNothing().when(authorizeServiceSpy).authorizeAction(any(Context.class), + any(Collection.class), eq(Constants.ADD)); boolean template; WorkspaceItem created; From fcf077c685b819d8a7e9ac7abef0e54559791732 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Tue, 7 Sep 2021 16:42:28 -0400 Subject: [PATCH 23/38] w2p-80200 Remove unecessary comment --- .../src/test/java/org/dspace/content/WorkspaceItemTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java index 43afbead70..d018a15f97 100644 --- a/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/WorkspaceItemTest.java @@ -165,7 +165,6 @@ public class WorkspaceItemTest extends AbstractUnitTest { @Test public void testCreateAuth() throws Exception { // Allow Collection ADD perms - //doNothing().when(authorizeServiceSpy).authorizeAction(context, collection, Constants.ADD); doNothing().when(authorizeServiceSpy).authorizeAction(any(Context.class), any(Collection.class), eq(Constants.ADD)); From ad148b529e0964fa8de9229d8f4e2186e608bbba Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Mon, 13 Sep 2021 14:40:38 -0400 Subject: [PATCH 24/38] w2p-80200 Added auth comment also run tests again --- .../src/test/java/org/dspace/app/packager/PackagerIT.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 037404ef40..f1bf8635bd 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -42,6 +42,11 @@ import org.dspace.services.factory.DSpaceServicesFactory; import org.jdom.Element; import org.junit.Test; +/** + * Basic integration testing for the Packager restore feature + * + * @author Nathan Buckingham + */ public class PackagerIT extends AbstractIntegrationTestWithDatabase { private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); From 2fd4625a7e8d0e3516476e1aaf1a09fc397618dd Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Tue, 14 Sep 2021 14:13:38 -0400 Subject: [PATCH 25/38] Rebased main --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 2 +- .../src/test/java/org/dspace/app/packager/PackagerIT.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java index 2244d4b149..0ce132d77b 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -450,7 +450,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It context.addEvent(new Event(Event.CREATE, Constants.ITEM, item.getID(), null, getIdentifiers(context, item))); - log.info(LogManager.getHeader(context, "create_item", "item_id=" + item.getID())); + log.info(LogHelper.getHeader(context, "create_item", "item_id=" + item.getID())); return item; } diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index f1bf8635bd..262fac3ab9 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -10,7 +10,6 @@ package org.dspace.app.packager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; @@ -163,7 +162,7 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { Iterator items = itemService.findByCollection(context, col1); Item testItem = items.next(); assertFalse(items.hasNext()); //check to make sure there is only 1 item - assertSame("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as + assertEquals("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as // it would have the old handle. } finally { tempFile.delete(); From a5103dbd39fe3b7163aa7587aaea74da7ee5d695 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Thu, 16 Sep 2021 10:00:36 -0400 Subject: [PATCH 26/38] Create setup and destory to cleanup items from test file --- .../org/dspace/app/packager/PackagerIT.java | 208 ++++++++---------- 1 file changed, 97 insertions(+), 111 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index 262fac3ab9..ff79ae8d39 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -14,6 +14,7 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; +import java.sql.SQLException; import java.util.Iterator; import java.util.UUID; import java.util.zip.ZipEntry; @@ -39,6 +40,8 @@ import org.dspace.content.service.WorkspaceItemService; import org.dspace.services.ConfigurationService; import org.dspace.services.factory.DSpaceServicesFactory; import org.jdom.Element; +import org.junit.After; +import org.junit.Before; import org.junit.Test; /** @@ -60,116 +63,9 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { protected Item article; File tempFile; - @Test - public void packagerExportUUIDTest() throws Exception { + @Before + public void setup() throws IOException { context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - try { - performExportScript(article.getHandle(), tempFile); - assertTrue(tempFile.length() > 0); - String idStr = getID(); - assertEquals(idStr, article.getID().toString()); - } finally { - tempFile.delete(); - } - } - - @Test - public void packagerImportUUIDTest() throws Exception { - context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - try { - //Item - performExportScript(article.getHandle(), tempFile); - String idStr = getID(); - itemService.delete(context, article); - performImportScript(tempFile); - Item item = itemService.find(context, UUID.fromString(idStr)); - assertNotNull(item); - } finally { - tempFile.delete(); - } - } - - @Test - public void packagerImportColUUIDTest() throws Exception { - context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - configService.setProperty("upload.temp.dir",tempFile.getParent()); - try { - performExportScript(col1.getHandle(), tempFile); - String idStr = getID(); - collectionService.delete(context, col1); - performImportScript(tempFile); - Collection collection = collectionService.find(context, UUID.fromString(idStr)); - assertNotNull(collection); - } finally { - tempFile.delete(); - } - } - - @Test - public void packagerImportComUUIDTest() throws Exception { - context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - configService.setProperty("upload.temp.dir",tempFile.getParent()); - try { - //Community - performExportScript(child1.getHandle(), tempFile); - String idStr = getID(); - communityService.delete(context, child1); - performImportScript(tempFile); - Community community = communityService.find(context, UUID.fromString(idStr)); - assertNotNull(community); - } finally { - tempFile.delete(); - } - } - - @Test - public void packagerUUIDAlreadyExistTest() throws Exception { - context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - try { - //Item should be overwritten if UUID already Exists - performExportScript(article.getHandle(), tempFile); - performImportScript(tempFile); - Iterator items = itemService.findByCollection(context, col1); - assertEquals(1, Iterators.size(items)); - } finally { - tempFile.delete(); - } - } - - @Test - public void packagerUUIDAlreadyExistWithoutForceTest() throws Exception { - context.turnOffAuthorisationSystem(); - createTemplate(); - createFiles(); - try { - //should fail to restore the item because the uuid already exists. - performExportScript(article.getHandle(), tempFile); - UUID id = article.getID(); - itemService.delete(context, article); - WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false); - installItemService.installItem(context, workspaceItem, "123456789/100"); - performImportNoForceScript(tempFile); - Iterator items = itemService.findByCollection(context, col1); - Item testItem = items.next(); - assertFalse(items.hasNext()); //check to make sure there is only 1 item - assertEquals("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as - // it would have the old handle. - } finally { - tempFile.delete(); - } - } - - protected void createTemplate() { parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") .build(); @@ -184,10 +80,100 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { .withIssueDate("2017-10-17") .withEntityType("Publication") .build(); + + tempFile = File.createTempFile("packagerExportTest", ".zip"); + context.restoreAuthSystemState(); } - protected void createFiles() throws IOException { - tempFile = File.createTempFile("packagerExportTest", ".zip"); + @After + public void destroy() throws SQLException, IOException { + context.turnOffAuthorisationSystem(); + CommunityBuilder.deleteCommunity(parentCommunity.getID()); + CommunityBuilder.deleteCommunity(child1.getID()); + CommunityBuilder.deleteCommunity(col1.getID()); + CommunityBuilder.deleteCommunity(article.getID()); + CommunityBuilder.deleteCommunity(article.getID()); + tempFile.delete(); + context.restoreAuthSystemState(); + } + + @Test + public void packagerExportUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + + performExportScript(article.getHandle(), tempFile); + assertTrue(tempFile.length() > 0); + String idStr = getID(); + assertEquals(idStr, article.getID().toString()); + } + + @Test + public void packagerImportUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //Item + performExportScript(article.getHandle(), tempFile); + String idStr = getID(); + itemService.delete(context, article); + performImportScript(tempFile); + Item item = itemService.find(context, UUID.fromString(idStr)); + assertNotNull(item); + } + + @Test + public void packagerImportColUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + configService.setProperty("upload.temp.dir",tempFile.getParent()); + + performExportScript(col1.getHandle(), tempFile); + String idStr = getID(); + collectionService.delete(context, col1); + performImportScript(tempFile); + Collection collection = collectionService.find(context, UUID.fromString(idStr)); + assertNotNull(collection); + } + + @Test + public void packagerImportComUUIDTest() throws Exception { + context.turnOffAuthorisationSystem(); + configService.setProperty("upload.temp.dir",tempFile.getParent()); + + //Community + performExportScript(child1.getHandle(), tempFile); + String idStr = getID(); + communityService.delete(context, child1); + performImportScript(tempFile); + Community community = communityService.find(context, UUID.fromString(idStr)); + assertNotNull(community); + } + + @Test + public void packagerUUIDAlreadyExistTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //Item should be overwritten if UUID already Exists + performExportScript(article.getHandle(), tempFile); + performImportScript(tempFile); + Iterator items = itemService.findByCollection(context, col1); + assertEquals(1, Iterators.size(items)); + } + + @Test + public void packagerUUIDAlreadyExistWithoutForceTest() throws Exception { + context.turnOffAuthorisationSystem(); + //should fail to restore the item because the uuid already exists. + performExportScript(article.getHandle(), tempFile); + UUID id = article.getID(); + itemService.delete(context, article); + WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false); + installItemService.installItem(context, workspaceItem, "123456789/100"); + performImportNoForceScript(tempFile); + Iterator items = itemService.findByCollection(context, col1); + Item testItem = items.next(); + assertFalse(items.hasNext()); //check to make sure there is only 1 item + assertEquals("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as + // it would have the old handle. + itemService.delete(context, testItem); } private String getID() throws IOException, MetadataValidationException { From 6696cb7c9c4c7861cc6f4aa1624a7faa882ace30 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Thu, 16 Sep 2021 10:12:46 -0400 Subject: [PATCH 27/38] Make handle something that could never be ran into --- .../src/test/java/org/dspace/app/packager/PackagerIT.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index ff79ae8d39..d7bdce9279 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -166,12 +166,12 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { UUID id = article.getID(); itemService.delete(context, article); WorkspaceItem workspaceItem = workspaceItemService.create(context, col1, id, false); - installItemService.installItem(context, workspaceItem, "123456789/100"); + installItemService.installItem(context, workspaceItem, "123456789/0100"); performImportNoForceScript(tempFile); Iterator items = itemService.findByCollection(context, col1); Item testItem = items.next(); assertFalse(items.hasNext()); //check to make sure there is only 1 item - assertEquals("123456789/100", testItem.getHandle()); //check to make sure the item wasn't overwritten as + assertEquals("123456789/0100", testItem.getHandle()); //check to make sure the item wasn't overwritten as // it would have the old handle. itemService.delete(context, testItem); } From 6f27b82aa6b6ecc682281eaf435193d375f74035 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 16 Sep 2021 16:19:38 -0500 Subject: [PATCH 28/38] Upgrade to latest PostgreSQL driver 42.2.x and Flyway 6.x --- dspace-api/pom.xml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 81303d3785..a55c2563ee 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -743,7 +743,7 @@ org.flywaydb flyway-core - 6.5.5 + 6.5.7 diff --git a/pom.xml b/pom.xml index db14434e1c..e964a30c76 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 5.2.2.RELEASE 5.4.10.Final 6.0.18.Final - 42.2.9 + 42.2.23 8.8.1 1.2.22 From ebd2b89272917cfd25af00a793676574494f379d Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Tue, 21 Sep 2021 09:44:42 +1000 Subject: [PATCH 29/38] Removed processRelationships property --- .../org/dspace/app/itemimport/ItemImportServiceImpl.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 9214fc0570..880a59a3ee 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -172,7 +172,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea protected boolean useWorkflow = false; protected boolean useWorkflowSendEmail = false; protected boolean isQuiet = false; - protected boolean processRelationships = false; //remember which folder item was imported from Map itemFolderMap = null; @@ -2121,9 +2120,4 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea this.isQuiet = isQuiet; } - @Override - public void setProcessRelationships(boolean processRelationships) { - this.processRelationships = processRelationships; - } - } From 1f552683a7b1c23f2ef63c7e12f9134eaad2dff6 Mon Sep 17 00:00:00 2001 From: Nathan Buckingham Date: Wed, 22 Sep 2021 14:57:24 -0400 Subject: [PATCH 30/38] Remove unecessary deletion --- .../src/test/java/org/dspace/app/packager/PackagerIT.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java index d7bdce9279..ddc2b115d8 100644 --- a/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java +++ b/dspace-api/src/test/java/org/dspace/app/packager/PackagerIT.java @@ -87,14 +87,7 @@ public class PackagerIT extends AbstractIntegrationTestWithDatabase { @After public void destroy() throws SQLException, IOException { - context.turnOffAuthorisationSystem(); - CommunityBuilder.deleteCommunity(parentCommunity.getID()); - CommunityBuilder.deleteCommunity(child1.getID()); - CommunityBuilder.deleteCommunity(col1.getID()); - CommunityBuilder.deleteCommunity(article.getID()); - CommunityBuilder.deleteCommunity(article.getID()); tempFile.delete(); - context.restoreAuthSystemState(); } @Test From b692b9e9ddb20e32f2c60e85006e624d6110647e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 24 Sep 2021 15:13:07 -0500 Subject: [PATCH 31/38] Ensure ItemDAOImpl queries are all ordered by UUID --- .../dspace/content/dao/impl/ItemDAOImpl.java | 33 ++++++++---- .../app/rest/CollectionRestRepositoryIT.java | 32 +++++++++--- .../dspace/app/rest/ItemRestRepositoryIT.java | 52 ++++++++++++------- 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java index 683a6502c5..fd404e2f3e 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java @@ -32,6 +32,7 @@ import org.dspace.eperson.EPerson; import org.hibernate.Criteria; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.DetachedCriteria; +import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; import org.hibernate.criterion.Restrictions; @@ -54,14 +55,14 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findAll(Context context, boolean archived) throws SQLException { - Query query = createQuery(context, "FROM Item WHERE inArchive= :in_archive"); + Query query = createQuery(context, "FROM Item WHERE inArchive=:in_archive ORDER BY id"); query.setParameter("in_archive", archived); return iterate(query); } @Override public Iterator findAll(Context context, boolean archived, int limit, int offset) throws SQLException { - Query query = createQuery(context, "FROM Item WHERE inArchive= :in_archive"); + Query query = createQuery(context, "FROM Item WHERE inArchive=:in_archive ORDER BY id"); query.setParameter("in_archive", archived); query.setFirstResult(offset); query.setMaxResults(limit); @@ -71,7 +72,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findAll(Context context, boolean archived, boolean withdrawn) throws SQLException { - Query query = createQuery(context, "FROM Item WHERE inArchive= :in_archive or withdrawn = :withdrawn"); + Query query = createQuery(context, + "FROM Item WHERE inArchive=:in_archive or withdrawn=:withdrawn ORDER BY id"); query.setParameter("in_archive", archived); query.setParameter("withdrawn", withdrawn); return iterate(query); @@ -89,6 +91,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA if (lastModified != null) { queryStr.append(" AND last_modified > :last_modified"); } + queryStr.append(" ORDER BY i.id"); Query query = createQuery(context, queryStr.toString()); query.setParameter("in_archive", archived); @@ -102,7 +105,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findBySubmitter(Context context, EPerson eperson) throws SQLException { - Query query = createQuery(context, "FROM Item WHERE inArchive= :in_archive and submitter= :submitter"); + Query query = createQuery(context, + "FROM Item WHERE inArchive=:in_archive and submitter=:submitter ORDER BY id"); query.setParameter("in_archive", true); query.setParameter("submitter", eperson); return iterate(query); @@ -114,7 +118,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA if (!retrieveAllItems) { return findBySubmitter(context, eperson); } - Query query = createQuery(context, "FROM Item WHERE submitter= :submitter"); + Query query = createQuery(context, "FROM Item WHERE submitter=:submitter ORDER BY id"); query.setParameter("submitter", eperson); return iterate(query); } @@ -146,7 +150,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA if (value != null) { hqlQueryString += " AND STR(metadatavalue.value) = :text_value"; } - Query query = createQuery(context, hqlQueryString); + Query query = createQuery(context, hqlQueryString + " ORDER BY item.id"); query.setParameter("in_archive", inArchive); query.setParameter("metadata_field", metadataField); @@ -262,6 +266,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA criteria.add(Subqueries.notExists(subcriteria)); } } + criteria.addOrder(Order.asc("item.id")); + log.debug(String.format("Running custom query with %d filters", index)); return ((List) criteria.list()).iterator(); @@ -274,7 +280,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA Query query = createQuery(context, "SELECT item FROM Item as item join item.metadata metadatavalue " + "WHERE item.inArchive=:in_archive AND metadatavalue.metadataField = :metadata_field AND " + - "metadatavalue.authority = :authority"); + "metadatavalue.authority = :authority ORDER BY item.id"); query.setParameter("in_archive", inArchive); query.setParameter("metadata_field", metadataField); query.setParameter("authority", authority); @@ -286,7 +292,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA Integer offset) throws SQLException { Query query = createQuery(context, "select i from Item i join i.collections c " + - "WHERE :collection IN c AND i.inArchive=:in_archive"); + "WHERE :collection IN c AND i.inArchive=:in_archive ORDER BY i.id"); query.setParameter("collection", collection); query.setParameter("in_archive", true); if (offset != null) { @@ -309,6 +315,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA criteriaBuilder.notEqual(itemRoot.get(Item_.owningCollection), collection), criteriaBuilder.isMember(collection, itemRoot.get(Item_.collections)), criteriaBuilder.isTrue(itemRoot.get(Item_.inArchive)))); + criteriaQuery.orderBy(criteriaBuilder.asc(itemRoot.get(Item_.id))); + criteriaQuery.groupBy(itemRoot.get(Item_.id)); return list(context, criteriaQuery, false, Item.class, limit, offset).iterator(); } @@ -327,7 +335,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findAllByCollection(Context context, Collection collection) throws SQLException { - Query query = createQuery(context, "select i from Item i join i.collections c WHERE :collection IN c"); + Query query = createQuery(context, + "select i from Item i join i.collections c WHERE :collection IN c ORDER BY i.id"); query.setParameter("collection", collection); return iterate(query); @@ -336,7 +345,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findAllByCollection(Context context, Collection collection, Integer limit, Integer offset) throws SQLException { - Query query = createQuery(context, "select i from Item i join i.collections c WHERE :collection IN c"); + Query query = createQuery(context, + "select i from Item i join i.collections c WHERE :collection IN c ORDER BY i.id"); query.setParameter("collection", collection); if (offset != null) { @@ -381,7 +391,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA @Override public Iterator findByLastModifiedSince(Context context, Date since) throws SQLException { - Query query = createQuery(context, "SELECT i FROM item i WHERE last_modified > :last_modified"); + Query query = createQuery(context, + "SELECT i FROM item i WHERE last_modified > :last_modified ORDER BY id"); query.setParameter("last_modified", since, TemporalType.TIMESTAMP); return iterate(query); } diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java index 09be02484f..a9e8dadbe7 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java @@ -29,6 +29,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -2414,16 +2415,34 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes .withName("Mapped Collection") .build(); + List items = new ArrayList(); + // This comparator is used to sort our test Items by java.util.UUID (which sorts them based on the RFC + // and not based on String comparison, see also https://stackoverflow.com/a/51031298/3750035 ) + Comparator compareByUUID = Comparator.comparing(i -> i.getID()); + Item item0 = ItemBuilder.createItem(context, collection).withTitle("Item 0").build(); + items.add(item0); Item item1 = ItemBuilder.createItem(context, collection).withTitle("Item 1").build(); + items.add(item1); Item item2 = ItemBuilder.createItem(context, collection).withTitle("Item 2").build(); + items.add(item2); Item item3 = ItemBuilder.createItem(context, collection).withTitle("Item 3").build(); + items.add(item3); Item item4 = ItemBuilder.createItem(context, collection).withTitle("Item 4").build(); + items.add(item4); Item item5 = ItemBuilder.createItem(context, collection).withTitle("Item 5").build(); + items.add(item5); Item item6 = ItemBuilder.createItem(context, collection).withTitle("Item 6").build(); + items.add(item6); Item item7 = ItemBuilder.createItem(context, collection).withTitle("Item 7").build(); + items.add(item7); Item item8 = ItemBuilder.createItem(context, collection).withTitle("Item 8").build(); + items.add(item8); Item item9 = ItemBuilder.createItem(context, collection).withTitle("Item 9").build(); + items.add(item9); + + // sort items list by UUID (as Items will come back ordered by UUID) + items.sort(compareByUUID); collectionService.addItem(context, mappedCollection, item0); collectionService.addItem(context, mappedCollection, item1); @@ -2445,12 +2464,13 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes .param("embed.size", "mappedItems=5")) .andExpect(status().isOk()) .andExpect(jsonPath("$", CollectionMatcher.matchCollection(mappedCollection))) - .andExpect(jsonPath("$._embedded.mappedItems._embedded.mappedItems", Matchers.containsInAnyOrder( - ItemMatcher.matchItemProperties(item0), - ItemMatcher.matchItemProperties(item1), - ItemMatcher.matchItemProperties(item2), - ItemMatcher.matchItemProperties(item3), - ItemMatcher.matchItemProperties(item4) + .andExpect(jsonPath("$._embedded.mappedItems._embedded.mappedItems", + Matchers.containsInRelativeOrder( + ItemMatcher.matchItemProperties(items.get(0)), + ItemMatcher.matchItemProperties(items.get(1)), + ItemMatcher.matchItemProperties(items.get(2)), + ItemMatcher.matchItemProperties(items.get(3)), + ItemMatcher.matchItemProperties(items.get(4)) ))) .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/collections/" + mappedCollection.getID()))) diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java index 1c47825a21..103eee48e2 100644 --- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java +++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java @@ -27,6 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -111,6 +112,11 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + List items = new ArrayList(); + // This comparator is used to sort our test Items by java.util.UUID (which sorts them based on the RFC + // and not based on String comparison, see also https://stackoverflow.com/a/51031298/3750035 ) + Comparator compareByUUID = Comparator.comparing(i -> i.getID()); + //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) .withTitle("Public item 1") @@ -118,6 +124,7 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withAuthor("Smith, Donald").withAuthor("Doe, John") .withSubject("ExtraEntry") .build(); + items.add(publicItem1); Item publicItem2 = ItemBuilder.createItem(context, col2) .withTitle("Public item 2") @@ -125,6 +132,7 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withAuthor("Smith, Maria").withAuthor("Doe, Jane") .withSubject("TestingForMore").withSubject("ExtraEntry") .build(); + items.add(publicItem2); Item publicItem3 = ItemBuilder.createItem(context, col2) .withTitle("Public item 3") @@ -133,19 +141,19 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withSubject("AnotherTest").withSubject("TestingForMore") .withSubject("ExtraEntry") .build(); + items.add(publicItem3); + // sort items list by UUID (as Items will come back ordered by UUID) + items.sort(compareByUUID); context.restoreAuthSystemState(); String token = getAuthToken(admin.getEmail(), password); getClient(token).perform(get("/api/core/items")) .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.items", Matchers.containsInAnyOrder( - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, - "Public item 1", "2017-10-17"), - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, - "Public item 2", "2016-02-13"), - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, - "Public item 3", "2016-02-13") + .andExpect(jsonPath("$._embedded.items", Matchers.containsInRelativeOrder( + ItemMatcher.matchItemProperties(items.get(0)), + ItemMatcher.matchItemProperties(items.get(1)), + ItemMatcher.matchItemProperties(items.get(2)) ))) .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/items"))) @@ -185,6 +193,11 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withTemplateItem() .build(); + List items = new ArrayList(); + // This comparator is used to sort our test Items by java.util.UUID (which sorts them based on the RFC + // and not based on String comparison, see also https://stackoverflow.com/a/51031298/3750035 ) + Comparator compareByUUID = Comparator.comparing(i -> i.getID()); + //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) .withTitle("Public item 1") @@ -192,6 +205,7 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withAuthor("Smith, Donald").withAuthor("Doe, John") .withSubject("ExtraEntry") .build(); + items.add(publicItem1); Item publicItem2 = ItemBuilder.createItem(context, col2) .withTitle("Public item 2") @@ -199,6 +213,7 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withAuthor("Smith, Maria").withAuthor("Doe, Jane") .withSubject("TestingForMore").withSubject("ExtraEntry") .build(); + items.add(publicItem2); Item publicItem3 = ItemBuilder.createItem(context, col2) .withTitle("Public item 3") @@ -207,6 +222,9 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .withSubject("AnotherTest").withSubject("TestingForMore") .withSubject("ExtraEntry") .build(); + items.add(publicItem3); + // sort items list by UUID (as Items will come back ordered by UUID) + items.sort(compareByUUID); // Create a Workspace Item (which in turn creates an Item with "in_archive=false") // This is only created to prove that WorkspaceItems are NOT counted/listed in this endpoint @@ -232,16 +250,13 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { getClient(token).perform(get("/api/core/items") .param("size", "2")) .andExpect(status().isOk()) - .andExpect(jsonPath("$._embedded.items", Matchers.containsInAnyOrder( - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, - "Public item 1", "2017-10-17"), - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, - "Public item 2", "2016-02-13") + .andExpect(jsonPath("$._embedded.items", Matchers.containsInRelativeOrder( + ItemMatcher.matchItemProperties(items.get(0)), + ItemMatcher.matchItemProperties(items.get(1)) ))) .andExpect(jsonPath("$._embedded.items", Matchers.not( Matchers.contains( - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, - "Public item 3", "2016-02-13"), + ItemMatcher.matchItemProperties(items.get(2)), ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkspace, "In Progress Item", "2018-02-05"), ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkflow, @@ -271,15 +286,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest { .param("page", "1")) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.items", Matchers.contains( - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem3, - "Public item 3", "2016-02-13") + ItemMatcher.matchItemProperties(items.get(2)) ))) .andExpect(jsonPath("$._embedded.items", Matchers.not( Matchers.contains( - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem1, - "Public item 1", "2017-10-17"), - ItemMatcher.matchItemWithTitleAndDateIssued(publicItem2, - "Public item 2", "2016-02-13"), + ItemMatcher.matchItemProperties(items.get(0)), + ItemMatcher.matchItemProperties(items.get(1)), ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkspace, "In Progress Item", "2018-02-05"), ItemMatcher.matchItemWithTitleAndDateIssued(itemInWorkflow, From c91c7caf1afa293c1f613ca6ce3b506734608366 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 30 Sep 2021 16:49:23 -0500 Subject: [PATCH 32/38] Update to Postgres JDBC driver 42.2.24 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e964a30c76..d5fb4e9c74 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 5.2.2.RELEASE 5.4.10.Final 6.0.18.Final - 42.2.23 + 42.2.24 8.8.1 1.2.22 From 93bdf9add6ce23129dc7c770e115a7b67b97ba37 Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Mon, 4 Oct 2021 14:03:29 +1100 Subject: [PATCH 33/38] Removed relationships flag --- .../org/dspace/app/itemimport/service/ItemImportService.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java index ab4473ad08..af333764b5 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/service/ItemImportService.java @@ -229,11 +229,6 @@ public interface ItemImportService { */ public void setUseWorkflowSendEmail(boolean useWorkflowSendMail); - /** - * @param processRelationships whether to look for a relationships manifest - */ - public void setProcessRelationships(boolean processRelationships); - /** * Set quiet flag * From c01f4c1ca016152af8c90891189fbb7056b84e0c Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Mon, 4 Oct 2021 14:04:24 +1100 Subject: [PATCH 34/38] Fix broken command-line collection arg --- .../app/itemimport/ItemImportCLITool.java | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java index 7cad97df31..3cfed8503a 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportCLITool.java @@ -337,29 +337,36 @@ public class ItemImportCLITool { // validate each collection arg to see if it's a real collection for (int i = 0; i < collections.length; i++) { - // is the ID a handle? - if (collections[i].indexOf('/') != -1) { - // string has a / so it must be a handle - try and resolve - // it - mycollections.add((Collection) handleService - .resolveToObject(c, collections[i])); - // resolved, now make sure it's a collection - if ((mycollections.get(i) == null) - || (mycollections.get(i).getType() != Constants.COLLECTION)) { - mycollections.set(i, null); + Collection resolved = null; + + if (collections[i] != null) { + + // is the ID a handle? + if (collections[i].indexOf('/') != -1) { + // string has a / so it must be a handle - try and resolve + // it + resolved = ((Collection) handleService + .resolveToObject(c, collections[i])); + + } else { + // not a handle, try and treat it as an integer collection database ID + resolved = collectionService.find(c, UUID.fromString(collections[i])); + } - } else if (collections[i] != null) { - // not a handle, try and treat it as an integer collection database ID - mycollections.set(i, collectionService.find(c, UUID.fromString(collections[i]))); + } // was the collection valid? - if (mycollections.get(i) == null) { + if ((resolved == null) + || (resolved.getType() != Constants.COLLECTION)) { throw new IllegalArgumentException("Cannot resolve " + collections[i] + " to collection"); } + // add resolved collection to list + mycollections.add(resolved); + // print progress info String owningPrefix = ""; @@ -368,7 +375,7 @@ public class ItemImportCLITool { } System.out.println(owningPrefix + " Collection: " - + mycollections.get(i).getName()); + + resolved.getName()); } } // end of validating collections From 00740cc0214c027aeec907bd6a1644beae28f576 Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Mon, 4 Oct 2021 14:40:29 +1100 Subject: [PATCH 35/38] don't attempt to create relationships in test mode --- .../org/dspace/app/itemimport/ItemImportServiceImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 880a59a3ee..1ad5e003c0 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -346,6 +346,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea for (String itemIdentifier : identifierList) { + if (isTest) { + System.out.println("\tAdding relationship (type: " + relationshipType + + ") from " + folderName + " to " + itemIdentifier); + continue; + } + //find referenced item Item relationItem = resolveRelatedItem(c, itemIdentifier); if (null == relationItem) { From 8bdd1138eb69d0e37993a18152dc2379b769c73c Mon Sep 17 00:00:00 2001 From: Mykhaylo Date: Mon, 4 Oct 2021 16:24:42 +0200 Subject: [PATCH 36/38] implemented flyway script to delete deprecated columns --- ...ollection_table_drop_workflow_stem_columns.sql | 15 +++++++++++++++ ...ollection_table_drop_workflow_stem_columns.sql | 15 +++++++++++++++ ...ollection_table_drop_workflow_stem_columns.sql | 15 +++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql new file mode 100644 index 0000000000..ae8f1e7ef5 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql @@ -0,0 +1,15 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +------------------------------------------------------------------------------------- +---- ALTER table collection +------------------------------------------------------------------------------------- + +ALTER TABLE collection DROP COLUMN workflow_step_1; +ALTER TABLE collection DROP COLUMN workflow_step_2; +ALTER TABLE collection DROP COLUMN workflow_step_3; \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql new file mode 100644 index 0000000000..ae8f1e7ef5 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql @@ -0,0 +1,15 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +------------------------------------------------------------------------------------- +---- ALTER table collection +------------------------------------------------------------------------------------- + +ALTER TABLE collection DROP COLUMN workflow_step_1; +ALTER TABLE collection DROP COLUMN workflow_step_2; +ALTER TABLE collection DROP COLUMN workflow_step_3; \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql new file mode 100644 index 0000000000..ae8f1e7ef5 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2021.10.04__alter_collection_table_drop_workflow_stem_columns.sql @@ -0,0 +1,15 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +------------------------------------------------------------------------------------- +---- ALTER table collection +------------------------------------------------------------------------------------- + +ALTER TABLE collection DROP COLUMN workflow_step_1; +ALTER TABLE collection DROP COLUMN workflow_step_2; +ALTER TABLE collection DROP COLUMN workflow_step_3; \ No newline at end of file From 11bea56988c53a0f046a809771dd2ca364f00e8c Mon Sep 17 00:00:00 2001 From: Tyson Lloyd Thwaites Date: Tue, 5 Oct 2021 12:15:37 +1100 Subject: [PATCH 37/38] fixed checkstyle violation --- .../java/org/dspace/app/itemimport/ItemImportServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java index 1ad5e003c0..255d1d5785 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java @@ -347,7 +347,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea for (String itemIdentifier : identifierList) { if (isTest) { - System.out.println("\tAdding relationship (type: " + relationshipType + + System.out.println("\tAdding relationship (type: " + relationshipType + ") from " + folderName + " to " + itemIdentifier); continue; } @@ -397,7 +397,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem); Relationship persistedRelationship = relationshipService.create( c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace); - relationshipService.update(c, persistedRelationship); + // relationshipService.update(c, persistedRelationship); System.out.println("\tAdded relationship (type: " + relationshipType + ") from " + leftItem.getHandle() + " to " + rightItem.getHandle()); From c516f9c856710ce814d6add792d2cfebdeee11c2 Mon Sep 17 00:00:00 2001 From: Davide Negretti Date: Wed, 6 Oct 2021 17:08:53 +0200 Subject: [PATCH 38/38] [CST-4659] hint fixed for dc.type --- dspace/config/submission-forms.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dspace/config/submission-forms.xml b/dspace/config/submission-forms.xml index 878b79ffd6..0ae058b9b8 100644 --- a/dspace/config/submission-forms.xml +++ b/dspace/config/submission-forms.xml @@ -161,8 +161,7 @@ true dropdown - Select the type(s) of content of the item. To select more than one value in the list, you may - have to hold down the "CTRL" or "Shift" key. + Select the type of content of the item.