mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 10:04:21 +00:00
DS-4226 Improvements to Entity validation first pass
This commit is contained in:
@@ -17,8 +17,8 @@ import java.util.Enumeration;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -38,7 +38,6 @@ import org.dspace.authorize.AuthorizeException;
|
|||||||
import org.dspace.content.Collection;
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.DSpaceObject;
|
import org.dspace.content.DSpaceObject;
|
||||||
import org.dspace.content.Entity;
|
import org.dspace.content.Entity;
|
||||||
import org.dspace.content.EntityType;
|
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.MetadataField;
|
import org.dspace.content.MetadataField;
|
||||||
import org.dspace.content.MetadataSchemaEnum;
|
import org.dspace.content.MetadataSchemaEnum;
|
||||||
@@ -106,19 +105,44 @@ public class MetadataImport {
|
|||||||
protected static final String AC_PREFIX = "authority.controlled.";
|
protected static final String AC_PREFIX = "authority.controlled.";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of field:value to csv row number, used to resolve indirect entity references.
|
* Map of field:value to csv row number, used to resolve indirect entity target references.
|
||||||
*
|
*
|
||||||
* @see #populateRefAndRowMap(DSpaceCSVLine, int, UUID)
|
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
|
||||||
*/
|
*/
|
||||||
protected HashMap<String, Set<Integer>> csvRefMap = new HashMap<>();
|
protected Map<String, Set<Integer>> csvRefMap = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of csv row number to UUID, used to resolve indirect entity references.
|
* Map of csv row number to UUID, used to resolve indirect entity target references.
|
||||||
*
|
*
|
||||||
* @see #populateRefAndRowMap(DSpaceCSVLine, int, UUID)
|
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
|
||||||
*/
|
*/
|
||||||
protected HashMap<Integer, UUID> csvRowMap = new HashMap<>();
|
protected HashMap<Integer, UUID> csvRowMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of UUIDs to their entity types.
|
||||||
|
*
|
||||||
|
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
|
||||||
|
*/
|
||||||
|
protected static HashMap<UUID, String> entityTypeMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map of UUIDs to their relations that are referenced within any import with their referers.
|
||||||
|
*
|
||||||
|
* @see #populateEntityRelationMap(String, String, String)
|
||||||
|
*/
|
||||||
|
protected static HashMap<String, HashMap<String, ArrayList<String>>> entityRelationMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of errors generated during relation validation process.
|
||||||
|
*/
|
||||||
|
protected ArrayList<String> relationValidationErrors = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counter of rows proccssed in a CSV.
|
||||||
|
*/
|
||||||
|
protected Integer rowCount = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger
|
* Logger
|
||||||
*/
|
*/
|
||||||
@@ -184,10 +208,9 @@ public class MetadataImport {
|
|||||||
c.setMode(Context.Mode.BATCH_EDIT);
|
c.setMode(Context.Mode.BATCH_EDIT);
|
||||||
|
|
||||||
// Process each change
|
// Process each change
|
||||||
int rowCount = 1;
|
|
||||||
for (DSpaceCSVLine line : toImport) {
|
for (DSpaceCSVLine line : toImport) {
|
||||||
//Resolve references to other items
|
// Resolve target references to other items
|
||||||
populateRefAndRowMap(line, rowCount, null);
|
populateRefAndRowMap(line, line.getID());
|
||||||
line = resolveEntityRefs(line);
|
line = resolveEntityRefs(line);
|
||||||
// Get the DSpace item to compare with
|
// Get the DSpace item to compare with
|
||||||
UUID id = line.getID();
|
UUID id = line.getID();
|
||||||
@@ -201,7 +224,7 @@ public class MetadataImport {
|
|||||||
WorkflowItem wfItem = null;
|
WorkflowItem wfItem = null;
|
||||||
Item item = null;
|
Item item = null;
|
||||||
|
|
||||||
// Is this a new item?
|
// Is this an existing item?
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
// Get the item
|
// Get the item
|
||||||
item = itemService.find(c, id);
|
item = itemService.find(c, id);
|
||||||
@@ -238,9 +261,8 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare
|
// Compare
|
||||||
compare(item, fromCSV, change, md, whatHasChanged, line);
|
compareAndUpdate(item, fromCSV, change, md, whatHasChanged, line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,30 +400,23 @@ public class MetadataImport {
|
|||||||
item = wsItem.getItem();
|
item = wsItem.getItem();
|
||||||
|
|
||||||
// Add the metadata to the item
|
// Add the metadata to the item
|
||||||
List<BulkEditMetadataValue> relationships = new LinkedList<>();
|
for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
|
||||||
|
itemService.addMetadata(c, item, dcv.getSchema(),
|
||||||
|
dcv.getElement(),
|
||||||
|
dcv.getQualifier(),
|
||||||
|
dcv.getLanguage(),
|
||||||
|
dcv.getValue(),
|
||||||
|
dcv.getAuthority(),
|
||||||
|
dcv.getConfidence());
|
||||||
|
}
|
||||||
|
//Add relations after all metadata has been processed
|
||||||
for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
|
for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
|
||||||
if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
|
if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
|
||||||
|
addRelationship(c, item, dcv.getElement(), dcv.getValue());
|
||||||
if (!StringUtils.equals(dcv.getElement(), "type")) {
|
|
||||||
relationships.add(dcv);
|
|
||||||
} else {
|
|
||||||
handleRelationshipMetadataValueFromBulkEditMetadataValue(item, dcv);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
itemService.addMetadata(c, item, dcv.getSchema(),
|
|
||||||
dcv.getElement(),
|
|
||||||
dcv.getQualifier(),
|
|
||||||
dcv.getLanguage(),
|
|
||||||
dcv.getValue(),
|
|
||||||
dcv.getAuthority(),
|
|
||||||
dcv.getConfidence());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (BulkEditMetadataValue relationship : relationships) {
|
|
||||||
handleRelationshipMetadataValueFromBulkEditMetadataValue(item, relationship);
|
|
||||||
}
|
|
||||||
// Should the workflow be used?
|
// Should the workflow be used?
|
||||||
if (useWorkflow) {
|
if (useWorkflow) {
|
||||||
WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService();
|
WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService();
|
||||||
@@ -424,8 +439,6 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit changes to the object
|
|
||||||
// c.commit();
|
|
||||||
whatHasChanged.setItem(item);
|
whatHasChanged.setItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +452,7 @@ public class MetadataImport {
|
|||||||
c.uncacheEntity(wfItem);
|
c.uncacheEntity(wfItem);
|
||||||
c.uncacheEntity(item);
|
c.uncacheEntity(item);
|
||||||
}
|
}
|
||||||
populateRefAndRowMap(line, rowCount, item == null ? null : item.getID());
|
populateRefAndRowMap(line, item == null ? null : item.getID());
|
||||||
// keep track of current rows processed
|
// keep track of current rows processed
|
||||||
rowCount++;
|
rowCount++;
|
||||||
}
|
}
|
||||||
@@ -452,32 +465,14 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the changes
|
// Return the changes
|
||||||
|
if (!change ) {
|
||||||
|
validateExpressedRelations();
|
||||||
|
}
|
||||||
return changes;
|
return changes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This metod handles the BulkEditMetadataValue objects that correspond to Relationship metadatavalues
|
* Compare an item metadata with a line from CSV, and optionally update the item.
|
||||||
* @param item The item to which this metadatavalue will belong
|
|
||||||
* @param dcv The BulkEditMetadataValue to be processed
|
|
||||||
* @throws SQLException If something goes wrong
|
|
||||||
* @throws AuthorizeException If something goes wrong
|
|
||||||
*/
|
|
||||||
private void handleRelationshipMetadataValueFromBulkEditMetadataValue(Item item, BulkEditMetadataValue dcv)
|
|
||||||
throws SQLException, AuthorizeException, MetadataImportException {
|
|
||||||
LinkedList<String> values = new LinkedList<>();
|
|
||||||
values.add(dcv.getValue());
|
|
||||||
LinkedList<String> authorities = new LinkedList<>();
|
|
||||||
authorities.add(dcv.getAuthority());
|
|
||||||
LinkedList<Integer> confidences = new LinkedList<>();
|
|
||||||
confidences.add(dcv.getConfidence());
|
|
||||||
handleRelationMetadata(c, item, dcv.getSchema(), dcv.getElement(),
|
|
||||||
dcv.getQualifier(),
|
|
||||||
dcv.getLanguage(), values, authorities, confidences);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare an item metadata with a line from CSV, and optionally update the item
|
|
||||||
*
|
*
|
||||||
* @param item The current item metadata
|
* @param item The current item metadata
|
||||||
* @param fromCSV The metadata from the CSV file
|
* @param fromCSV The metadata from the CSV file
|
||||||
@@ -487,9 +482,10 @@ public class MetadataImport {
|
|||||||
* @param line line in CSV file
|
* @param line line in CSV file
|
||||||
* @throws SQLException if there is a problem accessing a Collection from the database, from its handle
|
* @throws SQLException if there is a problem accessing a Collection from the database, from its handle
|
||||||
* @throws AuthorizeException if there is an authorization problem with permissions
|
* @throws AuthorizeException if there is an authorization problem with permissions
|
||||||
|
* @throws MetadataImportException custom exception for error handling within metadataimport
|
||||||
*/
|
*/
|
||||||
protected void compare(Item item, String[] fromCSV, boolean change,
|
protected void compareAndUpdate(Item item, String[] fromCSV, boolean change,
|
||||||
String md, BulkEditChange changes, DSpaceCSVLine line)
|
String md, BulkEditChange changes, DSpaceCSVLine line)
|
||||||
throws SQLException, AuthorizeException, MetadataImportException {
|
throws SQLException, AuthorizeException, MetadataImportException {
|
||||||
// Log what metadata element we're looking at
|
// Log what metadata element we're looking at
|
||||||
String all = "";
|
String all = "";
|
||||||
@@ -663,10 +659,9 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName())) {
|
if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName())) {
|
||||||
List<RelationshipType> relationshipTypeList = relationshipTypeService
|
List<RelationshipType> relationshipTypeList = relationshipTypeService
|
||||||
.findByLeftwardOrRightwardTypeName(c, element);
|
.findByLeftOrRightLabel(c, element);
|
||||||
for (RelationshipType relationshipType : relationshipTypeList) {
|
for (RelationshipType relationshipType : relationshipTypeList) {
|
||||||
for (Relationship relationship : relationshipService
|
for (Relationship relationship : relationshipService
|
||||||
.findByItemAndRelationshipType(c, item, relationshipType)) {
|
.findByItemAndRelationshipType(c, item, relationshipType)) {
|
||||||
@@ -674,7 +669,7 @@ public class MetadataImport {
|
|||||||
relationshipService.update(c, relationship);
|
relationshipService.update(c, relationship);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handleRelationMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences);
|
addRelationships(c, item, element, values);
|
||||||
} else {
|
} else {
|
||||||
itemService.clearMetadata(c, item, schema, element, qualifier, language);
|
itemService.clearMetadata(c, item, schema, element, qualifier, language);
|
||||||
itemService.addMetadata(c, item, schema, element, qualifier,
|
itemService.addMetadata(c, item, schema, element, qualifier,
|
||||||
@@ -685,47 +680,35 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method decides whether the metadatavalue is of type relation.type or if it corresponds to
|
*
|
||||||
* a relationship and handles it accordingly to their respective methods
|
* Adds multiple relationships with the same label to an item.
|
||||||
|
*
|
||||||
* @param c The relevant DSpace context
|
* @param c The relevant DSpace context
|
||||||
* @param item The item to which this metadatavalue belongs to
|
* @param item The item to which this metadatavalue belongs to
|
||||||
* @param schema The schema for the metadatavalue
|
* @param label The element for the metadatavalue
|
||||||
* @param element The element for the metadatavalue
|
* @param values to iterate over
|
||||||
* @param qualifier The qualifier for the metadatavalue
|
|
||||||
* @param language The language for the metadatavalue
|
|
||||||
* @param values The values for the metadatavalue
|
|
||||||
* @param authorities The authorities for the metadatavalue
|
|
||||||
* @param confidences The confidences for the metadatavalue
|
|
||||||
* @throws SQLException If something goes wrong
|
* @throws SQLException If something goes wrong
|
||||||
* @throws AuthorizeException If something goes wrong
|
* @throws AuthorizeException If something goes wrong
|
||||||
*/
|
*/
|
||||||
private void handleRelationMetadata(Context c, Item item, String schema, String element, String qualifier,
|
private void addRelationships(Context c, Item item, String label, List<String> values)
|
||||||
String language, List<String> values, List<String> authorities,
|
throws SQLException, AuthorizeException,
|
||||||
List<Integer> confidences) throws SQLException, AuthorizeException,
|
|
||||||
MetadataImportException {
|
MetadataImportException {
|
||||||
|
for (String value : values) {
|
||||||
if (StringUtils.equals(element, "type") && StringUtils.isBlank(qualifier)) {
|
addRelationship(c, item, label, value);
|
||||||
handleRelationTypeMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
for (String value : values) {
|
|
||||||
handleRelationOtherMetadata(c, item, element, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an existing entity from a reference.
|
* Gets an existing entity from a target reference.
|
||||||
*
|
*
|
||||||
* @param context the context to use.
|
* @param context the context to use.
|
||||||
* @param reference the reference which may be a UUID, metadata reference, or rowName reference.
|
* @param targetReference the target reference which may be a UUID, metadata reference, or rowName reference.
|
||||||
* @return the entity, which is guaranteed to exist.
|
* @return the entity, which is guaranteed to exist.
|
||||||
* @throws MetadataImportException if the reference is badly formed or refers to a non-existing item.
|
* @throws MetadataImportException if the target reference is badly formed or refers to a non-existing item.
|
||||||
*/
|
*/
|
||||||
private Entity getEntity(Context context, String reference) throws MetadataImportException {
|
private Entity getEntity(Context context, String targetReference) throws MetadataImportException {
|
||||||
Entity entity = null;
|
Entity entity = null;
|
||||||
UUID uuid = resolveEntityRef(context, reference);
|
UUID uuid = resolveEntityRef(context, targetReference);
|
||||||
// At this point, we have a uuid, so we can get an entity
|
// At this point, we have a uuid, so we can get an entity
|
||||||
try {
|
try {
|
||||||
entity = entityService.findByItemId(context, uuid);
|
entity = entityService.findByItemId(context, uuid);
|
||||||
@@ -734,218 +717,73 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
} catch (SQLException sqle) {
|
} catch (SQLException sqle) {
|
||||||
throw new MetadataImportException("Unable to find entity using reference: " + reference, sqle);
|
throw new MetadataImportException("Unable to find entity using reference: " + targetReference, sqle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method takes the item, element and values to determine what relationships should be built
|
*
|
||||||
* for these parameters and calls on the method to construct them
|
* Creates a relationship for the given item
|
||||||
|
*
|
||||||
* @param c The relevant DSpace context
|
* @param c The relevant DSpace context
|
||||||
* @param item The item that the relationships will be made for
|
* @param item The item that the relationships will be made for
|
||||||
* @param element The string determining which relationshiptype is to be used
|
* @param label The relationship label
|
||||||
* @param value The value for the relationship
|
* @param value The value for the relationship
|
||||||
* @throws SQLException If something goes wrong
|
* @throws SQLException If something goes wrong
|
||||||
* @throws AuthorizeException If something goes wrong
|
* @throws AuthorizeException If something goes wrong
|
||||||
*/
|
*/
|
||||||
private void handleRelationOtherMetadata(Context c, Item item, String element, String value)
|
private void addRelationship(Context c, Item item, String label, String value)
|
||||||
throws SQLException, AuthorizeException, MetadataImportException {
|
throws SQLException, AuthorizeException, MetadataImportException {
|
||||||
if (value.isEmpty()) {
|
if (value.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Entity entity = entityService.findByItemId(c, item.getID());
|
|
||||||
boolean left = false;
|
boolean left = false;
|
||||||
List<RelationshipType> acceptableRelationshipTypes = new LinkedList<>();
|
|
||||||
|
|
||||||
|
// Get entity from target reference
|
||||||
Entity relationEntity = getEntity(c, value);
|
Entity relationEntity = getEntity(c, value);
|
||||||
|
// Get relationship type of entity and item
|
||||||
|
String relationEntityRelationshipType = itemService.getMetadata(relationEntity.getItem(),
|
||||||
|
"relationship", "type",
|
||||||
|
null, Item.ANY).get(0).getValue();
|
||||||
|
String itemRelationshipType = itemService.getMetadata(item, "relationship", "type",
|
||||||
|
null, Item.ANY).get(0).getValue();
|
||||||
|
|
||||||
List<RelationshipType> leftRelationshipTypesForEntity = entityService.getLeftRelationshipTypes(c, entity);
|
// Get the correct RelationshipType based on label
|
||||||
List<RelationshipType> rightRelationshipTypesForEntity = entityService.getRightRelationshipTypes(c, entity);
|
List<RelationshipType> relType = relationshipTypeService.findByLeftOrRightLabel(c, label);
|
||||||
|
RelationshipType foundRelationshipType = matchRelationshipType(relType,
|
||||||
|
itemRelationshipType,relationEntityRelationshipType);
|
||||||
|
|
||||||
//Identify which RelationshipType objects match the combination of:
|
if (foundRelationshipType == null) {
|
||||||
// * the left entity type
|
throw new MetadataImportException("Error on CSV row " + rowCount + ":" + "\n" +
|
||||||
// * the right entity type
|
"No Relationship type found for:\n" +
|
||||||
// * the name of the relationship type (based on the expected direction of the relationship)
|
"Target type: " + relationEntityRelationshipType + "\n" +
|
||||||
//The matches are included in the acceptableRelationshipTypes
|
"Origin referer type: " + itemRelationshipType + "\n" +
|
||||||
for (RelationshipType relationshipType : entityService.getAllRelationshipTypes(c, entity)) {
|
"with label: " + label);
|
||||||
if (StringUtils.equalsIgnoreCase(relationshipType.getLeftwardType(), element)) {
|
|
||||||
left = verifyValidLeftwardRelationshipType(c, entity, relationEntity, left,
|
|
||||||
acceptableRelationshipTypes,
|
|
||||||
leftRelationshipTypesForEntity,
|
|
||||||
relationshipType);
|
|
||||||
} else if (StringUtils.equalsIgnoreCase(relationshipType.getRightwardType(), element)) {
|
|
||||||
left = verifyValidRightwardRelationshipType(c, entity, relationEntity, left,
|
|
||||||
acceptableRelationshipTypes,
|
|
||||||
rightRelationshipTypesForEntity,
|
|
||||||
relationshipType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acceptableRelationshipTypes.size() > 1) {
|
if (foundRelationshipType.getLeftLabel().equalsIgnoreCase(label)) {
|
||||||
log.error("Ambiguous relationship_types were found");
|
left = true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (acceptableRelationshipTypes.size() == 0) {
|
|
||||||
log.error("no relationship_types were found");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//There is exactly one
|
// Placeholder items for relation placing
|
||||||
buildRelationObject(c, item, relationEntity.getItem(), left, acceptableRelationshipTypes.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method creates the relationship for the item and stores it in the database
|
|
||||||
* @param c The relevant DSpace context
|
|
||||||
* @param item The item for which this relationship will be constructed
|
|
||||||
* @param otherItem The item for the relationship
|
|
||||||
* @param left A boolean indicating whether the item is the leftItem or the rightItem
|
|
||||||
* @param acceptedRelationshipType The acceptable relationship type
|
|
||||||
* @throws SQLException If something goes wrong
|
|
||||||
* @throws AuthorizeException If something goes wrong
|
|
||||||
*/
|
|
||||||
private void buildRelationObject(Context c, Item item, Item otherItem, boolean left,
|
|
||||||
RelationshipType acceptedRelationshipType)
|
|
||||||
throws SQLException, AuthorizeException {
|
|
||||||
Item leftItem = null;
|
Item leftItem = null;
|
||||||
Item rightItem = null;
|
Item rightItem = null;
|
||||||
if (left) {
|
if (left) {
|
||||||
leftItem = item;
|
leftItem = item;
|
||||||
rightItem = otherItem;
|
rightItem = relationEntity.getItem();
|
||||||
} else {
|
} else {
|
||||||
|
leftItem = relationEntity.getItem();
|
||||||
rightItem = item;
|
rightItem = item;
|
||||||
leftItem = otherItem;
|
|
||||||
}
|
}
|
||||||
RelationshipType relationshipType = acceptedRelationshipType;
|
|
||||||
|
// Create the relationship
|
||||||
int leftPlace = relationshipService.findLeftPlaceByLeftItem(c, leftItem) + 1;
|
int leftPlace = relationshipService.findLeftPlaceByLeftItem(c, leftItem) + 1;
|
||||||
int rightPlace = relationshipService.findRightPlaceByRightItem(c, rightItem) + 1;
|
int rightPlace = relationshipService.findRightPlaceByRightItem(c, rightItem) + 1;
|
||||||
Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem,
|
Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem,
|
||||||
relationshipType, leftPlace, rightPlace);
|
foundRelationshipType, leftPlace, rightPlace);
|
||||||
relationshipService.update(c, persistedRelationship);
|
relationshipService.update(c, persistedRelationship);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will add RelationshipType objects to the acceptableRelationshipTypes list
|
|
||||||
* if applicable and valid RelationshipType objects are found. It will also return a boolean indicating
|
|
||||||
* whether we're dealing with a left Relationship or not
|
|
||||||
* @param c The relevant DSpace context
|
|
||||||
* @param entity The Entity for which the RelationshipType has to be checked
|
|
||||||
* @param relationEntity The other Entity of the Relationship
|
|
||||||
* @param left Boolean indicating whether the Relationship is left or not
|
|
||||||
* @param acceptableRelationshipTypes The list of RelationshipType objects that will be added to
|
|
||||||
* @param rightRelationshipTypesForEntity The list of RelationshipType objects that are possible
|
|
||||||
* for the right entity
|
|
||||||
* @param relationshipType The RelationshipType object that we want to check whether it's
|
|
||||||
* valid to be added or not
|
|
||||||
* @return A boolean indicating whether the relationship is left or right.
|
|
||||||
* Will be set to false if the relationship is valid.
|
|
||||||
* Will remain unmodified from the left parameter if the
|
|
||||||
* relationship is not valid.
|
|
||||||
* @throws SQLException If something goes wrong
|
|
||||||
*/
|
|
||||||
private boolean verifyValidRightwardRelationshipType(Context c, Entity entity,
|
|
||||||
Entity relationEntity,
|
|
||||||
boolean left,
|
|
||||||
List<RelationshipType>
|
|
||||||
acceptableRelationshipTypes,
|
|
||||||
List<RelationshipType>
|
|
||||||
rightRelationshipTypesForEntity,
|
|
||||||
RelationshipType relationshipType)
|
|
||||||
throws SQLException {
|
|
||||||
if (StringUtils.equalsIgnoreCase(entityService.getType(c, entity).getLabel(),
|
|
||||||
relationshipType.getRightType().getLabel()) &&
|
|
||||||
StringUtils.equalsIgnoreCase(entityService.getType(c, relationEntity).getLabel(),
|
|
||||||
relationshipType.getLeftType().getLabel())) {
|
|
||||||
|
|
||||||
for (RelationshipType rightRelationshipType : rightRelationshipTypesForEntity) {
|
|
||||||
if (StringUtils.equalsIgnoreCase(rightRelationshipType.getLeftType().getLabel(),
|
|
||||||
relationshipType.getLeftType().getLabel()) ||
|
|
||||||
StringUtils.equalsIgnoreCase(rightRelationshipType.getRightType().getLabel(),
|
|
||||||
relationshipType.getLeftType().getLabel())) {
|
|
||||||
left = false;
|
|
||||||
acceptableRelationshipTypes.add(relationshipType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will add RelationshipType objects to the acceptableRelationshipTypes list
|
|
||||||
* if applicable and valid RelationshipType objects are found. It will also return a boolean indicating
|
|
||||||
* whether we're dealing with a left Relationship or not
|
|
||||||
* @param c The relevant DSpace context
|
|
||||||
* @param entity The Entity for which the RelationshipType has to be checked
|
|
||||||
* @param relationEntity The other Entity of the Relationship
|
|
||||||
* @param left Boolean indicating whether the Relationship is left or not
|
|
||||||
* @param acceptableRelationshipTypes The list of RelationshipType objects that will be added to
|
|
||||||
* @param leftRelationshipTypesForEntity The list of RelationshipType objects that are possible
|
|
||||||
* for the left entity
|
|
||||||
* @param relationshipType The RelationshipType object that we want to check whether it's
|
|
||||||
* valid to be added or not
|
|
||||||
* @return A boolean indicating whether the relationship is left or right.
|
|
||||||
* Will be set to true if the relationship is valid.
|
|
||||||
* Will remain unmodified from the left parameter if the
|
|
||||||
* relationship is not valid.
|
|
||||||
* @throws SQLException If something goes wrong
|
|
||||||
*/
|
|
||||||
private boolean verifyValidLeftwardRelationshipType(Context c, Entity entity,
|
|
||||||
Entity relationEntity,
|
|
||||||
boolean left,
|
|
||||||
List<RelationshipType>
|
|
||||||
acceptableRelationshipTypes,
|
|
||||||
List<RelationshipType>
|
|
||||||
leftRelationshipTypesForEntity,
|
|
||||||
RelationshipType relationshipType)
|
|
||||||
throws SQLException {
|
|
||||||
if (StringUtils.equalsIgnoreCase(entityService.getType(c, entity).getLabel(),
|
|
||||||
relationshipType.getLeftType().getLabel()) &&
|
|
||||||
StringUtils.equalsIgnoreCase(entityService.getType(c, relationEntity).getLabel(),
|
|
||||||
relationshipType.getRightType().getLabel())) {
|
|
||||||
for (RelationshipType leftRelationshipType : leftRelationshipTypesForEntity) {
|
|
||||||
if (StringUtils.equalsIgnoreCase(leftRelationshipType.getRightType().getLabel(),
|
|
||||||
relationshipType.getRightType().getLabel()) ||
|
|
||||||
StringUtils.equalsIgnoreCase(leftRelationshipType.getLeftType().getLabel(),
|
|
||||||
relationshipType.getRightType().getLabel())) {
|
|
||||||
left = true;
|
|
||||||
acceptableRelationshipTypes.add(relationshipType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method will add the relationship.type metadata to the item if an EntityType can be found for the value in
|
|
||||||
* the values list.
|
|
||||||
* @param c The relevant DSpace context
|
|
||||||
* @param item The item to which this metadatavalue will be added
|
|
||||||
* @param schema The schema for the metadatavalue to be added
|
|
||||||
* @param element The element for the metadatavalue to be added
|
|
||||||
* @param qualifier The qualifier for the metadatavalue to be added
|
|
||||||
* @param language The language for the metadatavalue to be added
|
|
||||||
* @param values The value on which we'll search for EntityType object and it's the value
|
|
||||||
* for the metadatavalue that will be created
|
|
||||||
* @param authorities The authority for the metadatavalue. This will be filled with the ID
|
|
||||||
* of the found EntityType for the value if it exists
|
|
||||||
* @param confidences The confidence for the metadatavalue
|
|
||||||
* @throws SQLException If something goes wrong
|
|
||||||
* @throws AuthorizeException If something goes wrong
|
|
||||||
*/
|
|
||||||
private void handleRelationTypeMetadata(Context c, Item item, String schema, String element, String qualifier,
|
|
||||||
String language, List<String> values, List<String> authorities,
|
|
||||||
List<Integer> confidences)
|
|
||||||
throws SQLException, AuthorizeException {
|
|
||||||
EntityType entityType = entityTypeService.findByEntityType(c, values.get(0));
|
|
||||||
if (entityType != null) {
|
|
||||||
authorities.add(String.valueOf(entityType.getID()));
|
|
||||||
itemService.clearMetadata(c, item, schema, element, qualifier, language);
|
|
||||||
itemService.addMetadata(c, item, schema, element, qualifier, language,
|
|
||||||
values, authorities, confidences);
|
|
||||||
itemService.update(c, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare changes between an items owning collection and mapped collections
|
* Compare changes between an items owning collection and mapped collections
|
||||||
* and what is in the CSV file
|
* and what is in the CSV file
|
||||||
@@ -1586,9 +1424,6 @@ public class MetadataImport {
|
|||||||
|
|
||||||
// Display the changes
|
// Display the changes
|
||||||
displayChanges(changes, true);
|
displayChanges(changes, true);
|
||||||
|
|
||||||
// Commit the change to the DB
|
|
||||||
// c.commit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finsh off and tidy up
|
// Finsh off and tidy up
|
||||||
@@ -1603,24 +1438,28 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a copy of the given csv line with all entity references resolved to UUID strings.
|
* Gets a copy of the given csv line with all entity target references resolved to UUID strings.
|
||||||
* Keys being iterated over represent metadatafields or special columns to be processed.
|
* Keys being iterated over represent metadatafields or special columns to be processed.
|
||||||
*
|
*
|
||||||
* @param line the csv line to process.
|
* @param line the csv line to process.
|
||||||
* @return a copy, with all references resolved.
|
* @return a copy, with all references resolved.
|
||||||
* @throws MetadataImportException if there is an error resolving any entity reference.
|
* @throws MetadataImportException if there is an error resolving any entity target reference.
|
||||||
*/
|
*/
|
||||||
public DSpaceCSVLine resolveEntityRefs(DSpaceCSVLine line) throws MetadataImportException {
|
public DSpaceCSVLine resolveEntityRefs(DSpaceCSVLine line) throws MetadataImportException {
|
||||||
DSpaceCSVLine newLine = new DSpaceCSVLine(line.getID());
|
DSpaceCSVLine newLine = new DSpaceCSVLine(line.getID());
|
||||||
|
UUID originId = evaluateOriginId(line.getID());
|
||||||
for (String key : line.keys()) {
|
for (String key : line.keys()) {
|
||||||
// If a key represents a relation field attempt to resolve the reference from the csvRefMap
|
// If a key represents a relation field attempt to resolve the target reference from the csvRefMap
|
||||||
if (key.split("\\.")[0].equalsIgnoreCase("relation")) {
|
if (key.split("\\.")[0].equalsIgnoreCase("relation")) {
|
||||||
if (line.get(key).size() > 0) {
|
if (line.get(key).size() > 0) {
|
||||||
for (String val : line.get(key)) {
|
for (String val : line.get(key)) {
|
||||||
// Attempt to resolve the relation reference
|
// Attempt to resolve the relation target reference
|
||||||
// These can be a UUID, metadata reference or rowName reference
|
// These can be a UUID, metadata target reference or rowName target reference
|
||||||
String uuid = resolveEntityRef(c, val).toString();
|
String uuid = resolveEntityRef(c, val).toString();
|
||||||
newLine.add(key, uuid);
|
newLine.add(key, uuid);
|
||||||
|
//Entity refs have been resolved / placeholdered
|
||||||
|
//Populate the EntityRelationMap
|
||||||
|
populateEntityRelationMap(uuid, key, originId.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1635,27 +1474,59 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newLine;
|
return newLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populates the csvRefMap and csvRowMap for the given csv line.
|
* Populate the entityRelationMap with all target references and it's asscoiated labels
|
||||||
|
* to their respective origins
|
||||||
|
*
|
||||||
|
* @param refUUID the target reference UUID for the relation
|
||||||
|
* @param relationField the field of the label to relate
|
||||||
|
*/
|
||||||
|
private void populateEntityRelationMap(String refUUID, String relationField, String originId) {
|
||||||
|
HashMap<String, ArrayList<String>> labels = null;
|
||||||
|
if (entityRelationMap.get(refUUID) == null) {
|
||||||
|
labels = new HashMap<>();
|
||||||
|
ArrayList<String> originIds = new ArrayList<>();
|
||||||
|
originIds.add(originId);
|
||||||
|
labels.put(relationField, originIds);
|
||||||
|
entityRelationMap.put(refUUID, labels);
|
||||||
|
} else {
|
||||||
|
labels = entityRelationMap.get(refUUID);
|
||||||
|
if (labels.get(relationField) == null) {
|
||||||
|
ArrayList<String> originIds = new ArrayList<>();
|
||||||
|
originIds.add(originId);
|
||||||
|
labels.put(relationField, originIds);
|
||||||
|
} else {
|
||||||
|
ArrayList<String> originIds = labels.get(relationField);
|
||||||
|
originIds.add(originId);
|
||||||
|
labels.put(relationField, originIds);
|
||||||
|
}
|
||||||
|
entityRelationMap.put(refUUID, labels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the csvRefMap, csvRowMap, and entityTypeMap for the given csv line.
|
||||||
*
|
*
|
||||||
* The csvRefMap is an index that keeps track of which rows have a specific value for
|
* The csvRefMap is an index that keeps track of which rows have a specific value for
|
||||||
* a specific metadata field or the special "rowName" column. This is used to help resolve indirect
|
* a specific metadata field or the special "rowName" column. This is used to help resolve indirect
|
||||||
* entity references in the same CSV.
|
* entity target references in the same CSV.
|
||||||
*
|
*
|
||||||
* The csvRowMap is a row number to UUID map, and contains an entry for every row that has
|
* The csvRowMap is a row number to UUID map, and contains an entry for every row that has
|
||||||
* been processed so far which has a known (minted) UUID for its item. This is used to help complete
|
* been processed so far which has a known (minted) UUID for its item. This is used to help complete
|
||||||
* the resolution after the row number has been determined.
|
* the resolution after the row number has been determined.
|
||||||
*
|
*
|
||||||
* @param line the csv line.
|
* @param line the csv line.
|
||||||
* @param rowNumber the row number.
|
|
||||||
* @param uuid the uuid of the item, which may be null if it has not been minted yet.
|
* @param uuid the uuid of the item, which may be null if it has not been minted yet.
|
||||||
*/
|
*/
|
||||||
private void populateRefAndRowMap(DSpaceCSVLine line, int rowNumber, @Nullable UUID uuid) {
|
private void populateRefAndRowMap(DSpaceCSVLine line, @Nullable UUID uuid) {
|
||||||
if (uuid != null) {
|
if (uuid != null) {
|
||||||
csvRowMap.put(rowNumber, uuid);
|
csvRowMap.put(rowCount, uuid);
|
||||||
|
} else {
|
||||||
|
csvRowMap.put(rowCount, new UUID(0, rowCount));
|
||||||
}
|
}
|
||||||
for (String key : line.keys()) {
|
for (String key : line.keys()) {
|
||||||
if (key.contains(".") && !key.split("\\.")[0].equalsIgnoreCase("relation") ||
|
if (key.contains(".") && !key.split("\\.")[0].equalsIgnoreCase("relation") ||
|
||||||
@@ -1667,22 +1538,31 @@ public class MetadataImport {
|
|||||||
rowNums = new HashSet<>();
|
rowNums = new HashSet<>();
|
||||||
csvRefMap.put(valueKey, rowNums);
|
csvRefMap.put(valueKey, rowNums);
|
||||||
}
|
}
|
||||||
rowNums.add(rowNumber);
|
rowNums.add(rowCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Populate entityTypeMap
|
||||||
|
if (key.equalsIgnoreCase("relationship.type") && line.get(key).size() > 0) {
|
||||||
|
if (uuid == null) {
|
||||||
|
entityTypeMap.put(new UUID(0, rowCount), line.get(key).get(0));
|
||||||
|
} else {
|
||||||
|
entityTypeMap.put(uuid, line.get(key).get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the UUID of the item indicated by the given reference, which may be a direct UUID string, a row reference
|
* Gets the UUID of the item indicated by the given target reference,
|
||||||
|
* which may be a direct UUID string, a row reference
|
||||||
* of the form rowName:VALUE, or a metadata value reference of the form schema.element[.qualifier]:VALUE.
|
* of the form rowName:VALUE, or a metadata value reference of the form schema.element[.qualifier]:VALUE.
|
||||||
*
|
*
|
||||||
* The reference may refer to a previously-processed item in the CSV or an item in the database.
|
* The reference may refer to a previously-processed item in the CSV or an item in the database.
|
||||||
*
|
*
|
||||||
* @param context the context to use.
|
* @param context the context to use.
|
||||||
* @param reference the reference which may be a UUID, metadata reference, or rowName reference.
|
* @param reference the target reference which may be a UUID, metadata reference, or rowName reference.
|
||||||
* @return the uuid.
|
* @return the uuid.
|
||||||
* @throws MetadataImportException if the reference is malformed or ambiguous (refers to multiple items).
|
* @throws MetadataImportException if the target reference is malformed or ambiguous (refers to multiple items).
|
||||||
*/
|
*/
|
||||||
private UUID resolveEntityRef(Context context, String reference) throws MetadataImportException {
|
private UUID resolveEntityRef(Context context, String reference) throws MetadataImportException {
|
||||||
// value reference
|
// value reference
|
||||||
@@ -1692,7 +1572,8 @@ public class MetadataImport {
|
|||||||
try {
|
try {
|
||||||
return UUID.fromString(reference);
|
return UUID.fromString(reference);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new MetadataImportException("Not a UUID or indirect entity reference: '" + reference + "'");
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Not a UUID or indirect entity reference: '" + reference + "'");
|
||||||
}
|
}
|
||||||
} else if (!reference.startsWith("rowName:") ) { // Not a rowName ref; so it's a metadata value reference
|
} else if (!reference.startsWith("rowName:") ) { // Not a rowName ref; so it's a metadata value reference
|
||||||
MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
|
MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
|
||||||
@@ -1702,7 +1583,8 @@ public class MetadataImport {
|
|||||||
String mfValue = reference.substring(i + 1);
|
String mfValue = reference.substring(i + 1);
|
||||||
String mf[] = reference.substring(0, i).split("\\.");
|
String mf[] = reference.substring(0, i).split("\\.");
|
||||||
if (mf.length < 2) {
|
if (mf.length < 2) {
|
||||||
throw new MetadataImportException("Bad metadata field in reference: '" + reference
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Bad metadata field in reference: '" + reference
|
||||||
+ "' (expected syntax is schema.element[.qualifier])");
|
+ "' (expected syntax is schema.element[.qualifier])");
|
||||||
}
|
}
|
||||||
String schema = mf[0];
|
String schema = mf[0];
|
||||||
@@ -1715,11 +1597,13 @@ public class MetadataImport {
|
|||||||
MetadataValue mdvVal = mdv.next();
|
MetadataValue mdvVal = mdv.next();
|
||||||
uuid = mdvVal.getDSpaceObject().getID();
|
uuid = mdvVal.getDSpaceObject().getID();
|
||||||
if (mdv.hasNext()) {
|
if (mdv.hasNext()) {
|
||||||
throw new MetadataImportException("Ambiguous reference; multiple matches in db: " + reference);
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Ambiguous reference; multiple matches in db: " + reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
throw new MetadataImportException("Error looking up item by metadata reference: " + reference, e);
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Error looking up item by metadata reference: " + reference, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Lookup UUIDs that may have already been processed into the csvRefMap
|
// Lookup UUIDs that may have already been processed into the csvRefMap
|
||||||
@@ -1727,20 +1611,23 @@ public class MetadataImport {
|
|||||||
// See getMatchingCSVUUIDs() for how the reference param is sourced from the csvRefMap
|
// See getMatchingCSVUUIDs() for how the reference param is sourced from the csvRefMap
|
||||||
Set<UUID> csvUUIDs = getMatchingCSVUUIDs(reference);
|
Set<UUID> csvUUIDs = getMatchingCSVUUIDs(reference);
|
||||||
if (csvUUIDs.size() > 1) {
|
if (csvUUIDs.size() > 1) {
|
||||||
throw new MetadataImportException("Ambiguous reference; multiple matches in csv: " + reference);
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Ambiguous reference; multiple matches in csv: " + reference);
|
||||||
} else if (csvUUIDs.size() == 1) {
|
} else if (csvUUIDs.size() == 1) {
|
||||||
UUID csvUUID = csvUUIDs.iterator().next();
|
UUID csvUUID = csvUUIDs.iterator().next();
|
||||||
if (csvUUID.equals(uuid)) {
|
if (csvUUID.equals(uuid)) {
|
||||||
return uuid; // one match from csv and db (same item)
|
return uuid; // one match from csv and db (same item)
|
||||||
} else if (uuid != null) {
|
} else if (uuid != null) {
|
||||||
throw new MetadataImportException("Ambiguous reference; multiple matches in db and csv: " + reference);
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
|
"Ambiguous reference; multiple matches in db and csv: " + reference);
|
||||||
} else {
|
} else {
|
||||||
return csvUUID; // one match from csv
|
return csvUUID; // one match from csv
|
||||||
}
|
}
|
||||||
} else { // size == 0; the reference does not exist throw an error
|
} else { // size == 0; the reference does not exist throw an error
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
throw new MetadataImportException("No matches found for reference: " + reference
|
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
|
||||||
+ ", Keep in mind you can only reference entries that are listed before " +
|
"No matches found for reference: " + reference
|
||||||
|
+ "\nKeep in mind you can only reference entries that are listed before " +
|
||||||
"this one within the CSV.");
|
"this one within the CSV.");
|
||||||
} else {
|
} else {
|
||||||
return uuid; // one match from db
|
return uuid; // one match from db
|
||||||
@@ -1780,4 +1667,167 @@ public class MetadataImport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a UUID of the origin in process or a placeholder for the origin to be evaluated later
|
||||||
|
*
|
||||||
|
* @param originId UUID of the origin
|
||||||
|
* @return the UUID of the item or UUID placeholder
|
||||||
|
*/
|
||||||
|
private UUID evaluateOriginId(@Nullable UUID originId) {
|
||||||
|
if (originId != null) {
|
||||||
|
return originId;
|
||||||
|
} else {
|
||||||
|
return new UUID(0, rowCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate every relation modification expressed in the CSV.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void validateExpressedRelations() throws MetadataImportException {
|
||||||
|
for (String targetUUID : entityRelationMap.keySet()) {
|
||||||
|
String targetType = null;
|
||||||
|
try {
|
||||||
|
// Get the type of reference. Attempt lookup in processed map first before looking in archive.
|
||||||
|
if (entityTypeMap.get(UUID.fromString(targetUUID)) != null) {
|
||||||
|
targetType = entityTypeService.
|
||||||
|
findByEntityType(c, entityTypeMap.get(UUID.fromString(targetUUID))).getLabel();
|
||||||
|
} else {
|
||||||
|
// Target item may be archived; check there.
|
||||||
|
// Add to errors if Realtionship.type cannot be derived
|
||||||
|
Item targetItem = null;
|
||||||
|
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
|
||||||
|
targetItem = itemService.find(c, UUID.fromString(targetUUID));
|
||||||
|
List<MetadataValue> relTypes = itemService.
|
||||||
|
getMetadata(targetItem, "relationship", "type", null, Item.ANY);
|
||||||
|
String relTypeValue = null;
|
||||||
|
if (relTypes.size() > 0) {
|
||||||
|
relTypeValue = relTypes.get(0).getValue();
|
||||||
|
targetType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
|
||||||
|
} else {
|
||||||
|
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
|
||||||
|
targetUUID);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
|
||||||
|
targetUUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetType == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Get labels for each origin referer of this target.
|
||||||
|
for (String label : entityRelationMap.get(targetUUID).keySet()) {
|
||||||
|
// Resolve Entity Type for each origin referer.
|
||||||
|
for (String originRefererUUID : entityRelationMap.get(targetUUID).get(label)) {
|
||||||
|
// Evaluate row number for origin referer.
|
||||||
|
String originRow = "N/A";
|
||||||
|
if (csvRowMap.containsValue(UUID.fromString(originRefererUUID))) {
|
||||||
|
for (int key : csvRowMap.keySet()) {
|
||||||
|
if (csvRowMap.get(key).toString().equalsIgnoreCase(originRefererUUID)) {
|
||||||
|
originRow = key + "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String originType = "";
|
||||||
|
// Validate target type and origin type pairing with label or add to errors.
|
||||||
|
// Attempt lookup in processed map first before looking in archive.
|
||||||
|
if (entityTypeMap.get(UUID.fromString(originRefererUUID)) != null) {
|
||||||
|
originType = entityTypeMap.get(UUID.fromString(originRefererUUID));
|
||||||
|
validateTypesByTypeByLabel(targetType, originType, label, originRow);
|
||||||
|
} else {
|
||||||
|
// Origin item may be archived; check there.
|
||||||
|
// Add to errors if Realtionship.type cannot be derived.
|
||||||
|
Item originItem = null;
|
||||||
|
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
|
||||||
|
originItem = itemService.find(c, UUID.fromString(originRefererUUID));
|
||||||
|
List<MetadataValue> relTypes = itemService.
|
||||||
|
getMetadata(originItem, "relationship", "type", null, Item.ANY);
|
||||||
|
String relTypeValue = null;
|
||||||
|
if (relTypes.size() > 0) {
|
||||||
|
relTypeValue = relTypes.get(0).getValue();
|
||||||
|
originType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
|
||||||
|
validateTypesByTypeByLabel(targetType, originType, label, originRow);
|
||||||
|
} else {
|
||||||
|
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
|
||||||
|
"Cannot resolve Entity type for reference: "
|
||||||
|
+ originRefererUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
|
||||||
|
"Cannot resolve Entity type for reference: "
|
||||||
|
+ originRefererUUID + " in row: " + originRow );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
throw new MetadataImportException("Error interacting with database!", sqle);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // If relationValidationErrors is empty all described relationships are valid.
|
||||||
|
if (!relationValidationErrors.isEmpty()) {
|
||||||
|
StringBuilder errors = new StringBuilder();
|
||||||
|
for (String error : relationValidationErrors) {
|
||||||
|
errors.append(error + "\n");
|
||||||
|
}
|
||||||
|
throw new MetadataImportException("Error validating relationships: \n" + errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a list of potenital Relationship Types given a label and attempts to match the given
|
||||||
|
* targetType and originType to a Relationship Type in the list.
|
||||||
|
*
|
||||||
|
* @param targetType entity type of target.
|
||||||
|
* @param originType entity type of origin referer.
|
||||||
|
* @param label left or right label of the respective Relationship.
|
||||||
|
* @return the UUID of the item.
|
||||||
|
*/
|
||||||
|
private void validateTypesByTypeByLabel(String targetType, String originType, String label, String originRow)
|
||||||
|
throws MetadataImportException {
|
||||||
|
try {
|
||||||
|
RelationshipType foundRelationshipType = null;
|
||||||
|
List<RelationshipType> relationshipTypeList = relationshipTypeService.
|
||||||
|
findByLeftOrRightLabel(c, label.split("\\.")[1]);
|
||||||
|
// Validate described relationship form the CSV.
|
||||||
|
foundRelationshipType = matchRelationshipType(relationshipTypeList, targetType, originType);
|
||||||
|
if (foundRelationshipType == null) {
|
||||||
|
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
|
||||||
|
"No Relationship type found for:\n" +
|
||||||
|
"Target type: " + targetType + "\n" +
|
||||||
|
"Origin referer type: " + originType + "\n" +
|
||||||
|
"with label: " + label);
|
||||||
|
}
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
throw new MetadataImportException("Error interacting with database!", sqle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches two Entity types to a Relationship Type from a set of Relationship Types.
|
||||||
|
*
|
||||||
|
* @param relTypes set of Relationship Types.
|
||||||
|
* @param typeOne first type to be used in matching.
|
||||||
|
* @param typeTwo second item to be used in matching.
|
||||||
|
* @return null or matched Relationship Type.
|
||||||
|
*/
|
||||||
|
private RelationshipType matchRelationshipType(List<RelationshipType> relTypes,
|
||||||
|
String typeOne, String typeTwo) {
|
||||||
|
RelationshipType foundRelationshipType = null;
|
||||||
|
for (RelationshipType relationshipType : relTypes) {
|
||||||
|
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(typeOne) &&
|
||||||
|
relationshipType.getRightType().getLabel().equalsIgnoreCase(typeTwo) ||
|
||||||
|
relationshipType.getLeftType().getLabel().equalsIgnoreCase(typeTwo) &&
|
||||||
|
relationshipType.getRightType().getLabel().equalsIgnoreCase(typeOne)) {
|
||||||
|
foundRelationshipType = relationshipType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundRelationshipType;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -33,7 +33,6 @@ import org.dspace.content.service.ItemService;
|
|||||||
import org.dspace.content.service.MetadataFieldService;
|
import org.dspace.content.service.MetadataFieldService;
|
||||||
import org.dspace.content.service.MetadataValueService;
|
import org.dspace.content.service.MetadataValueService;
|
||||||
import org.dspace.content.service.RelationshipService;
|
import org.dspace.content.service.RelationshipService;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -63,13 +62,6 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
.withName("Parent Community")
|
.withName("Parent Community")
|
||||||
.build();
|
.build();
|
||||||
col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
|
col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close testing enviorment and restore auth system
|
|
||||||
*/
|
|
||||||
@After
|
|
||||||
public void close() {
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,9 +172,11 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testSingleUUIDReference() throws Exception {
|
public void testSingleUUIDReference() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
Item person = ItemBuilder.createItem(context, col1)
|
Item person = ItemBuilder.createItem(context, col1)
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.build();
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName,dc.identifier.other",
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName,dc.identifier.other",
|
||||||
"+,Publication," + person.getID().toString() + "," + col1.getHandle() + ",anything,0"};
|
"+,Publication," + person.getID().toString() + "," + col1.getHandle() + ",anything,0"};
|
||||||
Item[] items = runImport(csv);
|
Item[] items = runImport(csv);
|
||||||
@@ -195,12 +189,14 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testMultiUUIDReference() throws Exception {
|
public void testMultiUUIDReference() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
Item person = ItemBuilder.createItem(context, col1)
|
Item person = ItemBuilder.createItem(context, col1)
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.build();
|
.build();
|
||||||
Item person2 = ItemBuilder.createItem(context, col1)
|
Item person2 = ItemBuilder.createItem(context, col1)
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.build();
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName,dc.identifier.other",
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName,dc.identifier.other",
|
||||||
"+,Publication," + person.getID().toString() + "||" + person2.getID().toString() + "," +
|
"+,Publication," + person.getID().toString() + "||" + person2.getID().toString() + "," +
|
||||||
col1.getHandle() + ",anything,0"};
|
col1.getHandle() + ",anything,0"};
|
||||||
@@ -215,6 +211,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testMultiRefArchivedCsv() throws Exception {
|
public void testMultiRefArchivedCsv() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
Item person = ItemBuilder.createItem(context, col1)
|
Item person = ItemBuilder.createItem(context, col1)
|
||||||
.withTitle("Person")
|
.withTitle("Person")
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
@@ -223,6 +220,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
"dc.identifier.other",
|
"dc.identifier.other",
|
||||||
"+,Person2,Person,," + col1.getHandle() + ",idVal,0",
|
"+,Person2,Person,," + col1.getHandle() + ",idVal,0",
|
||||||
"+,Pub1,Publication,dc.title:Person||dc.title:Person2," + col1.getHandle() + ",anything,1"};
|
"+,Pub1,Publication,dc.title:Person||dc.title:Person2," + col1.getHandle() + ",anything,1"};
|
||||||
|
context.restoreAuthSystemState();
|
||||||
Item[] items = runImport(csv);
|
Item[] items = runImport(csv);
|
||||||
assertRelationship(items[1], person, 1, "left", 0);
|
assertRelationship(items[1], person, 1, "left", 0);
|
||||||
assertRelationship(items[1], items[0], 1, "left", 1);
|
assertRelationship(items[1], items[0], 1, "left", 1);
|
||||||
@@ -235,6 +233,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testMultiMixedRefArchivedCsv() throws Exception {
|
public void testMultiMixedRefArchivedCsv() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
Item person = ItemBuilder.createItem(context, col1)
|
Item person = ItemBuilder.createItem(context, col1)
|
||||||
.withTitle("Person")
|
.withTitle("Person")
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
@@ -243,6 +242,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
.withTitle("Person2")
|
.withTitle("Person2")
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.build();
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
String[] csv = {"id,dc.title,relationship.type,relation.isAuthorOfPublication,collection,rowName," +
|
String[] csv = {"id,dc.title,relationship.type,relation.isAuthorOfPublication,collection,rowName," +
|
||||||
"dc.identifier.other",
|
"dc.identifier.other",
|
||||||
"+,Person3,Person,," + col1.getHandle() + ",idVal,0",
|
"+,Person3,Person,," + col1.getHandle() + ",idVal,0",
|
||||||
@@ -297,6 +297,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNonUniqueMDRefInDb() throws Exception {
|
public void testNonUniqueMDRefInDb() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
ItemBuilder.createItem(context, col1)
|
ItemBuilder.createItem(context, col1)
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.withIdentifierOther("1")
|
.withIdentifierOther("1")
|
||||||
@@ -305,6 +306,7 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.withIdentifierOther("1")
|
.withIdentifierOther("1")
|
||||||
.build();
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,dc.identifier.other",
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,dc.identifier.other",
|
||||||
"+,Publication,dc.identifier.other:1," + col1.getHandle() + ",2"};
|
"+,Publication,dc.identifier.other:1," + col1.getHandle() + ",2"};
|
||||||
assertEquals(1, performImportScript(csv, true));
|
assertEquals(1, performImportScript(csv, true));
|
||||||
@@ -315,10 +317,12 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNonUniqueMDRefInBoth() throws Exception {
|
public void testNonUniqueMDRefInBoth() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
ItemBuilder.createItem(context, col1)
|
ItemBuilder.createItem(context, col1)
|
||||||
.withRelationshipType("Person")
|
.withRelationshipType("Person")
|
||||||
.withIdentifierOther("1")
|
.withIdentifierOther("1")
|
||||||
.build();
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,dc.identifier.other",
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,dc.identifier.other",
|
||||||
"+,Person,," + col1.getHandle() + ",1",
|
"+,Person,," + col1.getHandle() + ",1",
|
||||||
"+,Publication,dc.identifier.other:1," + col1.getHandle() + ",2"};
|
"+,Publication,dc.identifier.other:1," + col1.getHandle() + ",2"};
|
||||||
@@ -358,6 +362,78 @@ public class CSVMetadataImportReferenceTest extends AbstractEntityIntegrationTes
|
|||||||
assertEquals(1, performImportScript(csv, false));
|
assertEquals(1, performImportScript(csv, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test relationship validation with invalid relationship definition
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCSVImportInvalidRelationship() throws Exception {
|
||||||
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName",
|
||||||
|
"+,Publication,," + col1.getHandle() + ",row1",
|
||||||
|
"+,Unit,rowName:row1," + col1.getHandle() + ",row2",};
|
||||||
|
assertEquals(1, performImportScript(csv, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test relationship validation with invalid relationship definition and with an archived origin referer
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInvalidRelationshipArchivedOrigin() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Item testItem = ItemBuilder.createItem(context, col1)
|
||||||
|
.withRelationshipType("OrgUnit")
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName",
|
||||||
|
"+,Person,," + col1.getHandle() + ",1",
|
||||||
|
testItem.getID().toString() + ",,rowName:1," + col1.getHandle() + ",2"};
|
||||||
|
assertEquals(1, performImportScript(csv, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test relationship validation with invalid relationship definition and with archived target reference
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInvalidRelationshipArchivedTarget() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Item testItem = ItemBuilder.createItem(context, col1)
|
||||||
|
.withRelationshipType("OrgUnit")
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String[] csv = {"id,relationship.type,relation.isAuthorOfPublication,collection,rowName",
|
||||||
|
testItem.getID().toString() + ",Person,," + col1.getHandle() + ",1",
|
||||||
|
"+,OrgUnit,rowName:1," + col1.getHandle() + ",2"};
|
||||||
|
assertEquals(1, performImportScript(csv, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test relationship validation against archived items with pre-existing relationship types
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testValidRelationshipNoDefinedTypesInCSV() throws Exception {
|
||||||
|
context.turnOffAuthorisationSystem();
|
||||||
|
Item testItemOne = ItemBuilder.createItem(context, col1)
|
||||||
|
.withRelationshipType("Person")
|
||||||
|
.withIdentifierOther("testItemOne")
|
||||||
|
.build();
|
||||||
|
Item testItemTwo = ItemBuilder.createItem(context, col1)
|
||||||
|
.withRelationshipType("Publication")
|
||||||
|
.withIdentifierOther("testItemTwo")
|
||||||
|
.build();
|
||||||
|
Item testItemThree = ItemBuilder.createItem(context, col1)
|
||||||
|
.withRelationshipType("Project")
|
||||||
|
.withIdentifierOther("testItemThree")
|
||||||
|
.build();
|
||||||
|
context.restoreAuthSystemState();
|
||||||
|
String[] csv = {"id,relation.isAuthorOfPublication,relation.isPublicationOfProject,collection",
|
||||||
|
testItemOne.getID().toString() + ",,," + col1.getHandle(),
|
||||||
|
testItemTwo.getID().toString() + ",dc.identifier.other:testItemOne,," + col1.getHandle(),
|
||||||
|
testItemThree.getID().toString() + ",,dc.identifier.other:testItemTwo," + col1.getHandle()};
|
||||||
|
performImportScript(csv, false);
|
||||||
|
assertRelationship(testItemTwo, testItemOne, 1, "left", 0);
|
||||||
|
assertRelationship(testItemTwo, testItemThree, 1, "left", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Import mocked CSVs to test item creation behavior, deleting temporary file afterward.
|
* Import mocked CSVs to test item creation behavior, deleting temporary file afterward.
|
||||||
|
@@ -26,7 +26,7 @@ dspace.dir = /dspace
|
|||||||
dspace.hostname = localhost
|
dspace.hostname = localhost
|
||||||
|
|
||||||
# DSpace base host URL. Include port number etc.
|
# DSpace base host URL. Include port number etc.
|
||||||
dspace.baseUrl = http://localhost:8080/server
|
dspace.baseUrl = http://localhost:8080
|
||||||
|
|
||||||
# Full link your end users will use to access DSpace. In most cases, this will be the baseurl followed by
|
# Full link your end users will use to access DSpace. In most cases, this will be the baseurl followed by
|
||||||
# the context path to the UI you are using.
|
# the context path to the UI you are using.
|
||||||
@@ -37,7 +37,7 @@ dspace.url = ${dspace.baseUrl}
|
|||||||
|
|
||||||
# This is the URL that will be used for the REST endpoints to be served on.
|
# This is the URL that will be used for the REST endpoints to be served on.
|
||||||
# This will typically be followed by /api to determine the root endpoints.
|
# This will typically be followed by /api to determine the root endpoints.
|
||||||
dspace.restUrl = ${dspace.baseUrl}
|
dspace.restUrl = ${dspace.baseUrl}/server
|
||||||
|
|
||||||
# Optional: DSpace URL for mobile access
|
# Optional: DSpace URL for mobile access
|
||||||
# This
|
# This
|
||||||
|
Reference in New Issue
Block a user