From f223f1c067697339b4a27b737d51b8629452ca59 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 16 Apr 2018 11:24:55 +0200 Subject: [PATCH 001/188] DSpace 7 Entities --- .../org/dspace/app/bulkedit/DSpaceCSV.java | 3 +- .../dspace/app/bulkedit/MetadataImport.java | 207 +++++++++- .../util/AdditionalRelationshipScript.java | 376 ++++++++++++++++++ .../dspace/app/util/InitializeEntities.java | 229 +++++++++++ .../content/DSpaceObjectServiceImpl.java | 13 +- .../main/java/org/dspace/content/Entity.java | 37 ++ .../org/dspace/content/EntityServiceImpl.java | 137 +++++++ .../java/org/dspace/content/EntityType.java | 48 +++ .../dspace/content/EntityTypeServiceImpl.java | 86 ++++ .../org/dspace/content/ItemServiceImpl.java | 163 +++++++- .../java/org/dspace/content/Relationship.java | 102 +++++ .../content/RelationshipServiceImpl.java | 289 ++++++++++++++ .../org/dspace/content/RelationshipType.java | 131 ++++++ .../content/RelationshipTypeServiceImpl.java | 87 ++++ .../org/dspace/content/dao/EntityTypeDAO.java | 20 + .../dspace/content/dao/RelationshipDAO.java | 25 ++ .../content/dao/RelationshipTypeDAO.java | 23 ++ .../content/dao/impl/EntityTypeDAOImpl.java | 29 ++ .../content/dao/impl/RelationshipDAOImpl.java | 62 +++ .../dao/impl/RelationshipTypeDAOImpl.java | 35 ++ .../factory/ContentServiceFactory.java | 12 + .../factory/ContentServiceFactoryImpl.java | 31 ++ .../dspace/content/service/EntityService.java | 33 ++ .../content/service/EntityTypeService.java | 25 ++ .../dspace/content/service/ItemService.java | 4 + .../content/service/RelationshipService.java | 29 ++ .../service/RelationshipTypeService.java | 27 ++ .../EntityTypeToFilterQueryService.java | 31 ++ .../virtual/VirtualMetadataPopulator.java | 23 ++ .../rdbms/DatabaseRegistryUpdater.java | 8 +- .../h2/V7.0_2018.04.16__dspace-entities.sql | 62 +++ .../V7.0_2018.04.16__dspace-entities.sql | 62 +++ .../V7.0_2018.04.16__dspace-entities.sql | 62 +++ .../config/entities/relationship-types.xml | 112 ++++++ .../app/rest/RootRestResourceController.java | 12 +- .../rest/converter/DSpaceObjectConverter.java | 12 +- .../converter/DiscoverResultConverter.java | 3 + .../rest/converter/EntityTypeConverter.java | 30 ++ .../FilteredDiscoveryPageConverter.java | 34 ++ .../app/rest/converter/ItemConverter.java | 36 ++ .../rest/converter/RelationshipConverter.java | 58 +++ .../converter/RelationshipTypeConverter.java | 52 +++ .../app/rest/converter/RootConverter.java | 4 +- .../dspace/app/rest/model/EntityTypeRest.java | 38 ++ .../rest/model/FilteredDiscoveryPageRest.java | 48 +++ .../org/dspace/app/rest/model/ItemRest.java | 11 + .../app/rest/model/RelationshipRest.java | 79 ++++ .../app/rest/model/RelationshipTypeRest.java | 106 +++++ .../rest/model/hateoas/DSpaceResource.java | 15 +- .../model/hateoas/EntityTypeResource.java | 19 + .../FilteredDiscoveryPageResource.java | 20 + .../model/hateoas/RelationshipResource.java | 19 + .../hateoas/RelationshipTypeResource.java | 19 + .../repository/EntityTypeRestRepository.java | 60 +++ .../FilteredDiscoveryPageRestRepository.java | 71 ++++ .../RelationshipRestRepository.java | 60 +++ .../RelationshipTypeRestRepository.java | 60 +++ .../rest/repository/RootRestRepository.java | 4 +- .../app/rest/EntityTypeRestRepositoryIT.java | 147 +++++++ .../rest/RelationshipRestRepositoryIT.java | 171 ++++++++ .../RelationshipTypeRestRepositoryIT.java | 265 ++++++++++++ .../SubmissionDefinitionsControllerIT.java | 6 +- .../rest/SubmissionSectionsControllerIT.java | 2 +- .../rest/SubmissionUploadsControllerIT.java | 2 +- .../app/rest/builder/AbstractBuilder.java | 3 + .../dspace/app/rest/builder/ItemBuilder.java | 4 + .../app/rest/builder/RelationshipBuilder.java | 80 ++++ .../app/rest/converter/RootConverterTest.java | 7 +- .../app/rest/matcher/BrowseIndexMatcher.java | 20 +- .../app/rest/matcher/EntityTypeMatcher.java | 56 +++ .../app/rest/matcher/RelationshipMatcher.java | 34 ++ .../rest/matcher/RelationshipTypeMatcher.java | 70 ++++ .../matcher/SubmissionDefinitionsMatcher.java | 4 +- .../AbstractControllerIntegrationTest.java | 18 +- dspace/config/dspace.cfg | 9 +- dspace/config/hibernate.cfg.xml | 4 + dspace/config/item-submission.xml | 57 +++ dspace/config/launcher.xml | 15 + dspace/config/modules/bulkedit.cfg | 2 +- dspace/config/registries/journal-types.xml | 55 +++ .../config/registries/journalissue-types.xml | 46 +++ .../config/registries/journalvolume-types.xml | 41 ++ dspace/config/registries/orgunit-types.xml | 55 +++ dspace/config/registries/person-types.xml | 61 +++ dspace/config/registries/project-types.xml | 61 +++ .../registries/relationship-formats.xml | 19 + .../config/spring/api/core-dao-services.xml | 3 + dspace/config/spring/api/core-services.xml | 102 ++++- dspace/config/spring/api/discovery.xml | 74 +++- dspace/config/submission-forms.xml | 315 +++++++++++++++ dspace/solr/search/conf/schema.xml | 3 + 91 files changed, 5224 insertions(+), 80 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/app/util/AdditionalRelationshipScript.java create mode 100644 dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java create mode 100644 dspace-api/src/main/java/org/dspace/content/Entity.java create mode 100644 dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/EntityType.java create mode 100644 dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/Relationship.java create mode 100644 dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/RelationshipType.java create mode 100644 dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/EntityTypeDAO.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java create mode 100644 dspace-api/src/main/java/org/dspace/content/service/EntityService.java create mode 100644 dspace-api/src/main/java/org/dspace/content/service/EntityTypeService.java create mode 100644 dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java create mode 100644 dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/EntityTypeToFilterQueryService.java create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql create mode 100644 dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/EntityTypeConverter.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/FilteredDiscoveryPageConverter.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/EntityTypeRest.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/FilteredDiscoveryPageRest.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRest.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRest.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/EntityTypeResource.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/FilteredDiscoveryPageResource.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipTypeResource.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/FilteredDiscoveryPageRestRepository.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipTypeRestRepository.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EntityTypeMatcher.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java create mode 100644 dspace/config/registries/journal-types.xml create mode 100644 dspace/config/registries/journalissue-types.xml create mode 100644 dspace/config/registries/journalvolume-types.xml create mode 100644 dspace/config/registries/orgunit-types.xml create mode 100644 dspace/config/registries/person-types.xml create mode 100644 dspace/config/registries/project-types.xml create mode 100644 dspace/config/registries/relationship-formats.xml diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java index e66c96782b..019cdd76cc 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java @@ -27,6 +27,7 @@ import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang.StringUtils; import org.dspace.authority.AuthorityValue; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; @@ -208,7 +209,7 @@ public class DSpaceCSV implements Serializable { // Check that the metadata element exists in the schema MetadataField foundField = metadataFieldService .findByElement(c, foundSchema, metadataElement, metadataQualifier); - if (foundField == null) { + if (foundField == null && !StringUtils.equals(metadataSchema, "relationship")) { throw new MetadataImportInvalidHeadingException(clean[0], MetadataImportInvalidHeadingException.ELEMENT, columnCounter); 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 9f94506980..7aac6fc8b9 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 @@ -15,6 +15,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.UUID; @@ -33,14 +34,22 @@ import org.dspace.authority.service.AuthorityValueService; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.DSpaceObject; +import org.dspace.content.Entity; +import org.dspace.content.EntityType; import org.dspace.content.Item; import org.dspace.content.MetadataValue; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; import org.dspace.content.WorkspaceItem; import org.dspace.content.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; +import org.dspace.content.service.EntityService; +import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; @@ -101,6 +110,10 @@ public class MetadataImport { protected final CollectionService collectionService; protected final HandleService handleService; protected final WorkspaceItemService workspaceItemService; + protected final RelationshipTypeService relationshipTypeService; + protected final RelationshipService relationshipService; + protected final EntityTypeService entityTypeService; + protected final EntityService entityService; /** * Create an instance of the metadata importer. Requires a context and an array of CSV lines @@ -120,6 +133,10 @@ public class MetadataImport { handleService = HandleServiceFactory.getInstance().getHandleService(); authorityValueService = AuthorityServiceFactory.getInstance().getAuthorityValueService(); workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); + relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); + relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService(); + entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService(); + entityService = ContentServiceFactory.getInstance().getEntityService(); } /** @@ -336,16 +353,30 @@ public class MetadataImport { item = wsItem.getItem(); // Add the metadata to the item + List 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()); + if (StringUtils.equals(dcv.getSchema(), "relationship")) { + + 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? if (useWorkflow) { WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService(); @@ -396,6 +427,19 @@ public class MetadataImport { return changes; } + private void handleRelationshipMetadataValueFromBulkEditMetadataValue(Item item, BulkEditMetadataValue dcv) + throws SQLException, AuthorizeException { + LinkedList values = new LinkedList<>(); + values.add(dcv.getValue()); + LinkedList authorities = new LinkedList<>(); + authorities.add(dcv.getAuthority()); + LinkedList 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 * @@ -583,9 +627,154 @@ public class MetadataImport { } } - // Set those values + + if (StringUtils.equals(schema, "relationship")) { + handleRelationMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences); + } else { + itemService.clearMetadata(c, item, schema, element, qualifier, language); + itemService.addMetadata(c, item, schema, element, qualifier, + language, values, authorities, confidences); + itemService.update(c, item); + } + } + } + + private void handleRelationMetadata(Context c, Item item, String schema, String element, String qualifier, + String language, List values, List authorities, + List confidences) throws SQLException, AuthorizeException { + + if (StringUtils.equals(element, "type") && StringUtils.isBlank(qualifier)) { + handleRelationTypeMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences); + + } else { + handleRelationOtherMetadata(c, item, element, values); + } + + } + + private void handleRelationOtherMetadata(Context c, Item item, String element, List values) + throws SQLException, AuthorizeException { + Entity entity = entityService.findByItemId(c, item.getID()); + boolean left = false; + List acceptableRelationshipTypes = new LinkedList<>(); + String[] components = values.get(0).split("-"); + String url = handleService.resolveToURL(c, values.get(0)); + if (components.length != 5 && StringUtils.isNotBlank(url)) { + return; + } + + Entity relationEntity = entityService.findByItemId(c, UUID.fromString(values.get(0))); + + + List leftRelationshipTypesForEntity = entityService.getLeftRelationshipTypes(c, entity); + List rightRelationshipTypesForEntity = entityService.getRightRelationshipTypes(c, entity); + + for (RelationshipType relationshipType : entityService.getAllRelationshipTypes(c, entity)) { + if (StringUtils.equalsIgnoreCase(relationshipType.getLeftLabel(), element)) { + left = handleLeftLabelEqualityRelationshipTypeElement(c, entity, relationEntity, left, + acceptableRelationshipTypes, + leftRelationshipTypesForEntity, + relationshipType); + } else if (StringUtils.equalsIgnoreCase(relationshipType.getRightLabel(), element)) { + left = handleRightLabelEqualityRelationshipTypeElement(c, entity, relationEntity, left, + acceptableRelationshipTypes, + rightRelationshipTypesForEntity, + relationshipType); + } + } + + if (acceptableRelationshipTypes.size() > 1) { + System.out.println("Ambiguous relationship_types were found"); + log.error("Ambiguous relationship_types were found"); + return; + } + if (acceptableRelationshipTypes.size() == 0) { + System.out.println("no relationship_types were found"); + log.error("no relationship_types were found"); + return; + } + + buildRelationObject(c, item, values, left, acceptableRelationshipTypes); + } + + private void buildRelationObject(Context c, Item item, List values, boolean left, + List acceptableRelationshipTypes) + throws SQLException, AuthorizeException { + Relationship relationship = new Relationship(); + RelationshipType acceptedRelationshipType = acceptableRelationshipTypes.get(0); + if (left) { + relationship.setLeftItem(item); + relationship.setRightItem(itemService.findByIdOrLegacyId(c, values.get(0))); + } else { + relationship.setRightItem(item); + relationship.setLeftItem(itemService.findByIdOrLegacyId(c, values.get(0))); + } + relationship.setRelationshipType(acceptedRelationshipType); + relationship.setLeftPlace(relationshipService.findLeftPlaceByLeftItem(c, relationship.getLeftItem()) + 1); + relationship.setRightPlace(relationshipService.findRightPlaceByRightItem(c, relationship.getLeftItem()) + 1); + Relationship persistedRelationship = relationshipService.create(c, relationship); + relationshipService.update(c, persistedRelationship); + } + + private boolean handleRightLabelEqualityRelationshipTypeElement(Context c, Entity entity, Entity relationEntity, + boolean left, + List acceptableRelationshipTypes, + List + 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; + } + + private boolean handleLeftLabelEqualityRelationshipTypeElement(Context c, Entity entity, Entity relationEntity, + boolean left, + List acceptableRelationshipTypes, + List + 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; + } + + private void handleRelationTypeMetadata(Context c, Item item, String schema, String element, String qualifier, + String language, List values, List authorities, + List 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.addMetadata(c, item, schema, element, qualifier, language, + values, authorities, confidences); itemService.update(c, item); } } diff --git a/dspace-api/src/main/java/org/dspace/app/util/AdditionalRelationshipScript.java b/dspace-api/src/main/java/org/dspace/app/util/AdditionalRelationshipScript.java new file mode 100644 index 0000000000..ee45139aaf --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/AdditionalRelationshipScript.java @@ -0,0 +1,376 @@ +/** + * 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.sql.SQLException; + +import org.apache.commons.cli.ParseException; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; + +public class AdditionalRelationshipScript { + + private RelationshipTypeService relationshipTypeService; + private RelationshipService relationshipService; + private EntityTypeService entityTypeService; + private ItemService itemService; + + private AdditionalRelationshipScript() { + relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService(); + relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); + entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService(); + itemService = ContentServiceFactory.getInstance().getItemService(); + } + + public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException { + AdditionalRelationshipScript additionalRelationshipScript = new AdditionalRelationshipScript(); + additionalRelationshipScript.execute(); + } + + private void execute() throws SQLException, AuthorizeException { + Context context = new Context(); + context.turnOffAuthorisationSystem(); + + //(left label) -> isAuthorOfPublication => Publication is leftItem + + Item article1 = itemService.findByIdOrLegacyId(context, "e98b0f27-5c19-49a0-960d-eb6ad5287067"); + Item article2 = itemService.findByIdOrLegacyId(context, "96715576-3748-4761-ad45-001646632963"); + Item article3 = itemService.findByIdOrLegacyId(context, "047556d1-3d01-4c53-bc68-0cee7ad7ed4e"); + Item article4 = itemService.findByIdOrLegacyId(context, "2f4ec582-109e-4952-a94a-b7d7615a8c69"); + Item article5 = itemService.findByIdOrLegacyId(context, "99c2e55c-6326-4442-9f36-fcac333b0e8c"); + Item article6 = itemService.findByIdOrLegacyId(context, "e7bd0d24-e83a-486a-bc0c-8aaaeb19dc7d"); + Item article7 = itemService.findByIdOrLegacyId(context, "72635f7f-37b5-4875-b4f2-5ff45d97a09b"); + Item article8 = itemService.findByIdOrLegacyId(context, "674f695e-8001-4150-8f9c-095c536a6bcb"); + Item article9 = itemService.findByIdOrLegacyId(context, "a64719f8-ba7b-41d1-8eb6-f8feb0c000b7"); + + Item author1 = itemService.findByIdOrLegacyId(context, "0ffbee3f-e7ea-42bc-92fe-2fbef1a52c0f"); + Item author2 = itemService.findByIdOrLegacyId(context, "5a3f7c7a-d3df-419c-b8a2-f00ede62c60a"); + Item author3 = itemService.findByIdOrLegacyId(context, "f2235aa6-6fe7-4174-a690-598b72dd8e44"); + + Item orgUnit1 = itemService.findByIdOrLegacyId(context, "d30de96b-1e76-40ae-8ef9-ab426b6f9763"); + Item orgUnit2 = itemService.findByIdOrLegacyId(context, "506a7e54-8d7c-4d5b-8636-d5f6411483de"); + Item orgUnit3 = itemService.findByIdOrLegacyId(context, "c216201f-ed10-4361-b0e0-5a065405bd3e"); + + Item project1 = itemService.findByIdOrLegacyId(context, "0de99067-c898-4d02-a82c-9555f3311288"); + Item project2 = itemService.findByIdOrLegacyId(context, "b1bc3a49-49b1-417a-ac90-8d5c7ba5e0ac"); + Item project3 = itemService.findByIdOrLegacyId(context, "18e7924c-f15b-4953-9fe3-3de370bccc97"); + + Item journal1 = itemService.findByIdOrLegacyId(context, "d4af6c3e-53d0-4757-81eb-566f3b45d63a"); + Item journal2 = itemService.findByIdOrLegacyId(context, "a23eae5a-7857-4ef9-8e52-989436ad2955"); + + Item journalVolume1OfJournal1 = itemService.findByIdOrLegacyId(context, "07c6249f-4bf7-494d-9ce3-6ffdb2aed538"); + Item journalVolume2OfJournal1 = itemService.findByIdOrLegacyId(context, "66bb4e5d-b419-42b7-a648-f270a527f17c"); + + Item journalVolume1OfJournal2 = itemService.findByIdOrLegacyId(context, "f9b89a11-b44e-4a64-a3b4-ab24a33553c7"); + Item journalVolume2OfJournal2 = itemService.findByIdOrLegacyId(context, "343d3263-2733-4367-9dc4-216a01b4a461"); + + Item journalIssue1OfJournalVolume1OfJournal1 = itemService.findByIdOrLegacyId + (context, "44c29473-5de2-48fa-b005-e5029aa1a50b"); + Item journalIssue2OfJournalVolume1OfJournal1 = itemService.findByIdOrLegacyId + (context, "c3076837-e5df-4221-80bc-2661cd390a7b"); + Item journalIssue1OfJournalVolume2OfJournal1 = itemService.findByIdOrLegacyId + (context, "a4a63ab5-8c0b-4456-b5f7-5b5d9828cb69"); + + Item journalIssue1OfJournalVolume1OfJournal2 = itemService.findByIdOrLegacyId + (context, "77877343-3f75-4c33-9492-6ed7c98ed84e"); + Item journalIssue2OfJournalVolume1OfJournal2 = itemService.findByIdOrLegacyId + (context, "f4dcd8a6-4cc4-4806-8bb9-a7e8202e05b0"); + Item journalIssue1OfJournalVolume2OfJournal2 = itemService.findByIdOrLegacyId + (context, "b7003f66-80e9-4c98-99a2-3695e8150b80"); + Item journalIssue2OfJournalVolume2OfJournal2 = itemService.findByIdOrLegacyId + (context, "db55298c-a21f-4677-8793-a21f1194a226"); + + RelationshipType isAuthorOfPublication = relationshipTypeService.find(context, 1); + RelationshipType isProjectOfPublication = relationshipTypeService.find(context, 2); + RelationshipType isOrgUnitOfPublication = relationshipTypeService.find(context, 3); + RelationshipType isProjectOfPerson = relationshipTypeService.find(context, 4); + RelationshipType isOrgUnitOfPerson = relationshipTypeService.find(context, 5); + RelationshipType isOrgUnitOfProject = relationshipTypeService.find(context, 6); + RelationshipType isVolumeOfJournal = relationshipTypeService.find(context, 7); + RelationshipType isIssueOfJournalVolume = relationshipTypeService.find(context, 8); + RelationshipType isPublicationOfJournalIssue = relationshipTypeService.find(context, 9); + + RelationshipType isAuthorOfPublicationNew = relationshipTypeService.find(context, 10); + constructRelationshipAndStore(context, article1, orgUnit1, isAuthorOfPublicationNew, 1); + constructRelationshipAndStore(context, article1, orgUnit2, isAuthorOfPublicationNew, 1); + constructRelationshipAndStore(context, article1, orgUnit3, isAuthorOfPublicationNew, 1); + + constructRelationshipAndStore(context, article1, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article1, author2, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article1, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article2, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article2, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article3, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article4, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article4, author2, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article4, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article5, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article6, author2, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article6, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article7, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article7, author2, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article7, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article8, author2, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article9, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article9, author1, isAuthorOfPublication, 1); + + constructRelationshipAndStore(context, article1, project1, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article6, project1, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article7, project1, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article1, project2, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article9, project3, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article8, project3, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article4, project3, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article5, project3, isProjectOfPublication, 1); + constructRelationshipAndStore(context, article2, project3, isProjectOfPublication, 1); + + constructRelationshipAndStore(context, article1, orgUnit1, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article1, orgUnit2, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article1, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article2, orgUnit1, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article2, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article3, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article4, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article4, orgUnit2, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article4, orgUnit1, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article5, orgUnit1, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article6, orgUnit2, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article6, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article7, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article7, orgUnit2, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article7, orgUnit1, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article8, orgUnit2, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article9, orgUnit3, isOrgUnitOfPublication, 1); + constructRelationshipAndStore(context, article9, orgUnit1, isOrgUnitOfPublication, 1); + + constructRelationshipAndStore(context, project1, orgUnit1, isOrgUnitOfProject, 1); + constructRelationshipAndStore(context, project2, orgUnit2, isOrgUnitOfProject, 1); + constructRelationshipAndStore(context, project3, orgUnit2, isOrgUnitOfProject, 1); + constructRelationshipAndStore(context, project2, orgUnit3, isOrgUnitOfProject, 1); + constructRelationshipAndStore(context, project1, orgUnit3, isOrgUnitOfProject, 1); + constructRelationshipAndStore(context, project3, orgUnit3, isOrgUnitOfProject, 1); + + + constructRelationshipAndStore(context, author1, project1, isProjectOfPerson, 1); + constructRelationshipAndStore(context, author2, project2, isProjectOfPerson, 1); + constructRelationshipAndStore(context, author2, project3, isProjectOfPerson, 1); + constructRelationshipAndStore(context, author3, project1, isProjectOfPerson, 1); + constructRelationshipAndStore(context, author3, project2, isProjectOfPerson, 1); + constructRelationshipAndStore(context, author3, project3, isProjectOfPerson, 1); + + constructRelationshipAndStore(context, author1,orgUnit1 ,isOrgUnitOfPerson, 1); + constructRelationshipAndStore(context, author2,orgUnit2 ,isOrgUnitOfPerson, 1); + constructRelationshipAndStore(context, author2,orgUnit3 ,isOrgUnitOfPerson, 1); + constructRelationshipAndStore(context, author3,orgUnit1 ,isOrgUnitOfPerson, 1); + constructRelationshipAndStore(context, author3,orgUnit2 ,isOrgUnitOfPerson, 1); + constructRelationshipAndStore(context, author3,orgUnit3 ,isOrgUnitOfPerson, 1); + + constructRelationshipAndStore(context, journal1, journalVolume1OfJournal1, isVolumeOfJournal, 1); + constructRelationshipAndStore(context, journal1, journalVolume2OfJournal1, isVolumeOfJournal, 1); + + constructRelationshipAndStore(context, journal2, journalVolume1OfJournal2, isVolumeOfJournal, 1); + constructRelationshipAndStore(context, journal2, journalVolume2OfJournal2, isVolumeOfJournal, 1); + + + constructRelationshipAndStore(context, journalVolume1OfJournal1, + journalIssue1OfJournalVolume1OfJournal1, isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal1, + journalIssue2OfJournalVolume1OfJournal1, isIssueOfJournalVolume, 1); + + constructRelationshipAndStore(context, journalVolume2OfJournal1, + journalIssue1OfJournalVolume2OfJournal1, isIssueOfJournalVolume, 1); + + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue1OfJournalVolume1OfJournal2,isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue2OfJournalVolume1OfJournal2,isIssueOfJournalVolume, 1); + + constructRelationshipAndStore(context, journalVolume2OfJournal2, + journalIssue1OfJournalVolume2OfJournal2,isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume2OfJournal2, + journalIssue2OfJournalVolume2OfJournal2,isIssueOfJournalVolume, 1); + + + Item journalIssue3 = itemService.findByIdOrLegacyId(context, "522eea91-096f-4a30-bd00-731b2dde33f3"); + + constructRelationshipAndStore(context, journalIssue3, + itemService.findByIdOrLegacyId(context, "434d9911-fc4e-4d8f-98a1-0343a84b637a"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue3, + itemService.findByIdOrLegacyId(context, "e9aaa1de-5927-4ced-af36-bc6750ff33af"), + isPublicationOfJournalIssue, 1); + + Item journalIssue4 = itemService.findByIdOrLegacyId(context, "df376455-2790-434a-9957-5e1ba740fff9"); + + constructRelationshipAndStore(context, journalIssue4, + itemService.findByIdOrLegacyId(context, "10bc6f8b-0796-486f-94d8-4d2e1814586f"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue4, + itemService.findByIdOrLegacyId(context, "75c0f7f5-5a69-40e8-aa1f-8f35b1ce5a63"), + isPublicationOfJournalIssue, 1); + + Item journalIssue5 = itemService.findByIdOrLegacyId(context, "9c75d673-412a-49ac-a58d-64df4fa1463a"); + + constructRelationshipAndStore(context, journalIssue5, + itemService.findByIdOrLegacyId(context, "5e945357-995a-424a-9ce8-bf3296120e30"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue5, + itemService.findByIdOrLegacyId(context, "87123332-a615-427e-92bc-885f31f161a5"), + isPublicationOfJournalIssue, 1); + + Item journalIssue6 = itemService.findByIdOrLegacyId(context, "d5944ff4-3dc1-407a-b49a-1a2681d75267"); + + constructRelationshipAndStore(context, journalIssue6, + itemService.findByIdOrLegacyId(context, "72ec3575-d9b5-46ab-8a1b-698dd6d73262"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue6, + itemService.findByIdOrLegacyId(context, "5ee81de6-aaac-409d-986f-bf21a7fb543c"), + isPublicationOfJournalIssue, 1); + + Item journalIssue7 = itemService.findByIdOrLegacyId(context, "4a45cacd-9653-437b-92cf-5824b0461f84"); + + constructRelationshipAndStore(context, journalIssue7, + itemService.findByIdOrLegacyId(context, "5f414d41-06ab-419a-b3c6-7e85f8480b31"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue7, + itemService.findByIdOrLegacyId(context, "6e9d30d4-6b1c-4a45-aadc-c81d88444c1a"), + isPublicationOfJournalIssue, 1); + + Item journalIssue8 = itemService.findByIdOrLegacyId(context, "7bba8606-37a1-4a78-b544-b3f1b7c79cb7"); + + constructRelationshipAndStore(context, journalIssue8, + itemService.findByIdOrLegacyId(context, "c5f0f7b6-7ba5-4d4f-94a3-c0d53b0cb62d"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue8, + itemService.findByIdOrLegacyId(context, "2e241414-dfea-4452-b2c4-89f51d89e0b2"), + isPublicationOfJournalIssue, 1); + + Item journalIssue9 = itemService.findByIdOrLegacyId(context, "c136663a-9925-453c-9aae-8cb8ed5e9e4b"); + + constructRelationshipAndStore(context, journalIssue9, + itemService.findByIdOrLegacyId(context, "d2dd2905-b178-45df-a5e1-8e2510bd33f8"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue9, + itemService.findByIdOrLegacyId(context, "17101e66-686b-42d5-b3eb-17488f8e3a9c"), + isPublicationOfJournalIssue, 1); + + Item journalIssue10 = itemService.findByIdOrLegacyId(context, "09f27238-8374-4da8-b442-295fd1c5fef7"); + + constructRelationshipAndStore(context, journalIssue10, + itemService.findByIdOrLegacyId(context, "249b1235-2793-4ad2-b40a-1745bcac7d52"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue10, + itemService.findByIdOrLegacyId(context, "dc1e6daa-8aa5-4b10-b70d-517792ab9801"), + isPublicationOfJournalIssue, 1); + + Item journalIssue11 = itemService.findByIdOrLegacyId(context, "f88bc89e-dcfa-4eca-8db6-1ef808c30564"); + + constructRelationshipAndStore(context, journalIssue11, + itemService.findByIdOrLegacyId(context, "786df549-c1c3-4818-8fee-10f07858b41f"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue11, + itemService.findByIdOrLegacyId(context, "2a351411-1614-4bfa-af50-752af07acf1c"), + isPublicationOfJournalIssue, 1); + + Item journalIssue12 = itemService.findByIdOrLegacyId(context, "961e137c-d815-4ade-aff1-0bb12f1fe965"); + + constructRelationshipAndStore(context, journalIssue12, + itemService.findByIdOrLegacyId(context, "19b25bea-59e6-4c3c-a461-19a2c18ec602"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue12, + itemService.findByIdOrLegacyId(context, "dde41d4d-55cd-4107-9d91-4407cdb441c1"), + isPublicationOfJournalIssue, 1); + + + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue3, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue4, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue5, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue6, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue7, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue8, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue9, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue10, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue11, + isIssueOfJournalVolume, 1); + constructRelationshipAndStore(context, journalVolume1OfJournal2, + journalIssue12, + isIssueOfJournalVolume, 1); + + + constructRelationshipAndStore(context, journalIssue1OfJournalVolume1OfJournal1, + article1 ,isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue2OfJournalVolume1OfJournal1, + article2 ,isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, journalIssue1OfJournalVolume2OfJournal1, + article3 ,isPublicationOfJournalIssue, 1); + + + constructRelationshipAndStore(context, article8, author1, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article8, orgUnit1, isAuthorOfPublicationNew, 1); + constructRelationshipAndStore(context, article8, author3, isAuthorOfPublication, 1); + constructRelationshipAndStore(context, article8, orgUnit2, isAuthorOfPublicationNew, 1); + + constructRelationshipAndStore(context, + itemService.findByIdOrLegacyId(context, "77877343-3f75-4c33-9492-6ed7c98ed84e"), + itemService.findByIdOrLegacyId(context, "32513cea-6b89-4bce-87c0-214ad118af3e"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, + itemService.findByIdOrLegacyId(context, "77877343-3f75-4c33-9492-6ed7c98ed84e"), + itemService.findByIdOrLegacyId(context, "d10c32e6-2b14-41f7-be3e-46a41bbe1cb4"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, + itemService.findByIdOrLegacyId(context, "f4dcd8a6-4cc4-4806-8bb9-a7e8202e05b0"), + itemService.findByIdOrLegacyId(context, "6a85aea7-a78b-43be-a2b6-c7948f4e12b7"), + isPublicationOfJournalIssue, 1); + constructRelationshipAndStore(context, + itemService.findByIdOrLegacyId(context, "f4dcd8a6-4cc4-4806-8bb9-a7e8202e05b0"), + itemService.findByIdOrLegacyId(context, "56f39a97-2f57-48cc-867d-8fa58804793a"), + isPublicationOfJournalIssue, 1); + + context.complete(); + } + + private void constructRelationshipAndStore(Context context, Item leftItem, + Item rightItem, RelationshipType relationshipType, int place) + throws SQLException, AuthorizeException { + Relationship relationship = new Relationship(); + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + relationship.setRelationshipType(relationshipType); + relationship.setLeftPlace(place); + relationship.setRightPlace(place); + relationshipService.create(context, relationship); + } + + +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java new file mode 100644 index 0000000000..bc3ae8bb5f --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -0,0 +1,229 @@ +/** + * 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.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.commons.cli.PosixParser; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.content.factory.ContentServiceFactory; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public class InitializeEntities { + + private final static Logger log = Logger.getLogger(InitializeEntities.class); + + private RelationshipTypeService relationshipTypeService; + private RelationshipService relationshipService; + private EntityTypeService entityTypeService; + + private InitializeEntities() { + relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService(); + relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); + entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService(); + + } + + public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException { + InitializeEntities initializeEntities = new InitializeEntities(); + CommandLineParser parser = new PosixParser(); + Options options = createCommandLineOptions(); + CommandLine line = parser.parse(options,argv); + String fileLocation = getFileLocationFromCommandLine(line); + checkHelpEntered(options, line); + initializeEntities.run(fileLocation); + } + private static void checkHelpEntered(Options options, CommandLine line) { + if (line.hasOption("h")) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("Intialize Entities", options); + System.exit(0); + } + } + private static String getFileLocationFromCommandLine(CommandLine line) { + String query = line.getOptionValue("f"); + if (StringUtils.isEmpty(query)) { + System.out.println("No file location was entered"); + log.info("No file location was entered"); + System.exit(1); + } + return query; + } + + protected static Options createCommandLineOptions() { + Options options = new Options(); + options.addOption("f", "file", true, "the location for the file containing the xml data"); + + return options; + } + + private void run(String fileLocation) throws SQLException, AuthorizeException { + Context context = new Context(); + context.turnOffAuthorisationSystem(); + List relationshipTypes = this.parseXMLToRelations(context, fileLocation); + this.saveRelations(context, relationshipTypes); + } + + private void saveRelations(Context context, List list) throws SQLException, AuthorizeException { + for (RelationshipType relationshipType : list) { + RelationshipType relationshipTypeFromDb = relationshipTypeService.findbyTypesAndLabels(context, + relationshipType.getLeftType(), + relationshipType.getRightType(), + relationshipType.getLeftLabel(), + relationshipType.getRightLabel()); + if (relationshipTypeFromDb == null) { + relationshipTypeService.create(context, relationshipType); + } else { + relationshipTypeFromDb.setLeftMinCardinality(relationshipType.getLeftMinCardinality()); + relationshipTypeFromDb.setLeftMaxCardinality(relationshipType.getLeftMaxCardinality()); + relationshipTypeFromDb.setRightMinCardinality(relationshipType.getRightMinCardinality()); + relationshipTypeFromDb.setRightMaxCardinality(relationshipType.getRightMaxCardinality()); + relationshipTypeService.update(context, relationshipTypeFromDb); + } + } + context.commit(); + context.complete(); + } + + private List parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException { + try { + File fXmlFile = new File(fileLocation); + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = null; + dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(fXmlFile); + + doc.getDocumentElement().normalize(); + + NodeList nList = doc.getElementsByTagName("type"); + List relationshipTypes = new LinkedList<>(); + for (int i = 0; i < nList.getLength(); i++) { + Node nNode = nList.item(i); + + if (nNode.getNodeType() == Node.ELEMENT_NODE) { + + Element eElement = (Element) nNode; + + String leftType = eElement.getElementsByTagName("leftType").item(0).getTextContent(); + String rightType = eElement.getElementsByTagName("rightType").item(0).getTextContent(); + String leftLabel = eElement.getElementsByTagName("leftLabel").item(0).getTextContent(); + String rightLabel = eElement.getElementsByTagName("rightLabel").item(0).getTextContent(); + + + NodeList leftCardinalityList = eElement.getElementsByTagName("leftCardinality"); + NodeList rightCardinalityList = eElement.getElementsByTagName("rightCardinality"); + + String leftCardinalityMin = ""; + String leftCardinalityMax = ""; + + String rightCardinalityMin = ""; + String rightCardinalityMax = ""; + + for (int j = 0; j < leftCardinalityList.getLength(); j++) { + Node node = leftCardinalityList.item(j); + leftCardinalityMin = getString(leftCardinalityMin,(Element) node, "min"); + leftCardinalityMax = getString(leftCardinalityMax,(Element) node, "max"); + + } + + for (int j = 0; j < rightCardinalityList.getLength(); j++) { + Node node = rightCardinalityList.item(j); + rightCardinalityMin = getString(rightCardinalityMin,(Element) node, "min"); + rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max"); + + } + RelationshipType relationshipType = populateRelationshipType(context,leftType,rightType,leftLabel, + rightLabel,leftCardinalityMin, + leftCardinalityMax, + rightCardinalityMin, + rightCardinalityMax); + + + relationshipTypes.add(relationshipType); + } + } + return relationshipTypes; + } catch (ParserConfigurationException | SAXException | IOException | SQLException e) { + log.error(e, e); + } + return null; + } + + private String getString(String leftCardinalityMin,Element node, String minOrMax) { + if (node.getElementsByTagName(minOrMax).getLength() > 0) { + leftCardinalityMin = node.getElementsByTagName(minOrMax).item(0).getTextContent(); + } + return leftCardinalityMin; + } + + private RelationshipType populateRelationshipType(Context context,String leftType,String rightType,String leftLabel, + String rightLabel,String leftCardinalityMin, + String leftCardinalityMax,String rightCardinalityMin, + String rightCardinalityMax) + throws SQLException, AuthorizeException { + RelationshipType relationshipType = new RelationshipType(); + + EntityType leftEntityType = entityTypeService.findByEntityType(context,leftType); + if (leftEntityType == null) { + leftEntityType = entityTypeService.create(context, leftType); + } + EntityType rightEntityType = entityTypeService.findByEntityType(context, rightType); + if (rightEntityType == null) { + rightEntityType = entityTypeService.create(context, rightType); + } + relationshipType.setLeftType(leftEntityType); + relationshipType.setRightType(rightEntityType); + relationshipType.setLeftLabel(leftLabel); + relationshipType.setRightLabel(rightLabel); + if (StringUtils.isNotBlank(leftCardinalityMin)) { + relationshipType.setLeftMinCardinality(Integer.parseInt(leftCardinalityMin)); + } else { + relationshipType.setLeftMinCardinality(Integer.MIN_VALUE); + } + if (StringUtils.isNotBlank(leftCardinalityMax)) { + relationshipType.setLeftMaxCardinality(Integer.parseInt(leftCardinalityMax)); + } else { + relationshipType.setLeftMaxCardinality(Integer.MAX_VALUE); + } + if (StringUtils.isNotBlank(rightCardinalityMin)) { + relationshipType.setRightMinCardinality(Integer.parseInt(rightCardinalityMin)); + } else { + relationshipType.setRightMinCardinality(Integer.MIN_VALUE); + } + if (StringUtils.isNotBlank(rightCardinalityMax)) { + relationshipType.setRightMaxCardinality(Integer.parseInt(rightCardinalityMax)); + } else { + relationshipType.setRightMaxCardinality(Integer.MAX_VALUE); + } + return relationshipType; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 8ec6b9ae29..06ae0d1f06 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -235,6 +235,13 @@ public abstract class DSpaceObjectServiceImpl implements boolean authorityControlled = metadataAuthorityService.isAuthorityControlled(metadataField); boolean authorityRequired = metadataAuthorityService.isAuthorityRequired(metadataField); + if (authorities != null) { + for (String s : authorities) { + if (StringUtils.equals(s, "virtual")) { + return; + } + } + } // We will not verify that they are valid entries in the registry // until update() is called. for (int i = 0; i < values.size(); i++) { @@ -545,8 +552,10 @@ public abstract class DSpaceObjectServiceImpl implements List metadataValues = dso.getMetadata(); for (MetadataValue metadataValue : metadataValues) { //Retrieve & store the place for each metadata value - int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); - metadataValue.setPlace(mvPlace); + if (!StringUtils.equals(metadataValue.getAuthority(), "virtual")) { + int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); + metadataValue.setPlace(mvPlace); + } } } } diff --git a/dspace-api/src/main/java/org/dspace/content/Entity.java b/dspace-api/src/main/java/org/dspace/content/Entity.java new file mode 100644 index 0000000000..593b489f07 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/Entity.java @@ -0,0 +1,37 @@ +/** + * 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.util.List; + +public class Entity { + + private Item item; + private List relationships; + + public Entity(Item item,List relationshipList) { + setItem(item); + setRelationships(relationshipList); + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } + + public List getRelationships() { + return relationships; + } + + public void setRelationships(List relationships) { + this.relationships = relationships; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java new file mode 100644 index 0000000000..a3785a756b --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java @@ -0,0 +1,137 @@ +/** + * 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.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.lang.StringUtils; +import org.dspace.content.service.EntityService; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class EntityServiceImpl implements EntityService { + + @Autowired(required = true) + protected EntityTypeService entityTypeService; + + @Autowired(required = true) + protected RelationshipService relationshipService; + + @Autowired(required = true) + protected RelationshipTypeService relationshipTypeService; + + @Autowired(required = true) + protected ItemService itemService; + + public Entity findByItemId(Context context, UUID itemId) throws SQLException { + Item item = itemService.find(context, itemId); + List relationshipList = relationshipService.findByItem(context, item); + return new Entity(item, relationshipList); + } + + public EntityType getType(Context context, Entity entity) throws SQLException { + Item item = entity.getItem(); + List list = itemService.getMetadata(item, "relationship", "type", null, Item.ANY); + if (!list.isEmpty()) { + return entityTypeService.findByEntityType(context, list.get(0).getValue()); + } else { + return null; + } + } + + public List getAllRelations(Context context, Entity entity) { + return entity.getRelationships(); + } + + public List getLeftRelations(Context context, Entity entity) { + List fullList = this.getAllRelations(context, entity); + List listToReturn = new LinkedList<>(); + for (Relationship relationship : fullList) { + if (relationship.getLeftItem() == entity.getItem()) { + listToReturn.add(relationship); + } + } + return listToReturn; + } + + public List getRightRelations(Context context, Entity entity) { + List fullList = this.getAllRelations(context, entity); + List listToReturn = new LinkedList<>(); + for (Relationship relationship : fullList) { + if (relationship.getRightItem() == entity.getItem()) { + listToReturn.add(relationship); + } + } + return listToReturn; + } + + public List getRelationsByLabel(Context context, String label) throws SQLException { + List listToReturn = new LinkedList<>(); + List relationshipList = relationshipService.findAll(context); + for (Relationship relationship : relationshipList) { + RelationshipType relationshipType = relationship.getRelationshipType(); + if (StringUtils.equals(relationshipType.getLeftLabel(),label) || + StringUtils.equals(relationshipType.getRightLabel(),label)) { + listToReturn.add(relationship); + } + } + return listToReturn; + } + + public List getAllRelationshipTypes(Context context, Entity entity) throws SQLException { + EntityType entityType = this.getType(context, entity); + List listToReturn = new LinkedList<>(); + for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { + if (relationshipType.getLeftType() == entityType || + relationshipType.getRightType() == entityType) { + listToReturn.add(relationshipType); + } + } + return listToReturn; + } + + public List getLeftRelationshipTypes(Context context, Entity entity) throws SQLException { + EntityType entityType = this.getType(context, entity); + List listToReturn = new LinkedList<>(); + for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { + if (relationshipType.getLeftType() == entityType) { + listToReturn.add(relationshipType); + } + } + return listToReturn; + } + + public List getRightRelationshipTypes(Context context, Entity entity) throws SQLException { + EntityType entityType = this.getType(context, entity); + List listToReturn = new LinkedList<>(); + for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { + if (relationshipType.getRightType() == entityType) { + listToReturn.add(relationshipType); + } + } + return listToReturn; + } + + public List getRelationshipTypesByLabel(Context context, String label) throws SQLException { + List listToReturn = new LinkedList<>(); + for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { + if (StringUtils.equals(relationshipType.getLeftLabel(),label) || + StringUtils.equals(relationshipType.getRightLabel(),label)) { + listToReturn.add(relationshipType); + } + } + return listToReturn; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/EntityType.java b/dspace-api/src/main/java/org/dspace/content/EntityType.java new file mode 100644 index 0000000000..d0f8d1e9b5 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/EntityType.java @@ -0,0 +1,48 @@ +/** + * 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 javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + + +@Entity +@Table(name = "entity_type") +public class EntityType { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity_type_id_seq") + @SequenceGenerator(name = "entity_type_id_seq", sequenceName = "entity_type_id_seq", allocationSize = 1) + @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) + protected Integer id; + + @Column(name = "label", nullable = false) + private String label; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + +} diff --git a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java new file mode 100644 index 0000000000..2eb4ab96ad --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java @@ -0,0 +1,86 @@ +/** + * 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.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.dao.EntityTypeDAO; +import org.dspace.content.service.EntityTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class EntityTypeServiceImpl implements EntityTypeService { + + @Autowired(required = true) + protected EntityTypeDAO entityTypeDAO; + + @Autowired(required = true) + protected AuthorizeService authorizeService; + + public EntityType findByEntityType(Context context,String entityType) throws SQLException { + return entityTypeDAO.findByEntityType(context, entityType); + } + + public List findAll(Context context) throws SQLException { + return entityTypeDAO.findAll(context, EntityType.class); + } + + public EntityType create(Context context) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify entityType"); + } + return entityTypeDAO.create(context, new EntityType()); + } + + public EntityType create(Context context, String entityTypeString) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify entityType"); + } + EntityType entityType = new EntityType(); + entityType.setLabel(entityTypeString); + return entityTypeDAO.create(context, entityType); + } + + public EntityType find(Context context,int id) throws SQLException { + EntityType entityType = entityTypeDAO.findByID(context, EntityType.class, id); + return entityType; + } + + public void update(Context context,EntityType entityType) throws SQLException, AuthorizeException { + update(context,Collections.singletonList(entityType)); + } + + public void update(Context context,List entityTypes) throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(entityTypes)) { + // Check authorisation - only administrators can change formats + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify entityType"); + } + + for (EntityType entityType : entityTypes) { + entityTypeDAO.save(context, entityType); + } + } + } + + public void delete(Context context,EntityType entityType) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can delete entityType"); + } + entityTypeDAO.delete(context, entityType); + } +} 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 41dff1e5a6..70d5835ea9 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -12,8 +12,11 @@ import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; +import java.util.Map; import java.util.UUID; import org.apache.commons.collections4.CollectionUtils; @@ -35,7 +38,9 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.InstallItemService; import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataSchemaService; +import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; +import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; @@ -100,6 +105,11 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It @Autowired(required = true) protected WorkflowItemService workflowItemService; + @Autowired(required = true) + protected RelationshipService relationshipService; + + @Autowired(required = true) + protected VirtualMetadataPopulator virtualMetadataPopulator; protected ItemServiceImpl() { super(); @@ -1257,4 +1267,155 @@ prevent the generation of resource policy entry values with null dspace_object a return false; } -} + + @Override + public List getMetadata(Item item, String schema, String element, String qualifier, String lang) { + List dbMetadataValues = super.getMetadata(item, schema, element, qualifier, lang); + + if (!(StringUtils.equals(schema, "*") && StringUtils.equals(element, "*") && + StringUtils.equals(qualifier, "*") && StringUtils.equals(lang, "*"))) { + return dbMetadataValues; + } + List fullMetadataValueList = getRelationshipMetadata(item); + fullMetadataValueList.addAll(dbMetadataValues); + + return fullMetadataValueList; + + } + + @Override + public List getRelationshipMetadata(Item item) { + Context context = new Context(); + List fullMetadataValueList = new LinkedList<>(); + try { + List list = item.getMetadata(); + String entityType = getEntityTypeStringFromMetadata(list); + if (StringUtils.isNotBlank(entityType)) { + List relationships = relationshipService.findByItem(context, item); + for (Relationship relationship : relationships) { + fullMetadataValueList.addAll(handleItemRelationship(item, entityType, relationship)); + } + + } + } catch (SQLException e) { + log.error(e, e); + } + return fullMetadataValueList; + } + + private List handleItemRelationship(Item item, String entityType, + Relationship relationship) { + List resultingMetadataValueList = new LinkedList<>(); + RelationshipType relationshipType = relationship.getRelationshipType(); + HashMap> hashMaps = new HashMap<>(); + String relationName = ""; + Item otherItem = null; + if (StringUtils.equals(relationshipType.getLeftType().getLabel(), entityType)) { + hashMaps = (HashMap>) virtualMetadataPopulator + .getMap().get(relationshipType.getLeftLabel()); + otherItem = relationship.getRightItem(); + relationName = relationship.getRelationshipType().getLeftLabel(); + } else if (StringUtils.equals(relationshipType.getRightType().getLabel(), entityType)) { + hashMaps = (HashMap>) virtualMetadataPopulator + .getMap().get(relationshipType.getRightLabel()); + otherItem = relationship.getLeftItem(); + relationName = relationship.getRelationshipType().getRightLabel(); + } + + if (hashMaps != null) { + resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(item, hashMaps, + otherItem, relationName)); + } + return resultingMetadataValueList; + } + + private List handleRelationshipTypeMetadataMappping(Item item, + HashMap> hashMaps, + Item otherItem, + String relationName) { + List resultingMetadataValueList = new LinkedList<>(); + for (Map.Entry> entry : hashMaps.entrySet()) { + String key = entry.getKey(); + List value = entry.getValue(); + + MetadataValue metadataValue = constructMetadataValue(key); + metadataValue = constructResultingMetadataValue(item, otherItem, value, metadataValue); + if (StringUtils.isNotBlank(metadataValue.getValue())) { + resultingMetadataValueList.add(metadataValue); + } + } + + resultingMetadataValueList.add(getRelationMetadataFromOtherItem(otherItem, relationName)); + return resultingMetadataValueList; + } + + private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName) { + MetadataValue metadataValue = constructMetadataValue("relation_" + relationName); + metadataValue.setAuthority("virtual"); + metadataValue.setValue(otherItem.getID().toString()); + return metadataValue; + } + + private String getEntityTypeStringFromMetadata(List list) { + String entityType = null; + for (MetadataValue mdv : list) { + if (StringUtils.equals(mdv.getMetadataField().getMetadataSchema().getName(), + "relationship") + && StringUtils.equals(mdv.getMetadataField().getElement(), + "type")) { + + entityType = mdv.getValue(); + } + } + return entityType; + } + + private MetadataValue constructResultingMetadataValue(Item item, Item otherItem, List value, + MetadataValue metadataValue) { + List resultValues = new LinkedList<>(); + for (String s : value) { + String[] splittedString = s.split("\\."); + + List resultList = this.getMetadata(otherItem, + splittedString.length > 0 ? splittedString[0] : null, + splittedString.length > 1 ? splittedString[1] : null, + splittedString.length > 2 ? splittedString[2] : null, + Item.ANY); + + String resultString = ""; + for (int i = 0; i < resultList.size(); i++) { + String metadataValueString = resultList.get(i).getValue(); + if (StringUtils.isNotBlank(metadataValueString)) { + if (StringUtils.isNotBlank(resultString)) { + resultString += ", "; + } + resultString += metadataValueString; + } + } + if (StringUtils.isNotBlank(resultString)) { + resultValues.add(resultString); + } + } + + String result = StringUtils.join(resultValues, ", "); + metadataValue.setValue(result); + metadataValue.setAuthority("virtual"); + metadataValue.setConfidence(-1); + metadataValue.setDSpaceObject(item); + return metadataValue; + } + + private MetadataValue constructMetadataValue(String key) { + String[] splittedKey = key.split("_"); + MetadataValue metadataValue = new MetadataValue(); + MetadataField metadataField = new MetadataField(); + MetadataSchema metadataSchema = new MetadataSchema(); + metadataSchema.setName(splittedKey.length > 0 ? splittedKey[0] : null); + metadataField.setMetadataSchema(metadataSchema); + metadataField.setElement(splittedKey.length > 1 ? splittedKey[1] : null); + metadataField.setQualifier(splittedKey.length > 2 ? splittedKey[2] : null); + metadataValue.setMetadataField(metadataField); + metadataValue.setLanguage(Item.ANY); + return metadataValue; + } +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/Relationship.java b/dspace-api/src/main/java/org/dspace/content/Relationship.java new file mode 100644 index 0000000000..b38b838ea7 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/Relationship.java @@ -0,0 +1,102 @@ +/** + * 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 javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.dspace.core.ReloadableEntity; + +@Entity +@Table(name = "relationship") +public class Relationship implements ReloadableEntity { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "relationship_id_seq") + @SequenceGenerator(name = "relationship_id_seq", sequenceName = "relationship_id_seq", allocationSize = 1) + @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) + protected Integer id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "left_id", nullable = false) + private Item leftItem; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "type_id", nullable = false) + private RelationshipType relationshipType; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "right_id", nullable = false) + private Item rightItem; + + @Column(name = "left_place") + private int leftPlace; + + @Column(name = "right_place") + private int rightPlace; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Item getLeftItem() { + return leftItem; + } + + public void setLeftItem(Item leftItem) { + this.leftItem = leftItem; + } + + public RelationshipType getRelationshipType() { + return relationshipType; + } + + public void setRelationshipType(RelationshipType relationshipType) { + this.relationshipType = relationshipType; + } + + public Item getRightItem() { + return rightItem; + } + + public void setRightItem(Item rightItem) { + this.rightItem = rightItem; + } + + public int getLeftPlace() { + return leftPlace; + } + + public void setLeftPlace(int leftPlace) { + this.leftPlace = leftPlace; + } + + public int getRightPlace() { + return rightPlace; + } + + public void setRightPlace(int rightPlace) { + this.rightPlace = rightPlace; + } + + public Integer getID() { + return id; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java new file mode 100644 index 0000000000..6b563564d3 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -0,0 +1,289 @@ +/** + * 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.sql.SQLException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.dao.RelationshipDAO; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class RelationshipServiceImpl implements RelationshipService { + + private static final Logger log = Logger.getLogger(RelationshipServiceImpl.class); + + @Autowired(required = true) + protected RelationshipDAO relationshipDAO; + + @Autowired(required = true) + protected AuthorizeService authorizeService; + + @Autowired(required = true) + protected ItemService itemService; + + @Autowired(required = true) + protected RelationshipTypeService relationshipTypeService; + + public Relationship create(Context context) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify relationship"); + } + return relationshipDAO.create(context, new Relationship()); + } + + public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException { + if (isRelationshipValidToCreate(context, relationship)) { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify relationship"); + } + updatePlaceInRelationship(context, relationship); + + return relationshipDAO.create(context, relationship); + } else { + throw new IllegalArgumentException("The relationship given was not valid"); + } + } + + private void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException { + List leftRelationships = findByItemAndRelationshipType(context, + relationship.getLeftItem(), + relationship.getRelationshipType(), true); + List rightRelationships = findByItemAndRelationshipType(context, + relationship.getRightItem(), + relationship.getRelationshipType(), + false); + + if (!leftRelationships.isEmpty()) { + leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); + relationship.setLeftPlace(leftRelationships.get(0).getLeftPlace() + 1); + } else { + relationship.setLeftPlace(1); + } + + if (!rightRelationships.isEmpty()) { + rightRelationships.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); + relationship.setRightPlace(rightRelationships.get(0).getRightPlace() + 1); + } else { + relationship.setRightPlace(1); + } + } + + public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { + return relationshipDAO.findLeftPlaceByLeftItem(context, item); + } + + public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { + return relationshipDAO.findRightPlaceByRightItem(context, item); + } + + private boolean isRelationshipValidToCreate(Context context, Relationship relationship) throws SQLException { + RelationshipType relationshipType = relationship.getRelationshipType(); + + if (!verifyEntityTypes(relationship.getLeftItem(), relationshipType.getLeftType())) { + log.warn("The relationship has been deemed invalid since the leftItem" + + " and leftType do no match on entityType"); + logRelationshipTypeDetails(relationshipType); + return false; + } + if (!verifyEntityTypes(relationship.getRightItem(), relationshipType.getRightType())) { + log.warn("The relationship has been deemed invalid since the rightItem" + + " and rightType do no match on entityType"); + logRelationshipTypeDetails(relationshipType); + return false; + } + if (!verifyMaxCardinality(context, relationship.getLeftItem(), + relationshipType.getLeftMaxCardinality(), relationshipType)) { + log.warn("The relationship has been deemed invalid since the left item has more" + + " relationships than the left max cardinality allows after we'd store this relationship"); + logRelationshipTypeDetails(relationshipType); + return false; + } + if (!verifyMaxCardinality(context, relationship.getRightItem(), + relationshipType.getRightMaxCardinality(), relationshipType)) { + log.warn("The relationship has been deemed invalid since the right item has more" + + " relationships than the right max cardinality allows after we'd store this relationship"); + logRelationshipTypeDetails(relationshipType); + return false; + } + return true; + } + + private void logRelationshipTypeDetails(RelationshipType relationshipType) { + log.warn("The relationshipType's ID is: " + relationshipType.getId()); + log.warn("The relationshipType's left label is: " + relationshipType.getLeftLabel()); + log.warn("The relationshipType's right label is: " + relationshipType.getRightLabel()); + log.warn("The relationshipType's left entityType label is: " + relationshipType.getLeftType().getLabel()); + log.warn("The relationshipType's right entityType label is: " + relationshipType.getRightType().getLabel()); + log.warn("The relationshipType's left min cardinality is: " + relationshipType.getLeftMinCardinality()); + log.warn("The relationshipType's left max cardinality is: " + relationshipType.getLeftMaxCardinality()); + log.warn("The relationshipType's right min cardinality is: " + relationshipType.getRightMinCardinality()); + log.warn("The relationshipType's right max cardinality is: " + relationshipType.getRightMaxCardinality()); + } + + private boolean verifyMaxCardinality(Context context, Item itemToProcess, + int maxCardinality, RelationshipType relationshipType) throws SQLException { + List rightRelationships = findByItemAndRelationshipType(context, itemToProcess, relationshipType, + false); + if (rightRelationships.size() >= maxCardinality && maxCardinality != 0) { + return false; + } + return true; + } + + private boolean verifyEntityTypes(Item itemToProcess, EntityType entityTypeToProcess) { + List list = itemService.getMetadata(itemToProcess, "relationship", "type", null, Item.ANY); + if (list.isEmpty()) { + return false; + } + String leftEntityType = list.get(0).getValue(); + if (!StringUtils.equals(leftEntityType, entityTypeToProcess.getLabel())) { + return false; + } + return true; + } + + public Relationship find(Context context, int id) throws SQLException { + Relationship relationship = relationshipDAO.findByID(context, Relationship.class, id); + return relationship; + } + + public List findByItem(Context context, Item item) throws SQLException { + + List list = relationshipDAO.findByItem(context, item); + + list.sort((o1, o2) -> { + int relationshipType = o1.getRelationshipType().getLeftLabel() + .compareTo(o2.getRelationshipType().getLeftLabel()); + if (relationshipType != 0) { + return relationshipType; + } else { + if (o1.getLeftItem() == item) { + return o1.getLeftPlace() - o2.getLeftPlace(); + } else { + return o1.getRightPlace() - o2.getRightPlace(); + } + } + }); + return list; + } + + public List findAll(Context context) throws SQLException { + return relationshipDAO.findAll(context, Relationship.class); + } + + public void update(Context context, Relationship relationship) throws SQLException, AuthorizeException { + update(context, Collections.singletonList(relationship)); + + } + + public void update(Context context, List relationships) throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(relationships)) { + // Check authorisation - only administrators can change formats + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify relationship"); + } + + for (Relationship relationship : relationships) { + relationshipDAO.save(context, relationship); + } + } + } + + public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException { + if (isRelationshipValidToDelete(context, relationship)) { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can delete relationship"); + } + relationshipDAO.delete(context, relationship); + } else { + throw new IllegalArgumentException("The relationship given was not valid"); + } + } + + private boolean isRelationshipValidToDelete(Context context, Relationship relationship) throws SQLException { + if (relationship == null) { + log.warn("The relationship has been deemed invalid since the relation was null"); + return false; + } + if (relationship.getId() == null) { + log.warn("The relationship has been deemed invalid since the ID" + + " off the given relationship was null"); + return false; + } + if (this.find(context, relationship.getId()) == null) { + log.warn("The relationship has been deemed invalid since the relationship" + + " is not present in the DB with the current ID"); + logRelationshipTypeDetails(relationship.getRelationshipType()); + return false; + } + if (!checkMinCardinality(context, relationship.getLeftItem(), + relationship, relationship.getRelationshipType().getLeftMinCardinality(), true)) { + log.warn("The relationship has been deemed invalid since the leftMinCardinality" + + " constraint would be violated upon deletion"); + logRelationshipTypeDetails(relationship.getRelationshipType()); + return false; + } + + if (!checkMinCardinality(context, relationship.getRightItem(), + relationship, relationship.getRelationshipType().getRightMinCardinality(), false)) { + log.warn("The relationship has been deemed invalid since the rightMinCardinality" + + " constraint would be violated upon deletion"); + logRelationshipTypeDetails(relationship.getRelationshipType()); + return false; + } + return true; + } + + private boolean checkMinCardinality(Context context, Item item, + Relationship relationship, + int minCardinality, boolean isLeft) throws SQLException { + List list = this + .findByItemAndRelationshipType(context, item, relationship.getRelationshipType(), isLeft); + if (!(list.size() > minCardinality)) { + return false; + } + return true; + } + + public List findByItemAndRelationshipType(Context context, Item item, + RelationshipType relationshipType, boolean isLeft) + + throws SQLException { + List list = this.findByItem(context, item); + List listToReturn = new LinkedList<>(); + for (Relationship relationship : list) { + if (isLeft) { + if (StringUtils + .equals(relationship.getRelationshipType().getLeftLabel(), relationshipType.getLeftLabel())) { + listToReturn.add(relationship); + } + } else { + if (StringUtils + .equals(relationship.getRelationshipType().getRightLabel(), relationshipType.getRightLabel())) { + listToReturn.add(relationship); + } + } + } + return listToReturn; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipType.java b/dspace-api/src/main/java/org/dspace/content/RelationshipType.java new file mode 100644 index 0000000000..94186743c2 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipType.java @@ -0,0 +1,131 @@ +/** + * 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 javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + + +@Entity +@Table(name = "relationship_type") +public class RelationshipType { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "relationship_type_id_seq") + @SequenceGenerator(name = "relationship_type_id_seq", sequenceName = "relationship_type_id_seq", allocationSize = 1) + @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) + protected Integer id; + + @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST}) + @JoinColumn(name = "left_type", nullable = false) + private EntityType leftType; + + @ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST}) + @JoinColumn(name = "right_type", nullable = false) + private EntityType rightType; + + @Column(name = "left_label", nullable = false) + private String leftLabel; + + @Column(name = "right_label", nullable = false) + private String rightLabel; + + @Column(name = "left_min_cardinality") + private int leftMinCardinality; + + @Column(name = "left_max_cardinality") + private int leftMaxCardinality; + + @Column(name = "right_min_cardinality") + private int rightMinCardinality; + + @Column(name = "right_max_cardinality") + private int rightMaxCardinality; + + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public EntityType getLeftType() { + return leftType; + } + + public void setLeftType(EntityType leftType) { + this.leftType = leftType; + } + + public EntityType getRightType() { + return rightType; + } + + public void setRightType(EntityType rightType) { + this.rightType = rightType; + } + + public String getLeftLabel() { + return leftLabel; + } + + public void setLeftLabel(String leftLabel) { + this.leftLabel = leftLabel; + } + + public String getRightLabel() { + return rightLabel; + } + + public void setRightLabel(String rightLabel) { + this.rightLabel = rightLabel; + } + + public int getLeftMinCardinality() { + return leftMinCardinality; + } + + public void setLeftMinCardinality(int leftMinCardinality) { + this.leftMinCardinality = leftMinCardinality; + } + + public int getLeftMaxCardinality() { + return leftMaxCardinality; + } + + public void setLeftMaxCardinality(int leftMaxCardinality) { + this.leftMaxCardinality = leftMaxCardinality; + } + + public int getRightMinCardinality() { + return rightMinCardinality; + } + + public void setRightMinCardinality(int rightMinCardinality) { + this.rightMinCardinality = rightMinCardinality; + } + + public int getRightMaxCardinality() { + return rightMaxCardinality; + } + + public void setRightMaxCardinality(int rightMaxCardinality) { + this.rightMaxCardinality = rightMaxCardinality; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java new file mode 100644 index 0000000000..a03eb02677 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -0,0 +1,87 @@ +/** + * 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.sql.SQLException; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.dao.RelationshipTypeDAO; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class RelationshipTypeServiceImpl implements RelationshipTypeService { + + @Autowired(required = true) + protected RelationshipTypeDAO relationshipTypeDAO; + + @Autowired(required = true) + protected AuthorizeService authorizeService; + + public RelationshipType create(Context context) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify relationshipType"); + } + return relationshipTypeDAO.create(context, new RelationshipType()); + } + + public RelationshipType create(Context context, RelationshipType relationshipType) + throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify relationshipType"); + } + return relationshipTypeDAO.create(context, relationshipType); + } + + public RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, + String leftLabel,String rightLabel) throws SQLException { + return relationshipTypeDAO.findbyTypesAndLabels(context, leftType, rightType, leftLabel, rightLabel); + } + + public List findAll(Context context) throws SQLException { + return relationshipTypeDAO.findAll(context, RelationshipType.class); + } + + public RelationshipType find(Context context,int id) throws SQLException { + return relationshipTypeDAO.findByID(context, RelationshipType.class, id); + } + + public void update(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException { + update(context,Collections.singletonList(relationshipType)); + } + + public void update(Context context,List relationshipTypes) + throws SQLException, AuthorizeException { + if (CollectionUtils.isNotEmpty(relationshipTypes)) { + // Check authorisation - only administrators can change formats + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can modify RelationshipType"); + } + + for (RelationshipType relationshipType : relationshipTypes) { + relationshipTypeDAO.save(context, relationshipType); + } + } + + } + + public void delete(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException { + if (!authorizeService.isAdmin(context)) { + throw new AuthorizeException( + "Only administrators can delete entityType"); + } + relationshipTypeDAO.delete(context, relationshipType); + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/EntityTypeDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/EntityTypeDAO.java new file mode 100644 index 0000000000..68dfb9b92a --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/EntityTypeDAO.java @@ -0,0 +1,20 @@ +/** + * 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.dao; + +import java.sql.SQLException; + +import org.dspace.content.EntityType; +import org.dspace.core.Context; +import org.dspace.core.GenericDAO; + +public interface EntityTypeDAO extends GenericDAO { + + public EntityType findByEntityType(Context context, String entityType) throws SQLException; + +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java new file mode 100644 index 0000000000..f25e8d473a --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java @@ -0,0 +1,25 @@ +/** + * 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.dao; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.core.Context; +import org.dspace.core.GenericDAO; + +public interface RelationshipDAO extends GenericDAO { + + List findByItem(Context context,Item item) throws SQLException; + + int findLeftPlaceByLeftItem(Context context,Item item) throws SQLException; + + int findRightPlaceByRightItem(Context context,Item item) throws SQLException; +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java new file mode 100644 index 0000000000..b94874dbfe --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java @@ -0,0 +1,23 @@ +/** + * 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.dao; + +import java.sql.SQLException; + +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.core.Context; +import org.dspace.core.GenericDAO; + +public interface RelationshipTypeDAO extends GenericDAO { + + RelationshipType findbyTypesAndLabels(Context context, + EntityType leftType,EntityType rightType,String leftLabel,String rightLabel) + throws SQLException; + +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java new file mode 100644 index 0000000000..514b337bb9 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java @@ -0,0 +1,29 @@ +/** + * 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.dao.impl; + +import java.sql.SQLException; + +import org.dspace.content.EntityType; +import org.dspace.content.dao.EntityTypeDAO; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.hibernate.Criteria; +import org.hibernate.criterion.Restrictions; + +public class EntityTypeDAOImpl extends AbstractHibernateDAO implements EntityTypeDAO { + + public EntityType findByEntityType(Context context,String entityType) throws SQLException { + Criteria criteria = createCriteria(context,EntityType.class); + criteria.add(Restrictions.and( + Restrictions.eq("label", entityType).ignoreCase() + )); + + return singleResult(criteria); + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java new file mode 100644 index 0000000000..e41a768c17 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java @@ -0,0 +1,62 @@ +/** + * 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.dao.impl; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.dao.RelationshipDAO; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.hibernate.Criteria; +import org.hibernate.criterion.Restrictions; + +public class RelationshipDAOImpl extends AbstractHibernateDAO implements RelationshipDAO { + + public List findByItem(Context context,Item item) throws SQLException { + Criteria criteria = createCriteria(context,Relationship.class); + criteria.add(Restrictions.or( + Restrictions.eq("leftItem", item), + Restrictions.eq("rightItem", item) + )); + + return list(criteria); + } + + public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { + Criteria criteria = createCriteria(context, Relationship.class); + criteria.add(Restrictions.and( + Restrictions.eq("leftItem", item) + )); + + List list = list(criteria); + list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); + if (!list.isEmpty()) { + return list.get(0).getLeftPlace(); + } else { + return 1; + } + } + + public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { + Criteria criteria = createCriteria(context, Relationship.class); + criteria.add(Restrictions.and( + Restrictions.eq("rightItem", item) + )); + + List list = list(criteria); + list.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); + if (!list.isEmpty()) { + return list.get(0).getLeftPlace(); + } else { + return 1; + } + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java new file mode 100644 index 0000000000..68c17d7807 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java @@ -0,0 +1,35 @@ +/** + * 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.dao.impl; + +import java.sql.SQLException; + +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.content.dao.RelationshipTypeDAO; +import org.dspace.core.AbstractHibernateDAO; +import org.dspace.core.Context; +import org.hibernate.Criteria; +import org.hibernate.criterion.Restrictions; + +public class RelationshipTypeDAOImpl extends AbstractHibernateDAO implements RelationshipTypeDAO { + + public RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, + String leftLabel,String rightLabel) + throws SQLException { + Criteria criteria = createCriteria(context,RelationshipType.class); + criteria.add(Restrictions.and( + Restrictions.eq("leftType", leftType), + Restrictions.eq("rightType", rightType), + Restrictions.eq("leftLabel", leftLabel), + Restrictions.eq("rightLabel", rightLabel) + )); + return singleResult(criteria); + } + +} diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java index b5f50aa141..f3f44f058d 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java @@ -19,12 +19,16 @@ import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.DSpaceObjectLegacySupportService; import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.EntityService; +import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.InProgressSubmissionService; 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.SiteService; import org.dspace.content.service.SupervisedItemService; import org.dspace.content.service.WorkspaceItemService; @@ -70,6 +74,14 @@ public abstract class ContentServiceFactory { public abstract SiteService getSiteService(); + public abstract RelationshipTypeService getRelationshipTypeService(); + + public abstract RelationshipService getRelationshipService(); + + public abstract EntityTypeService getEntityTypeService(); + + public abstract EntityService getEntityService(); + public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) { if (inProgressSubmission instanceof WorkspaceItem) { return getWorkspaceItemService(); diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java index ab10bb8bf5..8e36660c0e 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java @@ -17,11 +17,15 @@ import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; import org.dspace.content.service.DSpaceObjectLegacySupportService; import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.EntityService; +import org.dspace.content.service.EntityTypeService; 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.SiteService; import org.dspace.content.service.SupervisedItemService; import org.dspace.content.service.WorkspaceItemService; @@ -68,6 +72,14 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory { @Autowired(required = true) private SiteService siteService; + @Autowired(required = true) + private RelationshipService relationshipService; + @Autowired(required = true) + private RelationshipTypeService relationshipTypeService; + @Autowired(required = true) + private EntityTypeService entityTypeService; + @Autowired(required = true) + private EntityService entityService; @Override public List> getDSpaceObjectServices() { @@ -143,4 +155,23 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory { public SiteService getSiteService() { return siteService; } + + @Override + public RelationshipTypeService getRelationshipTypeService() { + return relationshipTypeService; + } + + @Override + public RelationshipService getRelationshipService() { + return relationshipService; + } + + @Override + public EntityTypeService getEntityTypeService() { + return entityTypeService; + } + + public EntityService getEntityService() { + return entityService; + } } diff --git a/dspace-api/src/main/java/org/dspace/content/service/EntityService.java b/dspace-api/src/main/java/org/dspace/content/service/EntityService.java new file mode 100644 index 0000000000..37b27f238d --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/service/EntityService.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.service; + +import java.sql.SQLException; +import java.util.List; +import java.util.UUID; + +import org.dspace.content.Entity; +import org.dspace.content.EntityType; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.core.Context; + +public interface EntityService { + + Entity findByItemId(Context context, UUID itemId) throws SQLException; + EntityType getType(Context context, Entity entity) throws SQLException; + List getAllRelations(Context context, Entity entity); + List getLeftRelations(Context context, Entity entity); + List getRightRelations(Context context, Entity entity); + List getRelationsByLabel(Context context, String label) throws SQLException; + List getAllRelationshipTypes(Context context, Entity entity) throws SQLException; + List getLeftRelationshipTypes(Context context, Entity entity) throws SQLException; + List getRightRelationshipTypes(Context context, Entity entity) throws SQLException; + List getRelationshipTypesByLabel(Context context, String label) throws SQLException; + +} diff --git a/dspace-api/src/main/java/org/dspace/content/service/EntityTypeService.java b/dspace-api/src/main/java/org/dspace/content/service/EntityTypeService.java new file mode 100644 index 0000000000..796ce666c2 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/service/EntityTypeService.java @@ -0,0 +1,25 @@ +/** + * 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.service; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.core.Context; +import org.dspace.service.DSpaceCRUDService; + +public interface EntityTypeService extends DSpaceCRUDService { + + public EntityType findByEntityType(Context context,String entityType) throws SQLException; + + public List findAll(Context context) throws SQLException; + + public EntityType create(Context context, String entityTypeString) throws SQLException, AuthorizeException; +} 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 bfc01fbf84..f604d2d6bb 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 @@ -23,6 +23,7 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; import org.dspace.content.Thumbnail; import org.dspace.content.WorkspaceItem; import org.dspace.core.Context; @@ -639,4 +640,7 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * @throws SQLException if database error */ boolean isInProgressSubmission(Context context, Item item) throws SQLException; + + public List getRelationshipMetadata(Item item); + } diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java new file mode 100644 index 0000000000..35a0ec381d --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -0,0 +1,29 @@ +/** + * 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.service; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.core.Context; +import org.dspace.service.DSpaceCRUDService; + +public interface RelationshipService extends DSpaceCRUDService { + public List findByItem(Context context,Item item) throws SQLException; + + public List findAll(Context context) throws SQLException; + + public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException; + + int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException; + + int findRightPlaceByRightItem(Context context, Item item) throws SQLException; +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java new file mode 100644 index 0000000000..76892e7800 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java @@ -0,0 +1,27 @@ +/** + * 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.service; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.core.Context; +import org.dspace.service.DSpaceCRUDService; + +public interface RelationshipTypeService extends DSpaceCRUDService { + + RelationshipType create(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException; + + RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, + String leftLabel,String rightLabel) + throws SQLException; + List findAll(Context context) throws SQLException; +} diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/EntityTypeToFilterQueryService.java b/dspace-api/src/main/java/org/dspace/content/virtual/EntityTypeToFilterQueryService.java new file mode 100644 index 0000000000..ff2ca43111 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/EntityTypeToFilterQueryService.java @@ -0,0 +1,31 @@ +/** + * 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.virtual; + +import java.util.Map; + +public class EntityTypeToFilterQueryService { + + private Map map; + + public void setMap(Map map) { + this.map = map; + } + + public Map getMap() { + return map; + } + + public String getFilterQueryForKey(String key) { + return map.get(key); + } + + public boolean hasKey(String key) { + return map.containsKey(key); + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java new file mode 100644 index 0000000000..29555b493c --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java @@ -0,0 +1,23 @@ +/** + * 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.virtual; + +import java.util.Map; + +public class VirtualMetadataPopulator { + + private Map map; + + public void setMap(Map map) { + this.map = map; + } + + public Map getMap() { + return map; + } +} diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java index 209dec554b..0f4e92fdda 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseRegistryUpdater.java @@ -71,6 +71,13 @@ public class DatabaseRegistryUpdater implements FlywayCallback { MetadataImporter.loadRegistry(base + "dublin-core-types.xml", true); MetadataImporter.loadRegistry(base + "dcterms-types.xml", true); MetadataImporter.loadRegistry(base + "local-types.xml", true); + MetadataImporter.loadRegistry(base + "relationship-formats.xml", true); + MetadataImporter.loadRegistry(base + "person-types.xml", true); + MetadataImporter.loadRegistry(base + "project-types.xml", true); + MetadataImporter.loadRegistry(base + "orgunit-types.xml", true); + MetadataImporter.loadRegistry(base + "journal-types.xml", true); + MetadataImporter.loadRegistry(base + "journalissue-types.xml", true); + MetadataImporter.loadRegistry(base + "journalvolume-types.xml", true); MetadataImporter.loadRegistry(base + "eperson-types.xml", true); MetadataImporter.loadRegistry(base + "sword-metadata.xml", true); @@ -163,6 +170,5 @@ public class DatabaseRegistryUpdater implements FlywayCallback { @Override public void afterInfo(Connection connection) { - } } diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql new file mode 100644 index 0000000000..52e290b923 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql @@ -0,0 +1,62 @@ +-- +-- 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/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------- +-- This will create the setup for the dspace 7 entities usage +------------------------------------------------------------- +CREATE SEQUENCE entity_type_id_seq; +CREATE SEQUENCE relationship_type_id_seq; +CREATE SEQUENCE relationship_id_seq; + +CREATE TABLE entity_type +( + id INTEGER NOT NULL PRIMARY KEY, + label varchar(32) UNIQUE NOT NULL +); + +CREATE TABLE relationship_type +( + id INTEGER NOT NULL PRIMARY KEY, + left_type INTEGER NOT NULL, + right_type INTEGER NOT NULL, + left_label varchar(32) NOT NULL, + right_label varchar(32) NOT NULL, + left_min_cardinality INTEGER, + left_max_cardinality INTEGER, + right_min_cardinality INTEGER, + right_max_cardinality INTEGER, + FOREIGN KEY (left_type) REFERENCES entity_type(id), + FOREIGN KEY (right_type) REFERENCES entity_type(id) +); + +CREATE TABLE relationship +( + id INTEGER NOT NULL PRIMARY KEY, + left_id uuid NOT NULL REFERENCES item(uuid), + type_id INTEGER NOT NULL REFERENCES relationship_type(id), + right_id uuid NOT NULL REFERENCES item(uuid), + left_place INTEGER, + right_place INTEGER, + CONSTRAINT u_constraint UNIQUE (left_id, type_id, right_id) + +); + +CREATE INDEX entity_type_label_idx ON entity_type(label); +CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); +CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); +CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); +CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql new file mode 100644 index 0000000000..f06e64e6f8 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql @@ -0,0 +1,62 @@ +-- +-- 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/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------- +-- This will create the setup for the dspace 7 entities usage +------------------------------------------------------------- +CREATE SEQUENCE entity_type_id_seq; +CREATE SEQUENCE relationship_type_id_seq; +CREATE SEQUENCE relationship_id_seq; + +CREATE TABLE entity_type +( + id INTEGER NOT NULL PRIMARY KEY, + label varchar(32) UNIQUE NOT NULL +); + +CREATE TABLE relationship_type +( + id INTEGER NOT NULL PRIMARY KEY, + left_type INTEGER NOT NULL, + right_type INTEGER NOT NULL, + left_label varchar(32) NOT NULL, + right_label varchar(32) NOT NULL, + left_min_cardinality INTEGER, + left_max_cardinality INTEGER, + right_min_cardinality INTEGER, + right_max_cardinality INTEGER, + FOREIGN KEY (left_type) REFERENCES entity_type(id), + FOREIGN KEY (right_type) REFERENCES entity_type(id) +); + +CREATE TABLE relationship +( + id INTEGER NOT NULL PRIMARY KEY, + left_id uuid NOT NULL REFERENCES item(uuid), + type_id INTEGER NOT NULL REFERENCES relationship_type(id), + right_id uuid NOT NULL REFERENCES item(uuid), + left_place INTEGER, + right_place INTEGER, + CONSTRAINT u_constraint UNIQUE (left_id, type_id, right_id) + +); + +CREATE INDEX entity_type_label_idx ON entity_type(label); +CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); +CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); +CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); +CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql new file mode 100644 index 0000000000..f06e64e6f8 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql @@ -0,0 +1,62 @@ +-- +-- 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/ +-- + +-- =============================================================== +-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +-- +-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED +-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE. +-- http://flywaydb.org/ +-- =============================================================== + +------------------------------------------------------------- +-- This will create the setup for the dspace 7 entities usage +------------------------------------------------------------- +CREATE SEQUENCE entity_type_id_seq; +CREATE SEQUENCE relationship_type_id_seq; +CREATE SEQUENCE relationship_id_seq; + +CREATE TABLE entity_type +( + id INTEGER NOT NULL PRIMARY KEY, + label varchar(32) UNIQUE NOT NULL +); + +CREATE TABLE relationship_type +( + id INTEGER NOT NULL PRIMARY KEY, + left_type INTEGER NOT NULL, + right_type INTEGER NOT NULL, + left_label varchar(32) NOT NULL, + right_label varchar(32) NOT NULL, + left_min_cardinality INTEGER, + left_max_cardinality INTEGER, + right_min_cardinality INTEGER, + right_max_cardinality INTEGER, + FOREIGN KEY (left_type) REFERENCES entity_type(id), + FOREIGN KEY (right_type) REFERENCES entity_type(id) +); + +CREATE TABLE relationship +( + id INTEGER NOT NULL PRIMARY KEY, + left_id uuid NOT NULL REFERENCES item(uuid), + type_id INTEGER NOT NULL REFERENCES relationship_type(id), + right_id uuid NOT NULL REFERENCES item(uuid), + left_place INTEGER, + right_place INTEGER, + CONSTRAINT u_constraint UNIQUE (left_id, type_id, right_id) + +); + +CREATE INDEX entity_type_label_idx ON entity_type(label); +CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); +CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); +CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); +CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file diff --git a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml new file mode 100644 index 0000000000..23604d7c71 --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml @@ -0,0 +1,112 @@ + + + + Publication + Person + isAuthorOfPublication + isPublicationOfAuthor + + 0 + + + 0 + + + + Publication + Project + isProjectOfPublication + isPublicationOfProject + + 0 + + + 0 + + + + Publication + OrgUnit + isOrgUnitOfPublication + isPublicationOfOrgUnit + + 0 + + + 0 + + + + Person + Project + isProjectOfPerson + isPersonOfProject + + 0 + + + 0 + + + + Person + OrgUnit + isOrgUnitOfPerson + isPersonOfOrgUnit + + 0 + + + 0 + + + + Project + OrgUnit + isOrgUnitOfProject + isProjectOfOrgUnit + + 0 + + + 0 + + + + Journal + JournalVolume + isVolumeOfJournal + isJournalOfVolume + + 0 + + + 1 + + + + JournalVolume + JournalIssue + isIssueOfJournalVolume + isJournalVolumeOfIssue + + 0 + + + 1 + 1 + + + + Publication + OrgUnit + isAuthorOfPublication + isPublicationOfAuthor + + 0 + + + 0 + + + \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java index 0ba085fab1..76dbb6fce5 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java @@ -9,6 +9,7 @@ package org.dspace.app.rest; import javax.servlet.http.HttpServletRequest; +import org.apache.log4j.Logger; import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RootRest; import org.dspace.app.rest.model.hateoas.RootResource; @@ -39,20 +40,15 @@ public class RootRestResourceController { @Autowired RootRestRepository rootRestRepository; + private static Logger log = Logger.getLogger(RootRestResourceController.class); + @RequestMapping(method = RequestMethod.GET) public RootResource listDefinedEndpoint(HttpServletRequest request) { - String restUrl = getRestURL(request); - - RootRest rootRest = rootRestRepository.getRoot(restUrl); + RootRest rootRest = rootRestRepository.getRoot(); RootResource rootResource = new RootResource(rootRest); halLinkService.addLinks(rootResource); return rootResource; } - - private String getRestURL(HttpServletRequest request) { - String url = request.getRequestURL().toString(); - return url.substring(0, url.length() - request.getRequestURI().length()) + request.getContextPath(); - } } \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DSpaceObjectConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DSpaceObjectConverter.java index 5f02ae8de0..d330056f9b 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DSpaceObjectConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DSpaceObjectConverter.java @@ -34,16 +34,22 @@ public abstract class DSpaceObjectConverter fullList = obj.getMetadata(); + List metadata = convertMetadataToRest(fullList); + resource.setMetadata(metadata); + return resource; + } + + public List convertMetadataToRest(List fullList) { List metadata = new ArrayList(); - for (MetadataValue mv : obj.getMetadata()) { + for (MetadataValue mv : fullList) { MetadataEntryRest me = new MetadataEntryRest(); me.setKey(mv.getMetadataField().toString('.')); me.setValue(mv.getValue()); me.setLanguage(mv.getLanguage()); metadata.add(me); } - resource.setMetadata(metadata); - return resource; + return metadata; } @Override diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java index 45470c3e8e..9facb9500b 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java @@ -45,6 +45,9 @@ public class DiscoverResultConverter { @Autowired private List converters; + @Autowired + private ItemService itemService; + @Autowired private SearchService searchService; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/EntityTypeConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/EntityTypeConverter.java new file mode 100644 index 0000000000..33c2388c12 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/EntityTypeConverter.java @@ -0,0 +1,30 @@ +/** + * 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.rest.converter; + +import org.dspace.app.rest.model.EntityTypeRest; +import org.dspace.content.EntityType; +import org.springframework.stereotype.Component; + +@Component +public class EntityTypeConverter extends DSpaceConverter { + + public EntityTypeRest fromModel(EntityType obj) { + EntityTypeRest entityTypeRest = new EntityTypeRest(); + entityTypeRest.setId(obj.getId()); + entityTypeRest.setLabel(obj.getLabel()); + return entityTypeRest; + } + + public EntityType toModel(EntityTypeRest obj) { + EntityType entityType = new EntityType(); + entityType.setId(obj.getId()); + entityType.setLabel(obj.getLabel()); + return entityType; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/FilteredDiscoveryPageConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/FilteredDiscoveryPageConverter.java new file mode 100644 index 0000000000..2d67fedb3d --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/FilteredDiscoveryPageConverter.java @@ -0,0 +1,34 @@ +/** + * 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.rest.converter; + +import org.dspace.app.rest.model.FilteredDiscoveryPageRest; +import org.dspace.content.EntityType; +import org.dspace.content.virtual.EntityTypeToFilterQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class FilteredDiscoveryPageConverter extends DSpaceConverter { + @Autowired + private EntityTypeToFilterQueryService entityTypeToFilterQueryService; + + public FilteredDiscoveryPageRest fromModel(EntityType obj) { + FilteredDiscoveryPageRest filteredDiscoveryPageRest = new FilteredDiscoveryPageRest(); + filteredDiscoveryPageRest.setId(obj.getLabel()); + filteredDiscoveryPageRest.setLabel(obj.getLabel()); + filteredDiscoveryPageRest.setFilterQueryString( + entityTypeToFilterQueryService.getFilterQueryForKey(obj.getLabel())); + return filteredDiscoveryPageRest; + } + + public EntityType toModel(FilteredDiscoveryPageRest obj) { + return new EntityType(); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index 51fb456d72..fbc97af5fc 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -7,16 +7,25 @@ */ package org.dspace.app.rest.converter; +import java.sql.SQLException; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import org.apache.log4j.Logger; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.model.MetadataEntryRest; +import org.dspace.app.rest.model.RelationshipRest; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.Relationship; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -32,6 +41,12 @@ public class ItemConverter extends DSpaceObjectConverter relationships = new LinkedList<>(); + try { + relationships = relationshipService.findByItem(new Context(), obj); + } catch (SQLException e) { + log.error(e, e); + } + List relationshipRestList = new LinkedList<>(); + for (Relationship relationship : relationships) { + RelationshipRest relationshipRest = relationshipConverter.fromModel(relationship); + relationshipRestList.add(relationshipRest); + } + item.setRelationships(relationshipRestList); + + List fullList = new LinkedList<>(); + fullList.addAll(obj.getMetadata()); + fullList.addAll(itemService.getRelationshipMetadata(obj)); + + List metadata = super.convertMetadataToRest(fullList); + item.setMetadata(metadata); + + return item; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java new file mode 100644 index 0000000000..5cf32269ea --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java @@ -0,0 +1,58 @@ +/** + * 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.rest.converter; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.app.rest.model.RelationshipRest; +import org.dspace.content.Relationship; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class RelationshipConverter extends DSpaceConverter { + + private static final Logger log = Logger.getLogger(RelationshipConverter.class); + + @Autowired + private ItemService itemService; + + @Autowired + private RelationshipTypeConverter relationshipTypeConverter; + + + public RelationshipRest fromModel(Relationship obj) { + RelationshipRest relationshipRest = new RelationshipRest(); + relationshipRest.setId(obj.getId()); + relationshipRest.setLeftId(obj.getLeftItem().getID()); + relationshipRest.setRelationshipType(relationshipTypeConverter.fromModel(obj.getRelationshipType())); + relationshipRest.setRightId(obj.getRightItem().getID()); + relationshipRest.setLeftPlace(obj.getLeftPlace()); + relationshipRest.setRightPlace(obj.getRightPlace()); + return relationshipRest; + } + + public Relationship toModel(RelationshipRest obj) { + Relationship relationship = new Relationship(); + try { + Context context = new Context(); + relationship.setLeftItem(itemService.find(context, obj.getLeftId())); + relationship.setRightItem(itemService.find(context, obj.getRightId())); + } catch (SQLException e) { + log.error(e,e); + } + relationship.setRelationshipType(relationshipTypeConverter.toModel(obj.getRelationshipType())); + relationship.setLeftPlace(obj.getLeftPlace()); + relationship.setRightPlace(obj.getRightPlace()); + relationship.setId(obj.getId()); + return relationship; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java new file mode 100644 index 0000000000..3917b83456 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java @@ -0,0 +1,52 @@ +/** + * 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.rest.converter; + +import org.dspace.app.rest.model.RelationshipTypeRest; +import org.dspace.content.RelationshipType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class RelationshipTypeConverter extends DSpaceConverter { + + @Autowired + private EntityTypeConverter entityTypeConverter; + + public RelationshipTypeRest fromModel(RelationshipType obj) { + RelationshipTypeRest relationshipTypeRest = new RelationshipTypeRest(); + + relationshipTypeRest.setId(obj.getId()); + relationshipTypeRest.setLeftLabel(obj.getLeftLabel()); + relationshipTypeRest.setRightLabel(obj.getRightLabel()); + relationshipTypeRest.setLeftMinCardinality(obj.getLeftMinCardinality()); + relationshipTypeRest.setLeftMaxCardinality(obj.getLeftMaxCardinality()); + relationshipTypeRest.setRightMinCardinality(obj.getRightMinCardinality()); + relationshipTypeRest.setRightMaxCardinality(obj.getRightMaxCardinality()); + relationshipTypeRest.setLeftType(entityTypeConverter.fromModel(obj.getLeftType())); + relationshipTypeRest.setRightType(entityTypeConverter.fromModel(obj.getRightType())); + + return relationshipTypeRest; + } + + public RelationshipType toModel(RelationshipTypeRest obj) { + RelationshipType relationshipType = new RelationshipType(); + + relationshipType.setId(obj.getId()); + relationshipType.setLeftLabel(obj.getLeftLabel()); + relationshipType.setRightLabel(obj.getRightLabel()); + relationshipType.setLeftMinCardinality(obj.getLeftMinCardinality()); + relationshipType.setLeftMaxCardinality(obj.getLeftMaxCardinality()); + relationshipType.setRightMinCardinality(obj.getRightMinCardinality()); + relationshipType.setRightMaxCardinality(obj.getRightMaxCardinality()); + relationshipType.setLeftType(entityTypeConverter.toModel(obj.getLeftType())); + relationshipType.setRightType(entityTypeConverter.toModel(obj.getRightType())); + + return relationshipType; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RootConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RootConverter.java index 606f7f28ac..177b2244f7 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RootConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RootConverter.java @@ -21,11 +21,11 @@ public class RootConverter { @Autowired private ConfigurationService configurationService; - public RootRest convert(String restUrl) { + public RootRest convert() { RootRest rootRest = new RootRest(); rootRest.setDspaceName(configurationService.getProperty("dspace.name")); rootRest.setDspaceURL(configurationService.getProperty("dspace.url")); - rootRest.setDspaceRest(restUrl); + rootRest.setDspaceRest(configurationService.getProperty("dspace.restUrl")); return rootRest; } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/EntityTypeRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/EntityTypeRest.java new file mode 100644 index 0000000000..e77eb0d952 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/EntityTypeRest.java @@ -0,0 +1,38 @@ +/** + * 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.rest.model; + +import org.dspace.app.rest.RestResourceController; + +public class EntityTypeRest extends BaseObjectRest { + + public static final String NAME = "entitytype"; + public static final String CATEGORY = "core"; + + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return RestResourceController.class; + } + + public String getType() { + return NAME; + } + + private String label; + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/FilteredDiscoveryPageRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/FilteredDiscoveryPageRest.java new file mode 100644 index 0000000000..9450d03a41 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/FilteredDiscoveryPageRest.java @@ -0,0 +1,48 @@ +/** + * 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.rest.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.dspace.app.rest.RestResourceController; + +public class FilteredDiscoveryPageRest extends BaseObjectRest { + + public static final String NAME = "filtered-discovery-page"; + public static final String CATEGORY = "config"; + + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return RestResourceController.class; + } + + public String getType() { + return NAME; + } + + @JsonProperty(value = "filter-name") + private String label; + @JsonProperty(value = "discovery-query") + private String filterQueryString; + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public void setFilterQueryString(String filterQueryString) { + this.filterQueryString = filterQueryString; } + + public String getFilterQueryString() { + return this.filterQueryString; } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ItemRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ItemRest.java index 292f2a29c2..af02574f09 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ItemRest.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ItemRest.java @@ -32,6 +32,8 @@ public class ItemRest extends DSpaceObjectRest { List bitstreams; + List relationships; + @Override public String getCategory() { return CATEGORY; @@ -100,4 +102,13 @@ public class ItemRest extends DSpaceObjectRest { this.bitstreams = bitstreams; } + @LinkRest(linkClass = RelationshipRest.class) + @JsonIgnore + public List getRelationships() { + return relationships; + } + + public void setRelationships(List relationships) { + this.relationships = relationships; + } } \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRest.java new file mode 100644 index 0000000000..3a4770b02c --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRest.java @@ -0,0 +1,79 @@ +/** + * 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.rest.model; + +import java.util.UUID; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dspace.app.rest.RestResourceController; + +public class RelationshipRest extends BaseObjectRest { + public static final String NAME = "relationship"; + public static final String CATEGORY = "core"; + + private UUID leftId; + private RelationshipTypeRest relationshipType; + private UUID rightId; + private int leftPlace; + private int rightPlace; + + public String getType() { + return NAME; + } + + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return RestResourceController.class; + } + + public UUID getLeftId() { + return leftId; + } + + public void setLeftId(UUID leftId) { + this.leftId = leftId; + } + + @LinkRest(linkClass = RelationshipTypeRest.class) + @JsonIgnore + public RelationshipTypeRest getRelationshipType() { + return relationshipType; + } + + public void setRelationshipType(RelationshipTypeRest relationshipType) { + this.relationshipType = relationshipType; + } + + public UUID getRightId() { + return rightId; + } + + public void setRightId(UUID rightId) { + this.rightId = rightId; + } + + public int getLeftPlace() { + return leftPlace; + } + + public void setLeftPlace(int leftPlace) { + this.leftPlace = leftPlace; + } + + public int getRightPlace() { + return rightPlace; + } + + public void setRightPlace(int rightPlace) { + this.rightPlace = rightPlace; + } + +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRest.java new file mode 100644 index 0000000000..45c6f48285 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRest.java @@ -0,0 +1,106 @@ +/** + * 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.rest.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.dspace.app.rest.RestResourceController; + +public class RelationshipTypeRest extends BaseObjectRest { + + public static final String NAME = "relationshiptype"; + public static final String CATEGORY = "core"; + + private String leftLabel; + private String rightLabel; + private int leftMinCardinality; + private int leftMaxCardinality; + private int rightMinCardinality; + private int rightMaxCardinality; + private EntityTypeRest leftType; + private EntityTypeRest rightType; + + public String getType() { + return NAME; + } + + public String getCategory() { + return CATEGORY; + } + + public Class getController() { + return RestResourceController.class; + } + + public String getLeftLabel() { + return leftLabel; + } + + public void setLeftLabel(String leftLabel) { + this.leftLabel = leftLabel; + } + + public String getRightLabel() { + return rightLabel; + } + + public void setRightLabel(String rightLabel) { + this.rightLabel = rightLabel; + } + + public int getLeftMinCardinality() { + return leftMinCardinality; + } + + public void setLeftMinCardinality(int leftMinCardinality) { + this.leftMinCardinality = leftMinCardinality; + } + + public int getLeftMaxCardinality() { + return leftMaxCardinality; + } + + public void setLeftMaxCardinality(int leftMaxCardinality) { + this.leftMaxCardinality = leftMaxCardinality; + } + + public int getRightMinCardinality() { + return rightMinCardinality; + } + + public void setRightMinCardinality(int rightMinCardinality) { + this.rightMinCardinality = rightMinCardinality; + } + + public int getRightMaxCardinality() { + return rightMaxCardinality; + } + + public void setRightMaxCardinality(int rightMaxCardinality) { + this.rightMaxCardinality = rightMaxCardinality; + } + + @LinkRest(linkClass = EntityTypeRest.class) + @JsonIgnore + public EntityTypeRest getLeftType() { + return leftType; + } + + public void setLeftType(EntityTypeRest leftType) { + this.leftType = leftType; + } + + @LinkRest(linkClass = EntityTypeRest.class) + @JsonIgnore + public EntityTypeRest getRightType() { + return rightType; + } + + public void setRightType(EntityTypeRest rightType) { + this.rightType = rightType; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java index dda7e76922..e1f423ed63 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java @@ -28,6 +28,7 @@ import org.dspace.app.rest.utils.Utils; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.hateoas.Link; /** @@ -119,12 +120,14 @@ public abstract class DSpaceResource extends HAL linkedRMList.get(0).getType()); // TODO should we force pagination also of embedded resource? // This will force pagination with size 10 for embedded collections as well -// int pageSize = 1; -// PageImpl page = new PageImpl( -// linkedRMList.subList(0, -// linkedRMList.size() > pageSize ? pageSize : linkedRMList.size()), -// new PageRequest(0, pageSize), linkedRMList.size()); - PageImpl page = new PageImpl(linkedRMList); + int pageSize = 20; + PageImpl page = new PageImpl( + linkedRMList.subList(0, + linkedRMList + .size() > pageSize ? pageSize : linkedRMList + .size()), + new PageRequest(0, pageSize), linkedRMList.size()); +// PageImpl page = new PageImpl(linkedRMList); wrapObject = new EmbeddedPage(linkToSubResource.getHref(), page.map(resourceRepository::wrapResource), linkedRMList, name); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/EntityTypeResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/EntityTypeResource.java new file mode 100644 index 0000000000..ea8c6a6193 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/EntityTypeResource.java @@ -0,0 +1,19 @@ +/** + * 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.rest.model.hateoas; + +import org.dspace.app.rest.model.EntityTypeRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +@RelNameDSpaceResource(EntityTypeRest.NAME) +public class EntityTypeResource extends DSpaceResource { + public EntityTypeResource(EntityTypeRest data, Utils utils, String... rels) { + super(data, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/FilteredDiscoveryPageResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/FilteredDiscoveryPageResource.java new file mode 100644 index 0000000000..29740ca810 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/FilteredDiscoveryPageResource.java @@ -0,0 +1,20 @@ +/** + * 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.rest.model.hateoas; + +import org.dspace.app.rest.model.FilteredDiscoveryPageRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +@RelNameDSpaceResource(FilteredDiscoveryPageRest.NAME) +public class FilteredDiscoveryPageResource extends DSpaceResource { + public FilteredDiscoveryPageResource(FilteredDiscoveryPageRest data, Utils utils, + String... rels) { + super(data, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java new file mode 100644 index 0000000000..86fddbabdc --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java @@ -0,0 +1,19 @@ +/** + * 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.rest.model.hateoas; + +import org.dspace.app.rest.model.RelationshipRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +@RelNameDSpaceResource(RelationshipRest.NAME) +public class RelationshipResource extends DSpaceResource { + public RelationshipResource(RelationshipRest data, Utils utils, String... rels) { + super(data, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipTypeResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipTypeResource.java new file mode 100644 index 0000000000..387e29396c --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipTypeResource.java @@ -0,0 +1,19 @@ +/** + * 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.rest.model.hateoas; + +import org.dspace.app.rest.model.RelationshipTypeRest; +import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource; +import org.dspace.app.rest.utils.Utils; + +@RelNameDSpaceResource(RelationshipTypeRest.NAME) +public class RelationshipTypeResource extends DSpaceResource { + public RelationshipTypeResource(RelationshipTypeRest data, Utils utils, String... rels) { + super(data, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java new file mode 100644 index 0000000000..cb4599fdb5 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java @@ -0,0 +1,60 @@ +/** + * 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.rest.repository; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.app.rest.converter.EntityTypeConverter; +import org.dspace.app.rest.model.EntityTypeRest; +import org.dspace.app.rest.model.hateoas.DSpaceResource; +import org.dspace.app.rest.model.hateoas.EntityTypeResource; +import org.dspace.content.EntityType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +@Component(EntityTypeRest.CATEGORY + "." + EntityTypeRest.NAME) +public class EntityTypeRestRepository extends DSpaceRestRepository { + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private EntityTypeConverter entityTypeConverter; + + public EntityTypeRest findOne(Context context, Integer integer) { + try { + return entityTypeConverter.fromModel(entityTypeService.find(context, integer)); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public Page findAll(Context context, Pageable pageable) { + List entityTypeList = null; + try { + entityTypeList = entityTypeService.findAll(context); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + Page page = utils.getPage(entityTypeList, pageable).map(entityTypeConverter); + return page; + } + + public Class getDomainClass() { + return EntityTypeRest.class; + } + + public DSpaceResource wrapResource(EntityTypeRest model, String... rels) { + return new EntityTypeResource(model, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/FilteredDiscoveryPageRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/FilteredDiscoveryPageRestRepository.java new file mode 100644 index 0000000000..c49c0daf08 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/FilteredDiscoveryPageRestRepository.java @@ -0,0 +1,71 @@ +/** + * 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.rest.repository; + +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; + +import org.dspace.app.rest.converter.FilteredDiscoveryPageConverter; +import org.dspace.app.rest.model.FilteredDiscoveryPageRest; +import org.dspace.app.rest.model.hateoas.DSpaceResource; +import org.dspace.app.rest.model.hateoas.FilteredDiscoveryPageResource; +import org.dspace.content.EntityType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.virtual.EntityTypeToFilterQueryService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +@Component(FilteredDiscoveryPageRest.CATEGORY + "." + FilteredDiscoveryPageRest.NAME) +public class FilteredDiscoveryPageRestRepository extends DSpaceRestRepository { + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private FilteredDiscoveryPageConverter filteredDiscoveryPageConverter; + + @Autowired + private EntityTypeToFilterQueryService entityTypeToFilterQueryService; + + public FilteredDiscoveryPageRest findOne(Context context, String string) { + try { + return filteredDiscoveryPageConverter.fromModel(entityTypeService.findByEntityType(context, string)); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public Page findAll(Context context, Pageable pageable) { + List entityTypeList = null; + try { + entityTypeList = entityTypeService.findAll(context); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + List resultingList = new LinkedList<>(); + for (EntityType entityType : entityTypeList) { + if (entityTypeToFilterQueryService.hasKey(entityType.getLabel())) { + resultingList.add(entityType); + } + } + Page page = utils.getPage(resultingList, pageable) + .map(filteredDiscoveryPageConverter); + return page; } + + public Class getDomainClass() { + return FilteredDiscoveryPageRest.class; + } + + public DSpaceResource wrapResource(FilteredDiscoveryPageRest model, String... rels) { + return new FilteredDiscoveryPageResource(model, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java new file mode 100644 index 0000000000..c7359869cc --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -0,0 +1,60 @@ +/** + * 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.rest.repository; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.app.rest.converter.RelationshipConverter; +import org.dspace.app.rest.model.RelationshipRest; +import org.dspace.app.rest.model.hateoas.DSpaceResource; +import org.dspace.app.rest.model.hateoas.RelationshipResource; +import org.dspace.content.Relationship; +import org.dspace.content.service.RelationshipService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +@Component(RelationshipRest.CATEGORY + "." + RelationshipRest.NAME) +public class RelationshipRestRepository extends DSpaceRestRepository { + + @Autowired + private RelationshipService relationshipService; + + @Autowired + private RelationshipConverter relationshipConverter; + + public RelationshipRest findOne(Context context, Integer integer) { + try { + return relationshipConverter.fromModel(relationshipService.find(context, integer)); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public Page findAll(Context context, Pageable pageable) { + List relationships = null; + try { + relationships = relationshipService.findAll(context); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + Page page = utils.getPage(relationships, pageable).map(relationshipConverter); + return page; + } + + public Class getDomainClass() { + return RelationshipRest.class; + } + + public DSpaceResource wrapResource(RelationshipRest model, String... rels) { + return new RelationshipResource(model, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipTypeRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipTypeRestRepository.java new file mode 100644 index 0000000000..030bb56e93 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipTypeRestRepository.java @@ -0,0 +1,60 @@ +/** + * 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.rest.repository; + +import java.sql.SQLException; +import java.util.List; + +import org.dspace.app.rest.converter.RelationshipTypeConverter; +import org.dspace.app.rest.model.RelationshipTypeRest; +import org.dspace.app.rest.model.hateoas.DSpaceResource; +import org.dspace.app.rest.model.hateoas.RelationshipTypeResource; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Component; + +@Component(RelationshipTypeRest.CATEGORY + "." + RelationshipTypeRest.NAME) +public class RelationshipTypeRestRepository extends DSpaceRestRepository { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private RelationshipTypeConverter relationshipTypeConverter; + + public RelationshipTypeRest findOne(Context context, Integer integer) { + try { + return relationshipTypeConverter.fromModel(relationshipTypeService.find(context, integer)); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public Page findAll(Context context, Pageable pageable) { + List relationshipTypeList = null; + try { + relationshipTypeList = relationshipTypeService.findAll(context); + } catch (SQLException e) { + throw new RuntimeException(e.getMessage(), e); + } + Page page = utils.getPage(relationshipTypeList, pageable).map(relationshipTypeConverter); + return page; + } + + public Class getDomainClass() { + return RelationshipTypeRest.class; + } + + public DSpaceResource wrapResource(RelationshipTypeRest model, String... rels) { + return new RelationshipTypeResource(model, utils, rels); + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RootRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RootRestRepository.java index e81a530b5e..54c678c18e 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RootRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RootRestRepository.java @@ -21,7 +21,7 @@ public class RootRestRepository { @Autowired RootConverter rootConverter; - public RootRest getRoot(String restUrl) { - return rootConverter.convert(restUrl); + public RootRest getRoot() { + return rootConverter.convert(); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java new file mode 100644 index 0000000000..edf83871d5 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java @@ -0,0 +1,147 @@ +/** + * 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.rest; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.sql.SQLException; +import java.util.List; + +import org.dspace.app.rest.matcher.EntityTypeMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + } + + @After + public void destroy() throws SQLException, AuthorizeException { + + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + + for (RelationshipType relationshipType : relationshipTypeList) { + relationshipTypeService.delete(context, relationshipType); + } + + for (EntityType entityType : entityTypeList) { + entityTypeService.delete(context, entityType); + } + context.restoreAuthSystemState(); + } + @Test + public void findAllEntityTypesSizeTest() throws SQLException { + assertEquals(7, entityTypeService.findAll(context).size()); + } + + @Test + public void findPublicationEntityTypeTest() throws SQLException { + String type = "Publication"; + checkEntityType(type); + } + + @Test + public void findPersonEntityTypeTest() throws SQLException { + String type = "Person"; + checkEntityType(type); + } + + @Test + public void findProjectEntityTypeTest() throws SQLException { + String type = "Project"; + checkEntityType(type); + } + + @Test + public void findOrgUnitEntityTypeTest() throws SQLException { + String type = "OrgUnit"; + checkEntityType(type); + } + + @Test + public void findJournalEntityTypeTest() throws SQLException { + String type = "Journal"; + checkEntityType(type); + } + + @Test + public void findJournalVolumeEntityTypeTest() throws SQLException { + String type = "JournalVolume"; + checkEntityType(type); + } + + @Test + public void findJournalIssueEntityTypeTest() throws SQLException { + String type = "JournalIssue"; + checkEntityType(type); + } + private void checkEntityType(String type) throws SQLException { + EntityType entityType = entityTypeService.findByEntityType(context, type); + assertNotNull(entityType); + assertEquals(type, entityType.getLabel()); + } + + @Test + public void getAllEntityTypeEndpoint() throws Exception { + //When we call this facets endpoint + getClient().perform(get("/api/core/entitytypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.totalElements", is(7))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/entitytypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.entitytypes", containsInAnyOrder( + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Publication")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Person")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Project")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "OrgUnit")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Journal")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalVolume")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalIssue")) + ))); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java new file mode 100644 index 0000000000..25831f257d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -0,0 +1,171 @@ +package org.dspace.app.rest; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.sql.SQLException; +import java.util.List; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.builder.RelationshipBuilder; +import org.dspace.app.rest.matcher.PageMatcher; +import org.dspace.app.rest.matcher.RelationshipMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.EntityType; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + + + } + + @After + public void destroy() throws SQLException, AuthorizeException { + + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + + for (RelationshipType relationshipType : relationshipTypeList) { + relationshipTypeService.delete(context, relationshipType); + } + + for (EntityType entityType : entityTypeList) { + entityTypeService.delete(context, entityType); + } + context.restoreAuthSystemState(); + } + + @Test + public void findAllRelationshipTest() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item auhor1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col2) + .withTitle("Author2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria") + .withRelationshipType("Person") + .build(); + + Item author3 = ItemBuilder.createItem(context, col2) + .withTitle("Author3") + .withIssueDate("2016-02-13") + .withAuthor("Maybe, Maybe") + .withRelationshipType("Person") + .build(); + + Item orgUnit1 = ItemBuilder.createItem(context, col3) + .withTitle("OrgUnit1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("OrgUnit") + .build(); + + Item project1 = ItemBuilder.createItem(context, col3) + .withTitle("Project1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Project") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + + RelationshipType isOrgUnitOfPersonRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, + entityTypeService + .findByEntityType(context, + "Person"), + entityTypeService + .findByEntityType(context, + "OrgUnit"), + "isOrgUnitOfPerson", + "isPersonOfOrgUnit"); + + RelationshipType isOrgUnitOfProjectRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, + entityTypeService.findByEntityType(context, "Project"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isOrgUnitOfProject", + "isProjectOfOrgUnit"); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, + entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", + "isPublicationOfAuthor"); + Relationship relationship1 = RelationshipBuilder.createRelationshipBuilder(context, auhor1, orgUnit1, isOrgUnitOfPersonRelationshipType).build(); + + Relationship relationship2 = RelationshipBuilder.createRelationshipBuilder(context, project1, orgUnit1, isOrgUnitOfProjectRelationshipType).build(); + + Relationship relationship3 = RelationshipBuilder.createRelationshipBuilder(context, publication, auhor1, isAuthorOfPublicationRelationshipType).build(); + + getClient().perform(get("/api/core/relationships")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3)))) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1), + RelationshipMatcher.matchRelationship(relationship2), + RelationshipMatcher.matchRelationship(relationship3) + ))) + ; } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java new file mode 100644 index 0000000000..9ebfafab84 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java @@ -0,0 +1,265 @@ +/** + * 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.rest; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.sql.SQLException; +import java.util.List; + +import javax.transaction.Transactional; + +import org.dspace.app.rest.matcher.EntityTypeMatcher; +import org.dspace.app.rest.matcher.RelationshipTypeMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.h2.util.StringUtils; +import org.jbibtex.StringUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + } + + @After + public void destroy() throws SQLException, AuthorizeException { + + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + + for (RelationshipType relationshipType : relationshipTypeList) { + relationshipTypeService.delete(context, relationshipType); + } + + for (EntityType entityType : entityTypeList) { + entityTypeService.delete(context, entityType); + } + context.restoreAuthSystemState(); + } + @Test + public void findAllRelationshipTypesTest() throws SQLException { + assertEquals(8, relationshipTypeService.findAll(context).size()); + } + + @Test + public void findPublicationPersonRelationshipType() throws SQLException { + String leftTypeString = "Publication"; + String rightTypeString = "Person"; + String leftLabel = "isAuthorOfPublication"; + String rightLabel = "isPublicationOfAuthor"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + + @Test + public void findPublicationProjectRelationshipType() throws SQLException { + String leftTypeString = "Publication"; + String rightTypeString = "Project"; + String leftLabel = "isProjectOfPublication"; + String rightLabel = "isPublicationOfProject"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findPublicationOrgUnitRelationshipType() throws SQLException { + String leftTypeString = "Publication"; + String rightTypeString = "OrgUnit"; + String leftLabel = "isOrgUnitOfPublication"; + String rightLabel = "isPublicationOfOrgUnit"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findPersonProjectRelationshipType() throws SQLException { + String leftTypeString = "Person"; + String rightTypeString = "Project"; + String leftLabel = "isProjectOfPerson"; + String rightLabel = "isPersonOfProject"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findPersonOrgUnitRelationshipType() throws SQLException { + String leftTypeString = "Person"; + String rightTypeString = "OrgUnit"; + String leftLabel = "isOrgUnitOfPerson"; + String rightLabel = "isPersonOfOrgUnit"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findProjectOrgUnitRelationshipType() throws SQLException { + String leftTypeString = "Project"; + String rightTypeString = "OrgUnit"; + String leftLabel = "isOrgUnitOfProject"; + String rightLabel = "isProjectOfOrgUnit"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findJournalJournalVolumeRelationshipType() throws SQLException { + String leftTypeString = "Journal"; + String rightTypeString = "JournalVolume"; + String leftLabel = "isVolumeOfJournal"; + String rightLabel = "isJournalOfVolume"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + @Test + public void findJournalVolumeJournalIssueRelationshipType() throws SQLException { + String leftTypeString = "JournalVolume"; + String rightTypeString = "JournalIssue"; + String leftLabel = "isIssueOfJournalVolume"; + String rightLabel = "isJournalVolumeOfIssue"; + checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); + } + private void checkRelationshipType(String leftType, String rightType, String leftLabel, String rightLabel) throws SQLException { + RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, + entityTypeService.findByEntityType(context,leftType), + entityTypeService.findByEntityType(context, rightType), + leftLabel, + rightLabel); + assertNotNull(relationshipType); + assertEquals(entityTypeService.findByEntityType(context, leftType), relationshipType.getLeftType()); + assertEquals(entityTypeService.findByEntityType(context, rightType), relationshipType.getRightType()); + assertEquals(leftLabel, relationshipType.getLeftLabel()); + assertEquals(rightLabel, relationshipType.getRightLabel()); + } + + @Test + public void getAllRelationshipTypesEndpointTest() throws Exception { + //When we call this facets endpoint + List relationshipTypes = relationshipTypeService.findAll(context); + + getClient().perform(get("/api/core/relationshiptypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.totalElements", is(8))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7))) + )); + } + + @Test + public void entityTypeForPublicationPersonRelationshipTypeTest() throws Exception{ + + List relationshipTypes = relationshipTypeService.findAll(context); + + RelationshipType foundRelationshipType = null; + for (RelationshipType relationshipType : relationshipTypes) { + if(StringUtils.equals(relationshipType.getLeftLabel(), "isAuthorOfPublication") && StringUtils.equals(relationshipType.getRightLabel(), "isPublicationOfAuthor")) { + foundRelationshipType = relationshipType; + break; + } + } + + if(foundRelationshipType != null) { + getClient().perform(get("/api/core/relationshiptypes/"+foundRelationshipType.getId())) + .andExpect(jsonPath("$._embedded.leftType", EntityTypeMatcher.matchEntityTypeEntryForLabel("Publication"))) + .andExpect(jsonPath("$._embedded.rightType", EntityTypeMatcher.matchEntityTypeEntryForLabel("Person"))); + } else { + throw new Exception("RelationshipType not found for isIssueOfJournalVolume"); + } + + } + + @Test + public void cardinalityOnAuthorPublicationRelationshipTypesTest() throws Exception{ + RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", "isPublicationOfAuthor"); + assertEquals(0, relationshipType.getLeftMinCardinality()); + assertEquals(0, relationshipType.getRightMinCardinality()); + assertEquals(Integer.MAX_VALUE, relationshipType.getLeftMaxCardinality()); + assertEquals(Integer.MAX_VALUE, relationshipType.getRightMaxCardinality()); + + getClient().perform(get("/api/core/relationshiptypes/"+relationshipType.getId())) + .andExpect(jsonPath("$.leftMinCardinality", is(0))) + .andExpect(jsonPath("$.rightMinCardinality", is(0))) + .andExpect(jsonPath("$.leftMaxCardinality", is(Integer.MAX_VALUE))) + .andExpect(jsonPath("$.rightMaxCardinality", is(Integer.MAX_VALUE))); + + } + + @Test + public void entityTypeForIssueJournalRelationshipTypeTest() throws Exception{ + + List relationshipTypes = relationshipTypeService.findAll(context); + + RelationshipType foundRelationshipType = null; + for (RelationshipType relationshipType : relationshipTypes) { + if(StringUtils.equals(relationshipType.getLeftLabel(), "isIssueOfJournalVolume") && StringUtils.equals(relationshipType.getRightLabel(), "isJournalVolumeOfIssue")) { + foundRelationshipType = relationshipType; + break; + } + } + + if(foundRelationshipType != null) { + getClient().perform(get("/api/core/relationshiptypes/"+foundRelationshipType.getId())) + .andExpect(jsonPath("$._embedded.leftType", EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalVolume"))) + .andExpect(jsonPath("$._embedded.rightType", EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalIssue"))); + } else { + throw new Exception("RelationshipType not found for isIssueOfJournalVolume"); + } + + } + @Test + public void cardinalityOnIssueJournalJournalVolumeRelationshipTypesTest() throws Exception{ + RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "JournalVolume"), entityTypeService.findByEntityType(context, "JournalIssue"), "isIssueOfJournalVolume", "isJournalVolumeOfIssue"); + assertEquals(0, relationshipType.getLeftMinCardinality()); + assertEquals(1, relationshipType.getRightMinCardinality()); + assertEquals(Integer.MAX_VALUE, relationshipType.getLeftMaxCardinality()); + assertEquals(1, relationshipType.getRightMaxCardinality()); + + getClient().perform(get("/api/core/relationshiptypes/"+relationshipType.getId())) + .andExpect(jsonPath("$.leftMinCardinality", is(0))) + .andExpect(jsonPath("$.rightMinCardinality", is(1))) + .andExpect(jsonPath("$.leftMaxCardinality", is(Integer.MAX_VALUE))) + .andExpect(jsonPath("$.rightMaxCardinality", is(1))); + + } + + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java index 553251633f..c4c744bc91 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java @@ -55,7 +55,7 @@ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegra .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect( - jsonPath("$._links.search.href", is(REST_SERVER_URL + "config/submissiondefinitions/search"))) + jsonPath("$._links.search.href", is(REST_SERVER_URL + "api/config/submissiondefinitions/search"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissiondefinitions", hasSize(greaterThanOrEqualTo(1)))) @@ -157,10 +157,10 @@ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegra hasJsonPath("$.type", is("submissionsection")), hasJsonPath("$._links.config.href", is(REST_SERVER_URL + - "config/submissionforms/traditionalpageone")), + "api/config/submissionforms/traditionalpageone")), hasJsonPath("$._links.self.href", is(REST_SERVER_URL + - "config/submissionsections/traditionalpageone")) + "api/config/submissionsections/traditionalpageone")) )))) ; } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java index 643debcbfc..9ff7cdef20 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java @@ -48,7 +48,7 @@ public class SubmissionSectionsControllerIT extends AbstractControllerIntegratio .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect(jsonPath("$._links.self.href", - Matchers.startsWith(REST_SERVER_URL + "config/submissionsections"))) + Matchers.startsWith(REST_SERVER_URL + "api/config/submissionsections"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissionsections", hasSize(greaterThanOrEqualTo(1)) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java index 07e570f609..f6b9d2dd86 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java @@ -48,7 +48,7 @@ public class SubmissionUploadsControllerIT extends AbstractControllerIntegration .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect(jsonPath("$._links.self.href", - Matchers.startsWith(REST_SERVER_URL + "config/submissionuploads"))) + Matchers.startsWith(REST_SERVER_URL + "api/config/submissionuploads"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissionuploads", hasSize(greaterThanOrEqualTo(1)))) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java index 29a219810e..04d1c20e63 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java @@ -27,6 +27,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.RelationshipService; import org.dspace.content.service.SiteService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; @@ -72,6 +73,7 @@ public abstract class AbstractBuilder { static MetadataFieldService metadataFieldService; static MetadataSchemaService metadataSchemaService; static SiteService siteService; + static RelationshipService relationshipService; protected Context context; @@ -107,6 +109,7 @@ public abstract class AbstractBuilder { metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService(); metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); siteService = ContentServiceFactory.getInstance().getSiteService(); + relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); // Temporarily disabled // TODO find a way to be able to test the XML and "default" workflow at the same time diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java index f21ba728ca..cf498cf0fb 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java @@ -67,6 +67,10 @@ public class ItemBuilder extends AbstractDSpaceObjectBuilder { return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "subject", null, subject); } + public ItemBuilder withRelationshipType(final String relationshipType) { + return addMetadataValue(item, "relationship", "type", null, relationshipType); + } + public ItemBuilder makeUnDiscoverable() { item.setDiscoverable(false); return this; diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java new file mode 100644 index 0000000000..2fc9b306fe --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java @@ -0,0 +1,80 @@ +package org.dspace.app.rest.builder; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.RelationshipService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; + +public class RelationshipBuilder extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(RelationshipBuilder.class); + + private Relationship relationship; + + protected RelationshipBuilder(Context context) { + super(context); + } + + @Override + protected RelationshipService getService() { + return relationshipService; + } + + protected void cleanup() throws Exception { + delete(relationship); + } + + public Relationship build() { + try { + + relationshipService.update(context, relationship); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException|SQLException|AuthorizeException e) { + log.error(e); + } + return relationship; + } + + public void delete(Relationship dso) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + Relationship attachedDso = c.reloadEntity(dso); + if (attachedDso != null) { + getService().delete(c, attachedDso); + } + c.complete(); + } + + indexingService.commit(); + } + + public static RelationshipBuilder createRelationshipBuilder(Context context, Item leftItem, Item rightItem, RelationshipType relationshipType) { + + RelationshipBuilder relationshipBuilder = new RelationshipBuilder(context); + return relationshipBuilder.create(context, leftItem, rightItem, relationshipType); + } + private RelationshipBuilder create(Context context, Item leftItem, Item rightItem, RelationshipType relationshipType) { + this.context = context; + + try { + relationship = new Relationship(); + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + relationship.setRelationshipType(relationshipType); + relationshipService.create(context, relationship); + } catch (SQLException|AuthorizeException e) { + e.printStackTrace(); + } + + return this; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java index 5ec396ec81..785e9ac07e 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/converter/RootConverterTest.java @@ -36,17 +36,18 @@ public class RootConverterTest { public void setUp() throws Exception { when(configurationService.getProperty("dspace.url")).thenReturn("dspaceurl"); when(configurationService.getProperty("dspace.name")).thenReturn("dspacename"); + when(configurationService.getProperty("dspace.restUrl")).thenReturn("rest"); } @Test public void testReturnCorrectClass() throws Exception { - assertEquals(rootConverter.convert("").getClass(), RootRest.class); + assertEquals(rootConverter.convert().getClass(), RootRest.class); } @Test public void testCorrectPropertiesSetFromConfigurationService() throws Exception { String restUrl = "rest"; - RootRest rootRest = rootConverter.convert(restUrl); + RootRest rootRest = rootConverter.convert(); assertEquals("dspaceurl", rootRest.getDspaceURL()); assertEquals("dspacename", rootRest.getDspaceName()); assertEquals(restUrl, rootRest.getDspaceRest()); @@ -54,6 +55,6 @@ public class RootConverterTest { @Test public void testReturnNotNull() throws Exception { - assertNotNull(rootConverter.convert("")); + assertNotNull(rootConverter.convert()); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java index 1ad8586574..2cba3f1f08 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BrowseIndexMatcher.java @@ -34,9 +34,9 @@ public class BrowseIndexMatcher { hasJsonPath("$.metadataBrowse", Matchers.is(true)), hasJsonPath("$.order", equalToIgnoringCase(order)), hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/subject")), - hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/subject/entries")), - hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/subject/items")) + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/discover/browses/subject")), + hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "api/discover/browses/subject/entries")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "api/discover/browses/subject/items")) ); } @@ -46,8 +46,8 @@ public class BrowseIndexMatcher { hasJsonPath("$.metadataBrowse", Matchers.is(false)), hasJsonPath("$.order", equalToIgnoringCase(order)), hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/title")), - hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/title/items")) + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/discover/browses/title")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "api/discover/browses/title/items")) ); } @@ -57,9 +57,9 @@ public class BrowseIndexMatcher { hasJsonPath("$.metadataBrowse", Matchers.is(true)), hasJsonPath("$.order", equalToIgnoringCase(order)), hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/author")), - hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/author/entries")), - hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/author/items")) + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/discover/browses/author")), + hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "api/discover/browses/author/entries")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "api/discover/browses/author/items")) ); } @@ -69,8 +69,8 @@ public class BrowseIndexMatcher { hasJsonPath("$.metadataBrowse", Matchers.is(false)), hasJsonPath("$.order", equalToIgnoringCase(order)), hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/dateissued")), - hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/dateissued/items")) + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/discover/browses/dateissued")), + hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "api/discover/browses/dateissued/items")) ); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EntityTypeMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EntityTypeMatcher.java new file mode 100644 index 0000000000..5686c9fd17 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EntityTypeMatcher.java @@ -0,0 +1,56 @@ +/** + * 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.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.dspace.content.Bitstream; +import org.dspace.content.EntityType; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class EntityTypeMatcher { + public static Matcher matchEntityTypeEntry(EntityType entityType) { + return matchEntityTypeExplicitValuesEntry(entityType.getId(), entityType.getLabel()); + } + public static Matcher matchEntityTypeEntryForLabel(String label) { + return matchEntityTypeExplicitValuesEntry(0, label); + } + + private static Matcher matchId(int id) { + return id == 0 ? + allOf( + hasJsonPath("$.id", Matchers.not(Matchers.empty())) + ) : + allOf( + hasJsonPath("$.id", Matchers.is(id)) + ); + } + + private static Matcher matchSelfLink(int id) { + return id == 0 ? + allOf( + hasJsonPath("$._links.self.href", containsString("/api/core/entitytypes/")) + ) : + allOf( + hasJsonPath("$._links.self.href", containsString("/api/core/entitytypes/" + id)) + ); + } + + public static Matcher matchEntityTypeExplicitValuesEntry(int id, String label) { + return allOf( + matchId(id), + hasJsonPath("$.label", is(label)), + hasJsonPath("$.type", is("entitytype")), + matchSelfLink(id) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java new file mode 100644 index 0000000000..dd858986ef --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java @@ -0,0 +1,34 @@ +package org.dspace.app.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.is; + +import java.util.UUID; + +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.hamcrest.Matcher; + +public class RelationshipMatcher { + + public static Matcher matchRelationship(Relationship relationship) { + return matchRelationshipExplicitValues(relationship.getLeftItem(), relationship.getRightItem(), relationship.getLeftPlace(), relationship.getRightPlace(), relationship.getRelationshipType()); + } + + private static Matcher matchRelationshipExplicitValues(Item leftItem, Item rightItem, int leftPlace, int rightPlace, RelationshipType relationshipType) { + return matchRelationshipExplicitObjectValues(leftItem.getID(), rightItem.getID(), leftPlace, rightPlace, relationshipType); + } + + private static Matcher matchRelationshipExplicitObjectValues(UUID leftId, UUID rightId, int leftPlace, int rightPlace, + RelationshipType relationshipType) { + return allOf( + hasJsonPath("$.leftId",is(leftId.toString())), + hasJsonPath("$.rightId", is(rightId.toString())), + hasJsonPath("$.leftPlace", is(leftPlace)), + hasJsonPath("$.rightPlace", is(rightPlace)), + hasJsonPath("$._embedded.relationshipType", RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType)) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java new file mode 100644 index 0000000000..f3fc20592d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java @@ -0,0 +1,70 @@ +/** + * 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.rest.matcher; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; + +import org.dspace.content.EntityType; +import org.dspace.content.RelationshipType; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; + +public class RelationshipTypeMatcher { + public static Matcher matchRelationshipTypeEntry(RelationshipType relationshipType) { + return matchRelationshipTypeExplicitEntityTypes(relationshipType, relationshipType.getLeftType(), relationshipType.getRightType()); + } + + private static Matcher matchRelationshipTypeExplicitEntityTypes(RelationshipType relationshipType, EntityType leftType, EntityType rightType) { + return matchRelationshipTypeExplicitEntityTypeValues(relationshipType, leftType.getId(), leftType.getLabel(), rightType.getId(), rightType.getLabel()); + } + + private static Matcher matchRelationshipTypeExplicitEntityTypeValues(RelationshipType relationshipType, int leftEntityTypeId, String leftEntityTypeLabel, int rightEntityTypeId, + String rightEntityTypeLabel) { + + return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(relationshipType.getId(), relationshipType.getLeftLabel(), relationshipType.getRightLabel(), + relationshipType.getLeftMinCardinality(), relationshipType.getLeftMaxCardinality(), + relationshipType.getRightMinCardinality(), relationshipType.getRightMaxCardinality(), + leftEntityTypeId, leftEntityTypeLabel, rightEntityTypeId, rightEntityTypeLabel); + } + + private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityType(int id, String leftLabel, String rightLabel, + int leftMinCardinality, int leftMaxCardinality, + int rightMinCardinality, int rightMaxCardinality, + EntityType leftEntityType, EntityType rightEntityType) { + return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(id, leftLabel, rightLabel, leftMinCardinality, leftMaxCardinality, rightMinCardinality, + rightMaxCardinality, leftEntityType.getId(), leftEntityType.getLabel(), + rightEntityType.getId(), rightEntityType.getLabel()); + } + + private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(int id, String leftLabel, String rightLabel, + int leftMinCardinality, int leftMaxCardinality, + int rightMinCardinality, int rightMaxCardinality, + int leftEntityTypeId, String leftEntityTypeLabel, + int rightEntityTypeId, String rightEntityTypeLabel) { + return allOf( + hasJsonPath("$.id", is(id)), + hasJsonPath("$.leftLabel", is(leftLabel)), + hasJsonPath("$.rightLabel", is(rightLabel)), + hasJsonPath("$.leftMinCardinality", is(leftMinCardinality)), + hasJsonPath("$.leftMaxCardinality", is(leftMaxCardinality)), + hasJsonPath("$.rightMinCardinality", is(rightMinCardinality)), + hasJsonPath("$.rightMaxCardinality", is(rightMaxCardinality)), + hasJsonPath("$.type", is("relationshiptype")), + hasJsonPath("$._links.self.href", containsString("/api/core/relationshiptypes/" + id)), + hasJsonPath("$._embedded.leftType", Matchers.allOf( + EntityTypeMatcher.matchEntityTypeExplicitValuesEntry(leftEntityTypeId, leftEntityTypeLabel) + )), + hasJsonPath("$._embedded.rightType", Matchers.is( + EntityTypeMatcher.matchEntityTypeExplicitValuesEntry(rightEntityTypeId, rightEntityTypeLabel) + )) + ); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java index d8e85f3495..c92f99c5e1 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java @@ -27,9 +27,9 @@ public class SubmissionDefinitionsMatcher { hasJsonPath("$.name", is(name)), hasJsonPath("$.id", is(id)), hasJsonPath("$.type", is("submissiondefinition")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "config/submissiondefinitions/" + id)), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/config/submissiondefinitions/" + id)), hasJsonPath("$._links.sections.href", - is(REST_SERVER_URL + "config/submissiondefinitions/" + id + "/sections")) + is(REST_SERVER_URL + "api/config/submissiondefinitions/" + id + "/sections")) ); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java index f790aa230a..ade7327c33 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java @@ -34,6 +34,7 @@ import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.TestExecutionListeners; @@ -44,6 +45,8 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.RequestPostProcessor; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; import org.springframework.web.context.WebApplicationContext; @@ -69,7 +72,11 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi //sits before the actual authentication token and can be used to easily compose or parse the Authorization header. protected static final String AUTHORIZATION_TYPE = "Bearer "; - public static final String REST_SERVER_URL = "http://localhost/api/"; + protected static final String REQUEST_SCHEME = "http"; + protected static final String REQUEST_NAME = "localhost"; + protected static final int REQUEST_PORT = 8080; + protected static final String REQUEST_CONTEXTPATH = "rest"; + public static final String REST_SERVER_URL = REQUEST_SCHEME + "://" + REQUEST_NAME + ":" + REQUEST_PORT + "/" + REQUEST_CONTEXTPATH +"/"; protected MediaType contentType = new MediaType(MediaTypes.HAL_JSON.getType(), MediaTypes.HAL_JSON.getSubtype(), Charsets.UTF_8); @@ -109,10 +116,19 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi .addFilters(new ErrorPageFilter()) .addFilters(requestFilters.toArray(new Filter[requestFilters.size()])); + MockHttpServletRequestBuilder defaultRequestParameters = get("") + .with(request -> { + request.setScheme(REQUEST_SCHEME); + request.setServerName(REQUEST_NAME); + request.setServerPort(REQUEST_PORT); + request.setContextPath(REQUEST_CONTEXTPATH); + return request; + }); if (StringUtils.isNotBlank(authToken)) { mockMvcBuilder.defaultRequest( get("").header(AUTHORIZATION_HEADER, AUTHORIZATION_TYPE + authToken)); } + mockMvcBuilder.defaultRequest(defaultRequestParameters); return mockMvcBuilder .build(); diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index f8a4930e61..7bf974a844 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -32,8 +32,13 @@ dspace.baseUrl = http://localhost:8080 # the context path to the UI you are using. # # Alternatively, you can use a url redirect or deploy the web application under the servlet container root. +# This is the URL that the front-end will be served on dspace.url = ${dspace.baseUrl} +# 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. +dspace.restUrl = ${dspace.baseUrl}/rest + # Optional: DSpace URL for mobile access # This #dspace.mobileUrl = http://mobile.example.com @@ -882,8 +887,8 @@ webui.item.thumbnail.show = true #webui.browse.thumbnail.linkbehaviour = item # maximum width and height of generated thumbnails -thumbnail.maxwidth = 80 -thumbnail.maxheight = 80 +thumbnail.maxwidth = 300 +thumbnail.maxheight = 300 # Blur before scaling. A little blur before scaling does wonders for keeping # moire in check. diff --git a/dspace/config/hibernate.cfg.xml b/dspace/config/hibernate.cfg.xml index fe322c6a48..f2a510cf9f 100644 --- a/dspace/config/hibernate.cfg.xml +++ b/dspace/config/hibernate.cfg.xml @@ -44,6 +44,10 @@ + + + + diff --git a/dspace/config/item-submission.xml b/dspace/config/item-submission.xml index 5756e9c4e8..f7432cda58 100644 --- a/dspace/config/item-submission.xml +++ b/dspace/config/item-submission.xml @@ -18,6 +18,12 @@ + + + + + + @@ -57,6 +63,37 @@ org.dspace.app.rest.submit.step.DescribeStep submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + + + submit.progressbar.describe.stepone + org.dspace.app.rest.submit.step.DescribeStep + submission-form + submit.progressbar.describe.steptwo org.dspace.app.rest.submit.step.DescribeStep @@ -150,6 +187,26 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/dspace/config/launcher.xml b/dspace/config/launcher.xml index 776e252314..fb8f893ca3 100644 --- a/dspace/config/launcher.xml +++ b/dspace/config/launcher.xml @@ -366,4 +366,19 @@ org.dspace.app.util.Version + + initialize-entities + Initialize the entities with a provided xml + + org.dspace.app.util.InitializeEntities + + + + + additional-relationship-demo + Creates additional relationships for the demo + + org.dspace.app.util.AdditionalRelationshipScript + + diff --git a/dspace/config/modules/bulkedit.cfg b/dspace/config/modules/bulkedit.cfg index 92a258fa1c..a5be0b06cd 100644 --- a/dspace/config/modules/bulkedit.cfg +++ b/dspace/config/modules/bulkedit.cfg @@ -9,7 +9,7 @@ # bulkedit.valueseparator = || # The delimiter used to separate fields (defaults to a comma for CSV) -# bulkedit.fieldseparator = , +bulkedit.fieldseparator = ; # The delimiter used to serarate authority data (defaults to a double colon ::) # bulkedit.authorityseparator = :: diff --git a/dspace/config/registries/journal-types.xml b/dspace/config/registries/journal-types.xml new file mode 100644 index 0000000000..57a40a3a72 --- /dev/null +++ b/dspace/config/registries/journal-types.xml @@ -0,0 +1,55 @@ + + + + DSpace journal Types + + + + journal + http://dspace.org/journal + + + + + journal + contributor + editor + + + + + + journal + publisher + + + + + + journal + identifier + issn + + + + journal + identifier + name + + + + + journal + identifier + description + + + + + journal + title + + + + + diff --git a/dspace/config/registries/journalissue-types.xml b/dspace/config/registries/journalissue-types.xml new file mode 100644 index 0000000000..fd53102128 --- /dev/null +++ b/dspace/config/registries/journalissue-types.xml @@ -0,0 +1,46 @@ + + + + DSpace journalissue Types + + + + journalissue + http://dspace.org/journalissue + + + + journalissue + issuedate + + + + + + + journalissue + identifier + number + + + + + journalissue + identifier + name + + + + + journalissue + identifier + description + + + + journalissue + identifier + keyword + + + diff --git a/dspace/config/registries/journalvolume-types.xml b/dspace/config/registries/journalvolume-types.xml new file mode 100644 index 0000000000..a3a02e554e --- /dev/null +++ b/dspace/config/registries/journalvolume-types.xml @@ -0,0 +1,41 @@ + + + + DSpace journalvolume Types + + + + journalvolume + http://dspace.org/journalvolume + + + + journalvolume + issuedate + + + + + + + journalvolume + identifier + volume + + + + + journalvolume + identifier + name + + + + + journalvolume + identifier + description + + + + diff --git a/dspace/config/registries/orgunit-types.xml b/dspace/config/registries/orgunit-types.xml new file mode 100644 index 0000000000..14c2696e79 --- /dev/null +++ b/dspace/config/registries/orgunit-types.xml @@ -0,0 +1,55 @@ + + + + DSpace OrgUnit Types + + + + orgunit + http://dspace.org/orgunit + + + + + orgunit + identifier + name + + + + + orgunit + identifier + id + + + + + orgunit + identifier + dateestablished + + + + + orgunit + identifier + city + + + + + orgunit + identifier + country + + + + + orgunit + identifier + description + + + + diff --git a/dspace/config/registries/person-types.xml b/dspace/config/registries/person-types.xml new file mode 100644 index 0000000000..49e6880deb --- /dev/null +++ b/dspace/config/registries/person-types.xml @@ -0,0 +1,61 @@ + + + + DSpace Person Types + + + + person + http://dspace.org/person + + + + + person + identifier + lastname + + + + + person + identifier + firstname + + + + + person + identifier + email + + + + + person + identifier + orcid + + + + + person + identifier + birthdate + + + + + person + identifier + staffid + + + + + person + identifier + jobtitle + + + diff --git a/dspace/config/registries/project-types.xml b/dspace/config/registries/project-types.xml new file mode 100644 index 0000000000..8ed1b84cf2 --- /dev/null +++ b/dspace/config/registries/project-types.xml @@ -0,0 +1,61 @@ + + + + DSpace Project Types + + + + project + http://dspace.org/project + + + + + project + identifier + name + + + + + project + identifier + id + + + + + project + identifier + status + + + + + project + identifier + startdate + + + + + project + identifier + expectedcompletion + + + + + project + identifier + keyword + + + + + project + identifier + description + + + diff --git a/dspace/config/registries/relationship-formats.xml b/dspace/config/registries/relationship-formats.xml new file mode 100644 index 0000000000..00dd43d8a9 --- /dev/null +++ b/dspace/config/registries/relationship-formats.xml @@ -0,0 +1,19 @@ + + + + DSpace Relationship + + + + relationship + http://dspace.org/relationship + + + + + relationship + type + Metadata field used for the type of entity, stored in the item + + + diff --git a/dspace/config/spring/api/core-dao-services.xml b/dspace/config/spring/api/core-dao-services.xml index cc9244015e..bed3009f07 100644 --- a/dspace/config/spring/api/core-dao-services.xml +++ b/dspace/config/spring/api/core-dao-services.xml @@ -28,6 +28,9 @@ + + + diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index f25cb5ea20..02c363749e 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -1,7 +1,8 @@ - + @@ -49,6 +50,10 @@ + + + + @@ -111,5 +116,96 @@ --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + orgunit.identifier.name + person.identifier.lastname + person.identifier.firstname + + + + + + + orgunit.identifier.name + + + + + + + person.identifier.lastname + person.identifier.firstname + + + + + + + orgunit.identifier.name + + + + + + + orgunit.identifier.name + + + + + + + journalvolume.identifier.volume + + + + + + + + journal.identifier.issn + + + journal.identifier.name + + + + + + + + + + journalissue.identifier.number + + diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index ba57e659ea..170e1af45a 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -103,6 +103,7 @@ + @@ -117,6 +118,7 @@ + @@ -157,25 +159,36 @@ - - - - - - - + + + + + + + + + + @@ -216,6 +229,7 @@ + @@ -230,6 +244,7 @@ + @@ -260,25 +275,36 @@ - - - - - - - + + + + + + + + + + @@ -409,6 +435,18 @@ + + + + + relationship.type + + + + + + + diff --git a/dspace/config/submission-forms.xml b/dspace/config/submission-forms.xml index 10e9578c88..2d0872970c 100644 --- a/dspace/config/submission-forms.xml +++ b/dspace/config/submission-forms.xml @@ -229,6 +229,321 @@ it, please enter the types and the actual numbers or codes. +
+ + + person + identifier + lastname + + textarea + Enter the last name of the person + + + + person + identifier + firstname + + textarea + Enter the first name of the person + + + + person + identifier + email + + textarea + Enter the email of the person + + + + person + identifier + orcid + + textarea + Enter the orcid of the person + + + + person + identifier + birthdate + + date + Enter the birth date of the person + + + + person + identifier + staffid + + textarea + Enter the staff id of the person + + + + person + identifier + jobtitle + + textarea + Enter the job title of the person + +
+ + + + +
+ + project + identifier + name + + textarea + Enter the name of the project + + + + project + identifier + id + + textarea + Enter the id of the project + + + project + identifier + status + + textarea + Enter the status of the project + + + project + identifier + startdate + + date + Enter the start date of the project + + + project + identifier + expectedcompletion + + date + Enter the expected completion date of the project + + + project + identifier + keyword + + textarea + Enter the keywords of the project + + + project + identifier + description + + textarea + Enter the description of the project + +
+ +
+ + orgunit + identifier + name + + textarea + Enter the name of the orgunit + + + orgunit + identifier + id + + textarea + Enter the id of the orgunit + + + orgunit + identifier + dateestablished + + date + Enter the established date of the orgunit + + + orgunit + identifier + city + + textarea + Enter the city of the orgunit + + + orgunit + identifier + country + + textarea + Enter the country of the orgunit + + + orgunit + identifier + description + + textarea + Enter the description of the orgunit + +
+ +
+ + + journal + identifier + name + + textarea + Enter the name of the journal + + + + journal + contributor + editor + + textarea + Enter the editor of the journal + + + + journal + identifier + issn + + textarea + Enter the issn of the journal + + + + journal + identifier + description + + textarea + Enter the description of the journal + + + + journal + publisher + + textarea + Enter the publisher of the journal + + +
+ +
+ + + journalvolume + identifier + name + + textarea + Enter the name of the journal volume + + + + journalvolume + identifier + volume + + textarea + Enter the volume of the journal volume + + + + journalvolume + issuedate + + date + Enter the issue date of the journal volume + + + + journalvolume + identifier + description + + textarea + Enter the description of the journal volume + + +
+ +
+ + + journalissue + identifier + name + + textarea + Enter the name of the journal issue + + + + journalissue + identifier + number + + textarea + Enter the number of the journal issue + + + + journalissue + issuedate + + date + Enter the issue date of the journal issue + + + + journalissue + identifier + description + + textarea + Enter the description of the journal issue + + + + journalissue + identifier + keyword + + textarea + Enter the keywords of the journal issue + + +
+ diff --git a/dspace/solr/search/conf/schema.xml b/dspace/solr/search/conf/schema.xml index b08510798f..70cdbf7c88 100644 --- a/dspace/solr/search/conf/schema.xml +++ b/dspace/solr/search/conf/schema.xml @@ -559,6 +559,9 @@ + + + From b0216cb91864b941421e0b62c34f576823513000 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 24 Oct 2018 14:12:23 +0200 Subject: [PATCH 002/188] Test fixes and checkstyle fixes --- .../content/dao/impl/EntityTypeDAOImpl.java | 21 +- .../content/dao/impl/RelationshipDAOImpl.java | 49 +- .../dao/impl/RelationshipTypeDAOImpl.java | 31 +- .../dspace/app/bulkedit/DSpaceCSVTest.java | 26 +- .../converter/DiscoverResultConverter.java | 1 + .../app/rest/DiscoveryRestControllerIT.java | 3363 +++++++++-------- .../app/rest/EntityTypeRestRepositoryIT.java | 44 +- .../rest/RelationshipRestRepositoryIT.java | 82 +- .../RelationshipTypeRestRepositoryIT.java | 116 +- .../rest/RootRestResourceControllerIT.java | 38 +- .../SubmissionDefinitionsControllerIT.java | 6 +- .../rest/SubmissionSectionsControllerIT.java | 2 +- .../rest/SubmissionUploadsControllerIT.java | 2 +- .../app/rest/builder/RelationshipBuilder.java | 18 +- .../app/rest/matcher/BrowseIndexMatcher.java | 20 +- .../app/rest/matcher/EntityTypeMatcher.java | 5 +- .../app/rest/matcher/FacetEntryMatcher.java | 9 +- .../app/rest/matcher/RelationshipMatcher.java | 30 +- .../rest/matcher/RelationshipTypeMatcher.java | 60 +- .../app/rest/matcher/SearchFilterMatcher.java | 9 + .../matcher/SubmissionDefinitionsMatcher.java | 4 +- .../AbstractControllerIntegrationTest.java | 30 +- dspace/config/spring/api/discovery.xml | 23 +- dspace/config/submission-forms.xml | 89 +- 24 files changed, 2166 insertions(+), 1912 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java index 514b337bb9..f2f6364987 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java @@ -8,22 +8,25 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.EntityType; +import org.dspace.content.EntityType_; import org.dspace.content.dao.EntityTypeDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; public class EntityTypeDAOImpl extends AbstractHibernateDAO implements EntityTypeDAO { - public EntityType findByEntityType(Context context,String entityType) throws SQLException { - Criteria criteria = createCriteria(context,EntityType.class); - criteria.add(Restrictions.and( - Restrictions.eq("label", entityType).ignoreCase() - )); - - return singleResult(criteria); + public EntityType findByEntityType(Context context, String entityType) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EntityType.class); + Root entityTypeRoot = criteriaQuery.from(EntityType.class); + criteriaQuery.select(entityTypeRoot); + criteriaQuery.where(criteriaBuilder.equal(criteriaBuilder.upper(entityTypeRoot.get(EntityType_.label)), + entityType.toUpperCase())); + return uniqueResult(context, criteriaQuery, true, EntityType.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java index e41a768c17..5b3e33f5b5 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java @@ -9,34 +9,37 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Item; import org.dspace.content.Relationship; +import org.dspace.content.Relationship_; import org.dspace.content.dao.RelationshipDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; public class RelationshipDAOImpl extends AbstractHibernateDAO implements RelationshipDAO { - public List findByItem(Context context,Item item) throws SQLException { - Criteria criteria = createCriteria(context,Relationship.class); - criteria.add(Restrictions.or( - Restrictions.eq("leftItem", item), - Restrictions.eq("rightItem", item) - )); - - return list(criteria); + public List findByItem(Context context, Item item) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); + Root relationshipRoot = criteriaQuery.from(Relationship.class); + criteriaQuery.select(relationshipRoot); + criteriaQuery + .where(criteriaBuilder.or(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item), + criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item))); + return list(context, criteriaQuery, true, Relationship.class, -1, -1); } public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Relationship.class); - criteria.add(Restrictions.and( - Restrictions.eq("leftItem", item) - )); - - List list = list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); + Root relationshipRoot = criteriaQuery.from(Relationship.class); + criteriaQuery.select(relationshipRoot); + criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item)); + List list = list(context, criteriaQuery, true, Relationship.class, -1, -1); list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); if (!list.isEmpty()) { return list.get(0).getLeftPlace(); @@ -46,13 +49,13 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl } public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Relationship.class); - criteria.add(Restrictions.and( - Restrictions.eq("rightItem", item) - )); - - List list = list(criteria); - list.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); + Root relationshipRoot = criteriaQuery.from(Relationship.class); + criteriaQuery.select(relationshipRoot); + criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)); + List list = list(context, criteriaQuery, true, Relationship.class, -1, -1); + list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); if (!list.isEmpty()) { return list.get(0).getLeftPlace(); } else { diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java index 68c17d7807..acf11bf743 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java @@ -8,28 +8,33 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.EntityType; import org.dspace.content.RelationshipType; +import org.dspace.content.RelationshipType_; import org.dspace.content.dao.RelationshipTypeDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; public class RelationshipTypeDAOImpl extends AbstractHibernateDAO implements RelationshipTypeDAO { - public RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, - String leftLabel,String rightLabel) - throws SQLException { - Criteria criteria = createCriteria(context,RelationshipType.class); - criteria.add(Restrictions.and( - Restrictions.eq("leftType", leftType), - Restrictions.eq("rightType", rightType), - Restrictions.eq("leftLabel", leftLabel), - Restrictions.eq("rightLabel", rightLabel) - )); - return singleResult(criteria); + public RelationshipType findbyTypesAndLabels(Context context, EntityType leftType, EntityType rightType, + String leftLabel, String rightLabel) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class); + Root relationshipTypeRoot = criteriaQuery.from(RelationshipType.class); + criteriaQuery.select(relationshipTypeRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftType), leftType), + criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.rightType), rightType), + criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftLabel), leftLabel), + criteriaBuilder + .equal(relationshipTypeRoot.get(RelationshipType_.rightLabel), rightLabel))); + return uniqueResult(context, criteriaQuery, false, RelationshipType.class, -1, -1); } } diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java index c4261f0b02..8f23449201 100644 --- a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java +++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java @@ -41,19 +41,19 @@ public class DSpaceCSVTest extends AbstractUnitTest { public void testDSpaceCSV() { try { // Test the CSV parsing - String[] csv = {"id,collection,\"dc.title[en]\",dc.contributor.author,dc.description.abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Easy line,\"Lewis, Stuart\",A nice short abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Two authors,\"Lewis, Stuart||Bloggs, Joe\",Two people wrote " + + String[] csv = {"id;collection;\"dc.title[en]\";dc.contributor.author;dc.description.abstract", + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;Easy line;\"Lewis, Stuart\";A nice short abstract", + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;Two authors;\"Lewis, Stuart||Bloggs, Joe\";Two people wrote " + "this item", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,Three authors,\"Lewis, Stuart||Bloggs, Joe||Loaf, Meat\"," + + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;Three authors;\"Lewis, Stuart||Bloggs, Joe||Loaf, Meat\";" + "Three people wrote this item", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Two line\n\ntitle\",\"Lewis, Stuart\",abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"Empty lines\n\nshould work too (DS-3245).\",\"Lewis, " + - "Stuart\",abstract", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Embedded quotes\"\" here\",\"Lewis, Stuart\",\"Abstract" + + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;\"Two line\n\ntitle\";\"Lewis, Stuart\";abstract", + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;\"Empty lines\n\nshould work too (DS-3245).\";\"Lewis, " + + "Stuart\";abstract", + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;\"\"\"Embedded quotes\"\" here\";\"Lewis, Stuart\";\"Abstract" + " with\ntwo\nnew lines\"", - "+,56599ad5-c7d2-4ac3-8354-a1f277d5a31f,\"\"\"Unbalanced embedded\"\" quotes\"\" here\",\"Lewis, " + - "Stuart\",\"Abstract with\ntwo\nnew lines\"",}; + "+;56599ad5-c7d2-4ac3-8354-a1f277d5a31f;\"\"\"Unbalanced embedded\"\" quotes\"\" here\";\"Lewis, " + + "Stuart\";\"Abstract with\ntwo\nnew lines\"",}; // Write the string to a file String filename = "test.csv"; BufferedWriter out = new BufferedWriter( @@ -81,7 +81,7 @@ public class DSpaceCSVTest extends AbstractUnitTest { line = null; // Test the CSV parsing with a bad heading element value - csv[0] = "id,collection,\"dc.title[en]\",dc.contributor.foobar[en-US],dc.description.abstract"; + csv[0] = "id;collection;\"dc.title[en]\";dc.contributor.foobar[en-US];dc.description.abstract"; // Write the string to a file filename = "test.csv"; out = new BufferedWriter( @@ -109,7 +109,7 @@ public class DSpaceCSVTest extends AbstractUnitTest { // Test the CSV parsing with a bad heading schema value - csv[0] = "id,collection,\"dcdc.title[en]\",dc.contributor[en-US],dc.description.abstract"; + csv[0] = "id;collection;\"dcdc.title[en]\";dc.contributor[en-US];dc.description.abstract"; // Write the string to a file filename = "test.csv"; out = new BufferedWriter( @@ -146,4 +146,4 @@ public class DSpaceCSVTest extends AbstractUnitTest { fail("IO Error while creating test CSV file"); } } -} +} \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java index 9facb9500b..e6a0fb47f8 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java @@ -22,6 +22,7 @@ import org.dspace.app.rest.model.SearchResultEntryRest; import org.dspace.app.rest.model.SearchResultsRest; import org.dspace.app.rest.parameter.SearchFilter; import org.dspace.content.DSpaceObject; +import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.dspace.discovery.DiscoverQuery; import org.dspace.discovery.DiscoverResult; diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java index 56d25ecf8c..996e19b75c 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -52,16 +52,16 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //When we call this endpoint getClient().perform(get("/api/discover")) - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a link to the facets endpoint - .andExpect(jsonPath("$._links.facets.href", containsString("api/discover/facets"))) - //There needs to be a link to the search endpoint - .andExpect(jsonPath("$._links.search.href", containsString("api/discover/search"))) - //There needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover"))); + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a link to the facets endpoint + .andExpect(jsonPath("$._links.facets.href", containsString("api/discover/facets"))) + //There needs to be a link to the search endpoint + .andExpect(jsonPath("$._links.search.href", containsString("api/discover/search"))) + //There needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover"))); } @Test @@ -70,19 +70,20 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //When we call this facets endpoint getClient().perform(get("/api/discover/facets")) - //We expect a 200 OK status - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a self link to this endpoint - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets"))) - //We have 4 facets in the default configuration, they need to all be present in the embedded section - .andExpect(jsonPath("$._embedded.facets", containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false))) - ); + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.facets", containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false))) + ); } @Test @@ -93,69 +94,69 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects and authors Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 getClient().perform(get("/api/discover/facets/author") - .param("size", "2")) + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type needs to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet needs to be author, because that's what we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's how the author facet is configured by default - .andExpect(jsonPath("$.facetType", is("text"))) - //Because we've constructed such a structure so that we have more than 2 (size) authors, there - // needs to be a next link - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //Because there are more authors than is represented (because of the size param), hasMore has to - // be true - //The page object needs to be present and just like specified in the matcher - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //These authors need to be in the response because it's sorted on how many times the author comes - // up in different items - //These authors are the most used ones. Only two show up because of the size. - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //Because we've constructed such a structure so that we have more than 2 (size) authors, there + // needs to be a next link + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are the most used ones. Only two show up because of the size. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) ; } @@ -167,64 +168,64 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects and authors Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 getClient().perform(get("/api/discover/facets/author?prefix=smith") - .param("size", "10")) + .param("size", "10")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type needs to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet needs to be author, because that's what we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's how the author facet is configured by default - .andExpect(jsonPath("$.facetType", is("text"))) - //We only request value starting with "smith", so we expect to only receive one page - .andExpect(jsonPath("$._links.next").doesNotExist()) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author?prefix=smith"))) - //Because there are more authors than is represented (because of the size param), hasMore has to - // be true - //The page object needs to be present and just like specified in the matcher - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 10)))) - //These authors need to be in the response because it's sorted on how many times the author comes - // up in different items - //These authors are order according to count. Only two show up because of the prefix. - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //We only request value starting with "smith", so we expect to only receive one page + .andExpect(jsonPath("$._links.next").doesNotExist()) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author?prefix=smith"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 10)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are order according to count. Only two show up because of the prefix. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -236,64 +237,64 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facets and doesn't enter a size getClient().perform(get("/api/discover/facets/author")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author, because that's the facet that we called upon - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //There always needs to be a self link present - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The page object needs to present and exactly like how it is specified here. 20 is entered as the - // size because that's the default in the configuration if no size parameter has been given - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //The authors need to be embedded in the values, all 4 of them have to be present as the size - // allows it - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author, because that's the facet that we called upon + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link present + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object needs to present and exactly like how it is specified here. 20 is entered as the + // size because that's the default in the configuration if no size parameter has been given + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The authors need to be embedded in the values, all 4 of them have to be present as the size + // allows it + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -306,69 +307,69 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John").withAuthor("Smith, Maria") - .withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John").withAuthor("Smith, Maria") + .withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Doe, John") - .withAuthor("Smith, Donald") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Doe, John") + .withAuthor("Smith, Donald") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facet //The user enters a size of two and wants to see page 1, this is the second page. getClient().perform(get("/api/discover/facets/author") - .param("size", "2") - .param("page", "1")) + .param("size", "2") + .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet has to be author as that's the one we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as this is the default configuration - .andExpect(jsonPath("$.facetType", is("text"))) - //There needs to be a next link because there are more authors than the current size is allowed to - // show. There are more pages after this one - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The page object has to be like this because that's what we've asked in the parameters - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(1, 2)))) - //These authors have to be present because of the current configuration - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet has to be author as that's the one we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as this is the default configuration + .andExpect(jsonPath("$.facetType", is("text"))) + //There needs to be a next link because there are more authors than the current size is allowed to + // show. There are more pages after this one + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object has to be like this because that's what we've asked in the parameters + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(1, 2)))) + //These authors have to be present because of the current configuration + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -381,76 +382,76 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facet //The user enters a small query, namely the title has to contain 'test' getClient().perform(get("/api/discover/facets/author") - .param("f.title", "test,contains")) + .param("f.title", "test,contains")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author as that's the facet that we've asked - .andExpect(jsonPath("$.name", is("author"))) - //The facetType needs to be 'text' as that's the default configuration for the given facet - .andExpect(jsonPath("$.facetType", is("text"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The self link needs to contain the query that was specified in the parameters, this is how it - // looks like - .andExpect(jsonPath("$._links.self.href", containsString("f.title=test,contains"))) - //The applied filters have to be specified like this, applied filters are the parameters given - // below starting with f. - .andExpect(jsonPath("$.appliedFilters", contains( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //This is how the page object must look like because it's the default - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //These authors need to be present in the result because these have made items that contain 'test' - // in the title - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Donald"), - FacetValueMatcher.entryAuthor("Testing, Works") - ))) - //These authors cannot be present because they've not produced an item with 'test' in the title - .andExpect(jsonPath("$._embedded.values", not(containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, Jane") - )))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've asked + .andExpect(jsonPath("$.name", is("author"))) + //The facetType needs to be 'text' as that's the default configuration for the given facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The self link needs to contain the query that was specified in the parameters, this is how it + // looks like + .andExpect(jsonPath("$._links.self.href", containsString("f.title=test,contains"))) + //The applied filters have to be specified like this, applied filters are the parameters given + // below starting with f. + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //This is how the page object must look like because it's the default + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //These authors need to be present in the result because these have made items that contain 'test' + // in the title + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Donald"), + FacetValueMatcher.entryAuthor("Testing, Works") + ))) + //These authors cannot be present because they've not produced an item with 'test' in the title + .andExpect(jsonPath("$._embedded.values", not(containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, Jane") + )))) ; } @@ -462,62 +463,62 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2000-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2000-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet getClient().perform(get("/api/discover/facets/dateIssued")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be 'dateIssued' as that's the facet that we've called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //The facetType has to be 'date' because that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //This is how the page object must look like because it's the default with size 20 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //The date values need to be as specified below - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - //We'll always get atleast two intervals with the items specified above, so we ask to match - // twice atleast - FacetValueMatcher.entryDateIssued(), - FacetValueMatcher.entryDateIssued() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'dateIssued' as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType has to be 'date' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //This is how the page object must look like because it's the default with size 20 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The date values need to be as specified below + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + //We'll always get atleast two intervals with the items specified above, so we ask to match + // twice atleast + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) ; } @@ -530,90 +531,90 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the author results by the facet //With a certain scope getClient().perform(get("/api/discover/facets/author") - .param("scope", "testScope")) + .param("scope", "testScope")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author as that's the facet that we've called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //The scope has to be the same as the one that we've given in the parameters - .andExpect(jsonPath("$.scope", is("testScope"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //These are all the authors for the items that were created and thus they have to be present in - // the embedded values section - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))); + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be the same as the one that we've given in the parameters + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are all the authors for the items that were created and thus they have to be present in + // the embedded values section + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))); //** WHEN ** //An anonymous user browses this endpoint to find the author results by the facet //With a certain scope //And a size of 2 getClient().perform(get("/api/discover/facets/author") - .param("scope", "testScope") - .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be 'author' as that's the facet that we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //The scope has to be same as the param that we've entered - .andExpect(jsonPath("$.scope", is("testScope"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //These are the values that need to be present as it's ordered by count and these authors are the - // most common ones in the items that we've created - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria") - ))) + .param("scope", "testScope") + .param("size", "2")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'author' as that's the facet that we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be same as the param that we've entered + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are the values that need to be present as it's ordered by count and these authors are the + // most common ones in the items that we've created + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) ; } @@ -625,105 +626,105 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. 7 public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1940-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1940-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem4 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1950-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem5 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1960-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1960-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem6 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1970-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem7 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1980-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1980-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet //And a size of 2 getClient().perform(get("/api/discover/facets/dateIssued") - .param("size", "2")) + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name needs to be dateIssued as that's the facet that we've called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //the facetType needs to be 'date' as that's the default facetType for this facet in the - // configuration - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //Seeing as we've entered a size of two and there are more dates than just two, we'll need a next - // link to go to the next page to see the rest of the dates - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/dateIssued?page"))) - //The page object needs to look like this because we've entered a size of 2 and we didn't specify - // a starting page so it defaults to 0 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //There needs to be two date results in the embedded values section because that's what we've - // specified - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryDateIssued(), - FacetValueMatcher.entryDateIssued() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name needs to be dateIssued as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //the facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //Seeing as we've entered a size of two and there are more dates than just two, we'll need a next + // link to go to the next page to see the rest of the dates + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/dateIssued?page"))) + //The page object needs to look like this because we've entered a size of 2 and we didn't specify + // a starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be two date results in the embedded values section because that's what we've + // specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) ; } @@ -737,71 +738,71 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet //With a query stating that the title needs to contain 'test' //And a size of 2 getClient().perform(get("/api/discover/facets/dateIssued") - .param("f.title", "test,contains") - .param("size", "2")) + .param("f.title", "test,contains") + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be dateIssued because that's the facet that we called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //The facetType needs to be 'date' as that's the default facetType for this facet in the - // configuration - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //There needs to be an appliedFilters section that looks like this because we've specified a query - // in the parameters - .andExpect(jsonPath("$.appliedFilters", containsInAnyOrder( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //The page object needs to look like this because we entered a size of 2 and we didn't specify a - // starting page so it defaults to 0 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //There needs to be only two date intervals with a count of 1 because of the query we specified - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryDateIssuedWithCountOne(), - FacetValueMatcher.entryDateIssuedWithCountOne() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be dateIssued because that's the facet that we called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //There needs to be an appliedFilters section that looks like this because we've specified a query + // in the parameters + .andExpect(jsonPath("$.appliedFilters", containsInAnyOrder( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //The page object needs to look like this because we entered a size of 2 and we didn't specify a + // starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be only two date intervals with a count of 1 because of the query we specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithCountOne(), + FacetValueMatcher.entryDateIssuedWithCountOne() + ))) ; } @@ -829,7 +830,8 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest SearchFilterMatcher.dateIssuedFilter(), SearchFilterMatcher.hasContentInOriginalBundleFilter(), SearchFilterMatcher.hasFileNameInOriginalBundleFilter(), - SearchFilterMatcher.hasFileDescriptionInOriginalBundleFilter() + SearchFilterMatcher.hasFileDescriptionInOriginalBundleFilter(), + SearchFilterMatcher.entityTypeFilter() ))) //These sortOptions need to be present as it's the default in the configuration .andExpect(jsonPath("$.sortOptions", containsInAnyOrder( @@ -849,74 +851,75 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a page object that shows the total pages and total elements as well as the - // size and the current page (number) - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //These search results have to be shown in the embedded.objects section as these are the items - // given in the structure defined above. - //Seeing as everything fits onto one page, they have to all be present - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("community", "communities"), - SearchResultMatcher.match("community", "communities"), - //This has to be like this because collections don't have anything else - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a page object that shows the total pages and total elements as well as the + // size and the current page (number) + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //These search results have to be shown in the embedded.objects section as these are the items + // given in the structure defined above. + //Seeing as everything fits onto one page, they have to all be present + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //This has to be like this because collections don't have anything else + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -928,79 +931,80 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works").withAuthor("a1, a1") - .withAuthor("b, b").withAuthor("c, c").withAuthor("d, d").withAuthor("e, e") - .withAuthor("f, f").withAuthor("g, g") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works").withAuthor("a1, a1") + .withAuthor("b, b").withAuthor("c, c").withAuthor("d, d").withAuthor("e, e") + .withAuthor("f, f").withAuthor("g, g") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because we've only made 7 elements, the default size is 20 - // and they all fit onto one page (20 > 7) so totalPages has to be 1. Number is 0 because - //page 0 is the default page we view if not specified otherwise - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //All elements have to be present in the embedded.objects section, these are the ones we made in - // the structure defined above - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("community", "communities"), - SearchResultMatcher.match("community", "communities"), - //Match without any parameters because collections don't have anything special to check in the - // json - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - //We do however exceed the limit for the authors, so this property has to be true for the author - // facet - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(true), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 elements, the default size is 20 + // and they all fit onto one page (20 > 7) so totalPages has to be 1. Number is 0 because + //page 0 is the default page we view if not specified otherwise + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All elements have to be present in the embedded.objects section, these are the ones we made in + // the structure defined above + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Match without any parameters because collections don't have anything special to check in the + // json + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the authors, so this property has to be true for the author + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1014,80 +1018,81 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry").withSubject("a") - .withSubject("b").withSubject("c") - .withSubject("d").withSubject("e") - .withSubject("f").withSubject("g") - .withSubject("h").withSubject("i") - .withSubject("j").withSubject("k") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry").withSubject("a") + .withSubject("b").withSubject("c") + .withSubject("d").withSubject("e") + .withSubject("f").withSubject("g") + .withSubject("h").withSubject("i") + .withSubject("j").withSubject("k") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because we've only made 7 items, they all fit onto 1 page - // because the default size is 20 and the default starting page is 0. - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //All the elements created in the structure above have to be present in the embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("community", "communities"), - SearchResultMatcher.match("community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - //We do however exceed the limit for the subject, so this property has to be true for the subject - // facet - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 items, they all fit onto 1 page + // because the default size is 20 and the default starting page is 0. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the subject, so this property has to be true for the subject + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1099,72 +1104,73 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a query that says that the title has to contain 'test' getClient().perform(get("/api/discover/search/objects") - .param("f.title", "test,contains")) + .param("f.title", "test,contains")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because of the query we specified, only two elements match - // the query. - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) - ))) - //Only the two item elements match the query, therefore those are the only ones that can be in the - // embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //We need to display the appliedFilters object that contains the query that we've ran - .andExpect(jsonPath("$.appliedFilters", contains( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because of the query we specified, only two elements match + // the query. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) + ))) + //Only the two item elements match the query, therefore those are the only ones that can be in the + // embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //We need to display the appliedFilters object that contains the query that we've ran + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1177,75 +1183,76 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a scope 'test' getClient().perform(get("/api/discover/search/objects") - .param("scope", "test")) + .param("scope", "test")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page element has to look like this because it contains all the elements we've just created - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //The scope property has to be set to the value we entered in the parameters - .andExpect(jsonPath("$.scope", is("test"))) - //All the elements created in the structure above have to be present in the embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("community", "communities"), - SearchResultMatcher.match("community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element has to look like this because it contains all the elements we've just created + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //The scope property has to be set to the value we entered in the parameters + .andExpect(jsonPath("$.scope", is("test"))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1257,71 +1264,72 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a dsoType 'item' getClient().perform(get("/api/discover/search/objects") - .param("dsoType", "item")) + .param("dsoType", "item")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page element needs to look like this and only have three totalElements because we only want - // the items (dsoType) and we only created three items - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) - ))) - //Only the three items can be present in the embedded.objects section as that's what we specified - // in the dsoType parameter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element needs to look like this and only have three totalElements because we only want + // the items (dsoType) and we only created three items + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1332,85 +1340,86 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Testing") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Testing") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a dsoType 'item' //And a sort on the dc.title ascending getClient().perform(get("/api/discover/search/objects") - .param("dsoType", "item") - .param("sort", "dc.title,ASC")) + .param("dsoType", "item") + .param("sort", "dc.title,ASC")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this and only contain three total elements because we only want - // to get the items back - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) - ))) - //Only the three items can be present in the embedded.objects section as that's what we specified - // in the dsoType parameter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items"), - SearchResultMatcher.match("item", "items") - ))) - //Here we want to match on the item name in a certain specified order because we want to check the - // sort properly - //We check whether the items are sorted properly as we expected - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Public"), - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Testing") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //We want to get the sort that's been used as well in the response - .andExpect(jsonPath("$.sort", is( - SortOptionMatcher.sortByAndOrder("dc.title", "ASC") - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this and only contain three total elements because we only want + // to get the items back + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items"), + SearchResultMatcher.match("item", "items") + ))) + //Here we want to match on the item name in a certain specified order because we want to check the + // sort properly + //We check whether the items are sorted properly as we expected + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public"), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Testing") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //We want to get the sort that's been used as well in the response + .andExpect(jsonPath("$.sort", is( + SortOptionMatcher.sortByAndOrder("dc.title", "ASC") + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1425,114 +1434,114 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. 9 public items that are readable by Anonymous with different subjects Item publicItem6 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2017-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2017-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem7 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem8 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem9 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1970-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem10 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1950-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem11 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1930-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1930-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem12 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1910-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1910-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem13 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1890-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1890-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem14 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1866-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1866-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find dateIssued facet values getClient().perform(get("/api/discover/facets/dateIssued")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because the default size is 20 and the default starting - // page is 0 - .andExpect(jsonPath("$.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Then we expect these dateIssued values to be present with the labels as specified - .andExpect(jsonPath("$._embedded.values", Matchers.containsInAnyOrder( - FacetValueMatcher.entryDateIssuedWithLabel("2000 - 2017"), - FacetValueMatcher.entryDateIssuedWithLabel("1980 - 1999"), - FacetValueMatcher.entryDateIssuedWithLabel("1960 - 1979"), - FacetValueMatcher.entryDateIssuedWithLabel("1940 - 1959"), - FacetValueMatcher.entryDateIssuedWithLabel("1920 - 1939"), - FacetValueMatcher.entryDateIssuedWithLabel("1880 - 1899"), - FacetValueMatcher.entryDateIssuedWithLabel("1866 - 1879"), - FacetValueMatcher.entryDateIssuedWithLabel("1900 - 1919") + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because the default size is 20 and the default starting + // page is 0 + .andExpect(jsonPath("$.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Then we expect these dateIssued values to be present with the labels as specified + .andExpect(jsonPath("$._embedded.values", Matchers.containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithLabel("2000 - 2017"), + FacetValueMatcher.entryDateIssuedWithLabel("1980 - 1999"), + FacetValueMatcher.entryDateIssuedWithLabel("1960 - 1979"), + FacetValueMatcher.entryDateIssuedWithLabel("1940 - 1959"), + FacetValueMatcher.entryDateIssuedWithLabel("1920 - 1939"), + FacetValueMatcher.entryDateIssuedWithLabel("1880 - 1899"), + FacetValueMatcher.entryDateIssuedWithLabel("1866 - 1879"), + FacetValueMatcher.entryDateIssuedWithLabel("1900 - 1919") - ))) + ))) ; } @@ -1544,76 +1553,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("size", "2") - .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - //Size of 2 because that's what we entered - //Page number 1 because that's the param we entered - //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages - //We made 7 elements -> 7 total elements - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) - ))) - //These are the two elements that'll be shown (because page = 1, so the third and fourth element - // in the list) and they'll be the only ones because the size is 2 - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match(), - SearchResultMatcher.match() - ))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(true), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false), + FacetEntryMatcher.entityTypeFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1627,45 +1637,45 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); String bitstreamContent = "ThisIsSomeDummyText"; //Add a bitstream to an item try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { Bitstream bitstream = BitstreamBuilder. - createBitstream(context, publicItem1, is) - .withName("Bitstream") - .withMimeType("text/plain") - .build(); + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withMimeType("text/plain") + .build(); } //Run the filter media to make the text in the bitstream searchable through the query @@ -1675,32 +1685,33 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'ThisIsSomeDummyText' getClient().perform(get("/api/discover/search/objects") - .param("query", "ThisIsSomeDummyText")) + .param("query", "ThisIsSomeDummyText")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //This is the only item that should be returned with the query given - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1713,40 +1724,40 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); //Make this one public to make sure that it doesn't show up in the search Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .withEmbargoPeriod("12 months") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .withEmbargoPeriod("12 months") + .build(); //Turn on the authorization again context.restoreAuthSystemState(); @@ -1754,38 +1765,39 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system // getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //These are the items that aren't set to private - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match("community", "communities"), - SearchResultMatcher.match("community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //This is a private item, this shouldn't show up in the result - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", - Matchers.not(SearchResultMatcher.matchOnItemName("item", "items", "Test 2")))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //These are the items that aren't set to private + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match("community", "communities"), + SearchResultMatcher.match("community", "communities"), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //This is a private item, this shouldn't show up in the result + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", + Matchers.not(SearchResultMatcher.matchOnItemName("item", "items", "Test 2")))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1800,37 +1812,37 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); //2. one public item that is readable by Anonymous Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); String bitstreamContent = "ThisIsSomeDummyText"; //Make the group that anon doesn't have access to Group internalGroup = GroupBuilder.createGroup(context) - .withName("Internal Group") - .build(); + .withName("Internal Group") + .build(); //Add this bitstream with the internal group as the reader group try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { Bitstream bitstream = BitstreamBuilder. - createBitstream(context, publicItem1, is) - .withName("Bitstream") - .withDescription("Test Private Bitstream") - .withMimeType("text/plain") - .withReaderGroup(internalGroup) - .build(); + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Test Private Bitstream") + .withMimeType("text/plain") + .withReaderGroup(internalGroup) + .build(); } @@ -1844,32 +1856,32 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("query", "ThisIsSomeDummyText")) + .param("query", "ThisIsSomeDummyText")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Make sure that the item with the private bitstream doesn't show up - .andExpect(jsonPath("$._embedded.object", Matchers.not(Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - )))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the item with the private bitstream doesn't show up + .andExpect(jsonPath("$._embedded.object", Matchers.not(Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + )))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1883,69 +1895,70 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the scope given getClient().perform(get("/api/discover/search/objects") - .param("scope", String.valueOf(scope))) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The scope has to be equal to the one given in the parameters - .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items belonging to the scope specified - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The scope has to be equal to the one given in the parameters + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items belonging to the scope specified + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1958,76 +1971,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Two items that are readable by Anonymous with different subjects and one private item Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("scope", String.valueOf(scope))) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //Make sure that the scope is set to the scope given in the param - .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Make sure that the search results contains the item with the correct scope - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2") + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //Make sure that the scope is set to the scope given in the param + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the search results contains the item with the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") // SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //Make sure that the search result doesn't contain the item that's set to private but does have - // the correct scope - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( - Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - )))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //Make sure that the search result doesn't contain the item that's set to private but does have + // the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + )))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2040,34 +2054,34 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .build(); String query = "Public"; @@ -2075,33 +2089,34 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'public' getClient().perform(get("/api/discover/search/objects") - .param("query", query)) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results has to contain the item with the query in the title and the hithighlight has - // to be filled in with a string containing the query - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher - .matchOnItemNameAndHitHighlight("item", "items", - "Public item 2", query, "dc.title") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results has to contain the item with the query in the title and the hithighlight has + // to be filled in with a string containing the query + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2115,35 +2130,35 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Two public items that are readable by Anonymous with different subjects and one private item Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); String query = "Public"; @@ -2151,25 +2166,25 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'Public' getClient().perform(get("/api/discover/search/objects") - .param("query", query)) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results should not contain this - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( - Matchers.contains( - SearchResultMatcher - .matchOnItemNameAndHitHighlight("item", "items", - "Public item 2", query, "dc.title") - )))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results should not contain this + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + )))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2182,66 +2197,68 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "test*,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Test 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2254,65 +2271,67 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-test*,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2325,76 +2344,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("size", "2") - .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - //Size of 2 because that's what we entered - //Page number 1 because that's the param we entered - //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages - //We made 7 elements -> 7 total elements - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) - ))) - //These are the two elements that'll be shown (because page = 1, so the third and fourth element - // in the list) and they'll be the only ones because the size is 2 - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match(), - SearchResultMatcher.match() - ))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2407,60 +2427,61 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/facets")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/facets"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/facets"))) ; } @@ -2473,65 +2494,67 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "Test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2544,66 +2567,68 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-Test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItems( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItems( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2616,66 +2641,68 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-id:test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-id:test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } -} +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java index edf83871d5..04992da16f 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java @@ -18,14 +18,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.io.File; import java.sql.SQLException; +import java.util.Iterator; import java.util.List; import org.dspace.app.rest.matcher.EntityTypeMatcher; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; -import org.dspace.authorize.AuthorizeException; import org.dspace.content.EntityType; +import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.services.ConfigurationService; import org.junit.After; @@ -44,6 +46,9 @@ public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTes @Autowired private ConfigurationService configurationService; + @Autowired + private RelationshipService relationshipService; + @Before public void setup() throws Exception { @@ -54,22 +59,37 @@ public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTes } @After - public void destroy() throws SQLException, AuthorizeException { - + public void destroy() throws Exception { //Clean up the database for the next test context.turnOffAuthorisationSystem(); List relationshipTypeList = relationshipTypeService.findAll(context); List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); - for (RelationshipType relationshipType : relationshipTypeList) { + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); relationshipTypeService.delete(context, relationshipType); } - for (EntityType entityType : entityTypeList) { + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); entityTypeService.delete(context, entityType); } - context.restoreAuthSystemState(); + + super.destroy(); } + @Test public void findAllEntityTypesSizeTest() throws SQLException { assertEquals(7, entityTypeService.findAll(context).size()); @@ -116,6 +136,7 @@ public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTes String type = "JournalIssue"; checkEntityType(type); } + private void checkEntityType(String type) throws SQLException { EntityType entityType = entityTypeService.findByEntityType(context, type); assertNotNull(entityType); @@ -135,13 +156,16 @@ public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTes .andExpect(jsonPath("$._links.self.href", containsString("api/core/entitytypes"))) //We have 4 facets in the default configuration, they need to all be present in the embedded section .andExpect(jsonPath("$._embedded.entitytypes", containsInAnyOrder( - EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Publication")), + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Publication")), EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Person")), EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Project")), EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "OrgUnit")), EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Journal")), - EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalVolume")), - EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalIssue")) + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalVolume")), + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalIssue")) ))); } -} +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 25831f257d..02cd387707 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.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.rest; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -7,7 +14,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.io.File; -import java.sql.SQLException; +import java.util.Iterator; import java.util.List; import org.dspace.app.rest.builder.CollectionBuilder; @@ -17,7 +24,6 @@ import org.dspace.app.rest.builder.RelationshipBuilder; import org.dspace.app.rest.matcher.PageMatcher; import org.dspace.app.rest.matcher.RelationshipMatcher; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; -import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.EntityType; @@ -25,6 +31,7 @@ import org.dspace.content.Item; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.services.ConfigurationService; import org.junit.After; @@ -40,6 +47,9 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT @Autowired private EntityTypeService entityTypeService; + @Autowired + private RelationshipService relationshipService; + @Autowired private ConfigurationService configurationService; @@ -55,21 +65,35 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } @After - public void destroy() throws SQLException, AuthorizeException { - + public void destroy() throws Exception { //Clean up the database for the next test context.turnOffAuthorisationSystem(); List relationshipTypeList = relationshipTypeService.findAll(context); List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); - for (RelationshipType relationshipType : relationshipTypeList) { + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); relationshipTypeService.delete(context, relationshipType); } - for (EntityType entityType : entityTypeList) { + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); entityTypeService.delete(context, entityType); } - context.restoreAuthSystemState(); + + super.destroy(); } @Test @@ -130,32 +154,27 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .build(); - RelationshipType isOrgUnitOfPersonRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, - entityTypeService - .findByEntityType(context, - "Person"), - entityTypeService - .findByEntityType(context, - "OrgUnit"), - "isOrgUnitOfPerson", - "isPersonOfOrgUnit"); + RelationshipType isOrgUnitOfPersonRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Person"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isOrgUnitOfPerson", "isPersonOfOrgUnit"); + RelationshipType isOrgUnitOfProjectRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Project"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isOrgUnitOfProject", "isProjectOfOrgUnit"); + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); - RelationshipType isOrgUnitOfProjectRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, - entityTypeService.findByEntityType(context, "Project"), - entityTypeService.findByEntityType(context, "OrgUnit"), - "isOrgUnitOfProject", - "isProjectOfOrgUnit"); + Relationship relationship1 = RelationshipBuilder + .createRelationshipBuilder(context, auhor1, orgUnit1, isOrgUnitOfPersonRelationshipType).build(); - RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService.findbyTypesAndLabels(context, - entityTypeService.findByEntityType(context, "Publication"), - entityTypeService.findByEntityType(context, "Person"), - "isAuthorOfPublication", - "isPublicationOfAuthor"); - Relationship relationship1 = RelationshipBuilder.createRelationshipBuilder(context, auhor1, orgUnit1, isOrgUnitOfPersonRelationshipType).build(); + Relationship relationship2 = RelationshipBuilder + .createRelationshipBuilder(context, project1, orgUnit1, isOrgUnitOfProjectRelationshipType).build(); - Relationship relationship2 = RelationshipBuilder.createRelationshipBuilder(context, project1, orgUnit1, isOrgUnitOfProjectRelationshipType).build(); - - Relationship relationship3 = RelationshipBuilder.createRelationshipBuilder(context, publication, auhor1, isAuthorOfPublicationRelationshipType).build(); + Relationship relationship3 = RelationshipBuilder + .createRelationshipBuilder(context, publication, auhor1, isAuthorOfPublicationRelationshipType).build(); getClient().perform(get("/api/core/relationships")) @@ -167,5 +186,6 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT RelationshipMatcher.matchRelationship(relationship2), RelationshipMatcher.matchRelationship(relationship3) ))) - ; } + ; + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java index 9ebfafab84..49688f1cb3 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java @@ -18,21 +18,20 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.io.File; import java.sql.SQLException; +import java.util.Iterator; import java.util.List; -import javax.transaction.Transactional; - import org.dspace.app.rest.matcher.EntityTypeMatcher; import org.dspace.app.rest.matcher.RelationshipTypeMatcher; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; -import org.dspace.authorize.AuthorizeException; import org.dspace.content.EntityType; +import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.services.ConfigurationService; import org.h2.util.StringUtils; -import org.jbibtex.StringUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -46,6 +45,9 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat @Autowired private EntityTypeService entityTypeService; + @Autowired + private RelationshipService relationshipService; + @Autowired private ConfigurationService configurationService; @@ -59,25 +61,40 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat } @After - public void destroy() throws SQLException, AuthorizeException { - + public void destroy() throws Exception { //Clean up the database for the next test context.turnOffAuthorisationSystem(); List relationshipTypeList = relationshipTypeService.findAll(context); List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); - for (RelationshipType relationshipType : relationshipTypeList) { + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); relationshipTypeService.delete(context, relationshipType); } - for (EntityType entityType : entityTypeList) { + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); entityTypeService.delete(context, entityType); } - context.restoreAuthSystemState(); + + super.destroy(); } + @Test public void findAllRelationshipTypesTest() throws SQLException { - assertEquals(8, relationshipTypeService.findAll(context).size()); + assertEquals(9, relationshipTypeService.findAll(context).size()); } @Test @@ -97,6 +114,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isPublicationOfProject"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findPublicationOrgUnitRelationshipType() throws SQLException { String leftTypeString = "Publication"; @@ -105,6 +123,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isPublicationOfOrgUnit"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findPersonProjectRelationshipType() throws SQLException { String leftTypeString = "Person"; @@ -113,6 +132,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isPersonOfProject"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findPersonOrgUnitRelationshipType() throws SQLException { String leftTypeString = "Person"; @@ -121,6 +141,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isPersonOfOrgUnit"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findProjectOrgUnitRelationshipType() throws SQLException { String leftTypeString = "Project"; @@ -129,6 +150,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isProjectOfOrgUnit"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findJournalJournalVolumeRelationshipType() throws SQLException { String leftTypeString = "Journal"; @@ -137,6 +159,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isJournalOfVolume"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } + @Test public void findJournalVolumeJournalIssueRelationshipType() throws SQLException { String leftTypeString = "JournalVolume"; @@ -145,15 +168,18 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat String rightLabel = "isJournalVolumeOfIssue"; checkRelationshipType(leftTypeString, rightTypeString, leftLabel, rightLabel); } - private void checkRelationshipType(String leftType, String rightType, String leftLabel, String rightLabel) throws SQLException { - RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, - entityTypeService.findByEntityType(context,leftType), - entityTypeService.findByEntityType(context, rightType), - leftLabel, - rightLabel); + + private void checkRelationshipType(String leftType, String rightType, String leftLabel, String rightLabel) + throws SQLException { + RelationshipType relationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, leftType), + entityTypeService.findByEntityType(context, rightType), + leftLabel, rightLabel); assertNotNull(relationshipType); - assertEquals(entityTypeService.findByEntityType(context, leftType), relationshipType.getLeftType()); - assertEquals(entityTypeService.findByEntityType(context, rightType), relationshipType.getRightType()); + assertEquals(entityTypeService.findByEntityType(context, leftType), + relationshipType.getLeftType()); + assertEquals(entityTypeService.findByEntityType(context, rightType), + relationshipType.getRightType()); assertEquals(leftLabel, relationshipType.getLeftLabel()); assertEquals(rightLabel, relationshipType.getRightLabel()); } @@ -168,7 +194,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat //We expect a 200 OK status .andExpect(status().isOk()) //The type has to be 'discover' - .andExpect(jsonPath("$.page.totalElements", is(8))) + .andExpect(jsonPath("$.page.totalElements", is(9))) //There needs to be a self link to this endpoint .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) //We have 4 facets in the default configuration, they need to all be present in the embedded section @@ -180,27 +206,31 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7))) + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8))) )); } @Test - public void entityTypeForPublicationPersonRelationshipTypeTest() throws Exception{ + public void entityTypeForPublicationPersonRelationshipTypeTest() throws Exception { List relationshipTypes = relationshipTypeService.findAll(context); RelationshipType foundRelationshipType = null; for (RelationshipType relationshipType : relationshipTypes) { - if(StringUtils.equals(relationshipType.getLeftLabel(), "isAuthorOfPublication") && StringUtils.equals(relationshipType.getRightLabel(), "isPublicationOfAuthor")) { + if (StringUtils.equals(relationshipType.getLeftLabel(), "isAuthorOfPublication") && StringUtils + .equals(relationshipType.getRightLabel(), "isPublicationOfAuthor")) { foundRelationshipType = relationshipType; break; } } - if(foundRelationshipType != null) { - getClient().perform(get("/api/core/relationshiptypes/"+foundRelationshipType.getId())) - .andExpect(jsonPath("$._embedded.leftType", EntityTypeMatcher.matchEntityTypeEntryForLabel("Publication"))) - .andExpect(jsonPath("$._embedded.rightType", EntityTypeMatcher.matchEntityTypeEntryForLabel("Person"))); + if (foundRelationshipType != null) { + getClient().perform(get("/api/core/relationshiptypes/" + foundRelationshipType.getId())) + .andExpect(jsonPath("$._embedded.leftType", + EntityTypeMatcher.matchEntityTypeEntryForLabel("Publication"))) + .andExpect( + jsonPath("$._embedded.rightType", EntityTypeMatcher.matchEntityTypeEntryForLabel("Person"))); } else { throw new Exception("RelationshipType not found for isIssueOfJournalVolume"); } @@ -208,14 +238,17 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat } @Test - public void cardinalityOnAuthorPublicationRelationshipTypesTest() throws Exception{ - RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", "isPublicationOfAuthor"); + public void cardinalityOnAuthorPublicationRelationshipTypesTest() throws Exception { + RelationshipType relationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", + "isPublicationOfAuthor"); assertEquals(0, relationshipType.getLeftMinCardinality()); assertEquals(0, relationshipType.getRightMinCardinality()); assertEquals(Integer.MAX_VALUE, relationshipType.getLeftMaxCardinality()); assertEquals(Integer.MAX_VALUE, relationshipType.getRightMaxCardinality()); - getClient().perform(get("/api/core/relationshiptypes/"+relationshipType.getId())) + getClient().perform(get("/api/core/relationshiptypes/" + relationshipType.getId())) .andExpect(jsonPath("$.leftMinCardinality", is(0))) .andExpect(jsonPath("$.rightMinCardinality", is(0))) .andExpect(jsonPath("$.leftMaxCardinality", is(Integer.MAX_VALUE))) @@ -224,36 +257,43 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat } @Test - public void entityTypeForIssueJournalRelationshipTypeTest() throws Exception{ + public void entityTypeForIssueJournalRelationshipTypeTest() throws Exception { List relationshipTypes = relationshipTypeService.findAll(context); RelationshipType foundRelationshipType = null; for (RelationshipType relationshipType : relationshipTypes) { - if(StringUtils.equals(relationshipType.getLeftLabel(), "isIssueOfJournalVolume") && StringUtils.equals(relationshipType.getRightLabel(), "isJournalVolumeOfIssue")) { + if (StringUtils.equals(relationshipType.getLeftLabel(), "isIssueOfJournalVolume") && StringUtils + .equals(relationshipType.getRightLabel(), "isJournalVolumeOfIssue")) { foundRelationshipType = relationshipType; break; } } - if(foundRelationshipType != null) { - getClient().perform(get("/api/core/relationshiptypes/"+foundRelationshipType.getId())) - .andExpect(jsonPath("$._embedded.leftType", EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalVolume"))) - .andExpect(jsonPath("$._embedded.rightType", EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalIssue"))); + if (foundRelationshipType != null) { + getClient().perform(get("/api/core/relationshiptypes/" + foundRelationshipType.getId())) + .andExpect(jsonPath("$._embedded.leftType", + EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalVolume"))) + .andExpect(jsonPath("$._embedded.rightType", + EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalIssue"))); } else { throw new Exception("RelationshipType not found for isIssueOfJournalVolume"); } } + @Test - public void cardinalityOnIssueJournalJournalVolumeRelationshipTypesTest() throws Exception{ - RelationshipType relationshipType = relationshipTypeService.findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "JournalVolume"), entityTypeService.findByEntityType(context, "JournalIssue"), "isIssueOfJournalVolume", "isJournalVolumeOfIssue"); + public void cardinalityOnIssueJournalJournalVolumeRelationshipTypesTest() throws Exception { + RelationshipType relationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "JournalVolume"), + entityTypeService.findByEntityType(context, "JournalIssue"), "isIssueOfJournalVolume", + "isJournalVolumeOfIssue"); assertEquals(0, relationshipType.getLeftMinCardinality()); assertEquals(1, relationshipType.getRightMinCardinality()); assertEquals(Integer.MAX_VALUE, relationshipType.getLeftMaxCardinality()); assertEquals(1, relationshipType.getRightMaxCardinality()); - getClient().perform(get("/api/core/relationshiptypes/"+relationshipType.getId())) + getClient().perform(get("/api/core/relationshiptypes/" + relationshipType.getId())) .andExpect(jsonPath("$.leftMinCardinality", is(0))) .andExpect(jsonPath("$.rightMinCardinality", is(1))) .andExpect(jsonPath("$.leftMaxCardinality", is(Integer.MAX_VALUE))) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java index 48f805bd13..bf19b4b9c5 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RootRestResourceControllerIT.java @@ -34,25 +34,25 @@ public class RootRestResourceControllerIT extends AbstractControllerIntegrationT //We expect the content type to be "application/hal+json;charset=UTF-8" .andExpect(content().contentType(contentType)) //Check that all required root links are present and that they are absolute - .andExpect(jsonPath("$._links.authorities.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.bitstreamformats.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.bitstreams.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.browses.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.collections.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.communities.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.epersons.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.groups.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.items.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.metadatafields.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.metadataschemas.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.resourcePolicies.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.sites.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.submissiondefinitions.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.submissionforms.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.submissionsections.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.submissionuploads.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.workspaceitems.href", startsWith(REST_SERVER_URL))) - .andExpect(jsonPath("$._links.authn.href", startsWith(REST_SERVER_URL))) + .andExpect(jsonPath("$._links.authorities.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.bitstreamformats.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.bitstreams.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.browses.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.collections.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.communities.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.epersons.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.groups.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.items.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.metadatafields.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.metadataschemas.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.resourcePolicies.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.sites.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissiondefinitions.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionforms.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionsections.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.submissionuploads.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.workspaceitems.href", startsWith(BASE_REST_SERVER_URL))) + .andExpect(jsonPath("$._links.authn.href", startsWith(BASE_REST_SERVER_URL))) ; } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java index c4c744bc91..553251633f 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionDefinitionsControllerIT.java @@ -55,7 +55,7 @@ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegra .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect( - jsonPath("$._links.search.href", is(REST_SERVER_URL + "api/config/submissiondefinitions/search"))) + jsonPath("$._links.search.href", is(REST_SERVER_URL + "config/submissiondefinitions/search"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissiondefinitions", hasSize(greaterThanOrEqualTo(1)))) @@ -157,10 +157,10 @@ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegra hasJsonPath("$.type", is("submissionsection")), hasJsonPath("$._links.config.href", is(REST_SERVER_URL + - "api/config/submissionforms/traditionalpageone")), + "config/submissionforms/traditionalpageone")), hasJsonPath("$._links.self.href", is(REST_SERVER_URL + - "api/config/submissionsections/traditionalpageone")) + "config/submissionsections/traditionalpageone")) )))) ; } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java index 9ff7cdef20..643debcbfc 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionSectionsControllerIT.java @@ -48,7 +48,7 @@ public class SubmissionSectionsControllerIT extends AbstractControllerIntegratio .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect(jsonPath("$._links.self.href", - Matchers.startsWith(REST_SERVER_URL + "api/config/submissionsections"))) + Matchers.startsWith(REST_SERVER_URL + "config/submissionsections"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissionsections", hasSize(greaterThanOrEqualTo(1)) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java index f6b9d2dd86..07e570f609 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SubmissionUploadsControllerIT.java @@ -48,7 +48,7 @@ public class SubmissionUploadsControllerIT extends AbstractControllerIntegration .andExpect(jsonPath("$.page.totalPages", greaterThanOrEqualTo(1))) .andExpect(jsonPath("$.page.number", is(0))) .andExpect(jsonPath("$._links.self.href", - Matchers.startsWith(REST_SERVER_URL + "api/config/submissionuploads"))) + Matchers.startsWith(REST_SERVER_URL + "config/submissionuploads"))) //The array of browse index should have a size greater or equals to 1 .andExpect(jsonPath("$._embedded.submissionuploads", hasSize(greaterThanOrEqualTo(1)))) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java index 2fc9b306fe..1dd894b1bf 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.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.rest.builder; import java.sql.SQLException; @@ -38,7 +45,7 @@ public class RelationshipBuilder extends AbstractBuilder matchEntityTypeEntry(EntityType entityType) { return matchEntityTypeExplicitValuesEntry(entityType.getId(), entityType.getLabel()); } + public static Matcher matchEntityTypeEntryForLabel(String label) { return matchEntityTypeExplicitValuesEntry(0, label); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java index ebea0336b5..5ae6fe5fba 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/FacetEntryMatcher.java @@ -93,5 +93,12 @@ public class FacetEntryMatcher { return anyOf(hasJsonPath("$.next.href", containsString(path)), not(hasJsonPath("$.next.href", containsString(path)))); } - + public static Matcher entityTypeFacet(boolean hasNext) { + return allOf( + hasJsonPath("$.name", is("entityType")), + hasJsonPath("$.facetLimit", any(Integer.class)), + hasJsonPath("$._links.self.href", containsString("api/discover/facets/entityType")), + hasJsonPath("$._links", matchNextLink(hasNext, "api/discover/facets/entityType")) + ); + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java index dd858986ef..20a855ff5e 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipMatcher.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.rest.matcher; import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; @@ -13,22 +20,31 @@ import org.hamcrest.Matcher; public class RelationshipMatcher { + private RelationshipMatcher() {} + public static Matcher matchRelationship(Relationship relationship) { - return matchRelationshipExplicitValues(relationship.getLeftItem(), relationship.getRightItem(), relationship.getLeftPlace(), relationship.getRightPlace(), relationship.getRelationshipType()); + return matchRelationshipExplicitValues(relationship.getLeftItem(), relationship.getRightItem(), + relationship.getLeftPlace(), relationship.getRightPlace(), + relationship.getRelationshipType()); } - private static Matcher matchRelationshipExplicitValues(Item leftItem, Item rightItem, int leftPlace, int rightPlace, RelationshipType relationshipType) { - return matchRelationshipExplicitObjectValues(leftItem.getID(), rightItem.getID(), leftPlace, rightPlace, relationshipType); + private static Matcher matchRelationshipExplicitValues(Item leftItem, Item rightItem, int leftPlace, + int rightPlace, + RelationshipType relationshipType) { + return matchRelationshipExplicitObjectValues(leftItem.getID(), rightItem.getID(), leftPlace, rightPlace, + relationshipType); } - private static Matcher matchRelationshipExplicitObjectValues(UUID leftId, UUID rightId, int leftPlace, int rightPlace, - RelationshipType relationshipType) { + private static Matcher matchRelationshipExplicitObjectValues(UUID leftId, UUID rightId, + int leftPlace, int rightPlace, + RelationshipType relationshipType) { return allOf( - hasJsonPath("$.leftId",is(leftId.toString())), + hasJsonPath("$.leftId", is(leftId.toString())), hasJsonPath("$.rightId", is(rightId.toString())), hasJsonPath("$.leftPlace", is(leftPlace)), hasJsonPath("$.rightPlace", is(rightPlace)), - hasJsonPath("$._embedded.relationshipType", RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType)) + hasJsonPath("$._embedded.relationshipType", + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType)) ); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java index f3fc20592d..563d5849a0 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java @@ -18,37 +18,53 @@ import org.hamcrest.Matcher; import org.hamcrest.Matchers; public class RelationshipTypeMatcher { + + private RelationshipTypeMatcher() {} + public static Matcher matchRelationshipTypeEntry(RelationshipType relationshipType) { - return matchRelationshipTypeExplicitEntityTypes(relationshipType, relationshipType.getLeftType(), relationshipType.getRightType()); + return matchRelationshipTypeExplicitEntityTypes(relationshipType, relationshipType.getLeftType(), + relationshipType.getRightType()); } - private static Matcher matchRelationshipTypeExplicitEntityTypes(RelationshipType relationshipType, EntityType leftType, EntityType rightType) { - return matchRelationshipTypeExplicitEntityTypeValues(relationshipType, leftType.getId(), leftType.getLabel(), rightType.getId(), rightType.getLabel()); + private static Matcher matchRelationshipTypeExplicitEntityTypes(RelationshipType relationshipType, + EntityType leftType, + EntityType rightType) { + return matchRelationshipTypeExplicitEntityTypeValues(relationshipType, leftType.getId(), leftType.getLabel(), + rightType.getId(), rightType.getLabel()); } - private static Matcher matchRelationshipTypeExplicitEntityTypeValues(RelationshipType relationshipType, int leftEntityTypeId, String leftEntityTypeLabel, int rightEntityTypeId, - String rightEntityTypeLabel) { + private static Matcher matchRelationshipTypeExplicitEntityTypeValues( + RelationshipType relationshipType, int leftEntityTypeId, String leftEntityTypeLabel, int rightEntityTypeId, + String rightEntityTypeLabel) { - return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(relationshipType.getId(), relationshipType.getLeftLabel(), relationshipType.getRightLabel(), - relationshipType.getLeftMinCardinality(), relationshipType.getLeftMaxCardinality(), - relationshipType.getRightMinCardinality(), relationshipType.getRightMaxCardinality(), - leftEntityTypeId, leftEntityTypeLabel, rightEntityTypeId, rightEntityTypeLabel); + return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(relationshipType.getId(), + relationshipType.getLeftLabel(), + relationshipType.getRightLabel(), + relationshipType.getLeftMinCardinality(), + relationshipType.getLeftMaxCardinality(), + relationshipType.getRightMinCardinality(), + relationshipType.getRightMaxCardinality(), + leftEntityTypeId, leftEntityTypeLabel, + rightEntityTypeId, rightEntityTypeLabel); } - private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityType(int id, String leftLabel, String rightLabel, - int leftMinCardinality, int leftMaxCardinality, - int rightMinCardinality, int rightMaxCardinality, - EntityType leftEntityType, EntityType rightEntityType) { - return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(id, leftLabel, rightLabel, leftMinCardinality, leftMaxCardinality, rightMinCardinality, - rightMaxCardinality, leftEntityType.getId(), leftEntityType.getLabel(), - rightEntityType.getId(), rightEntityType.getLabel()); + private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityType(int id, + String leftLabel, String rightLabel, int leftMinCardinality, int leftMaxCardinality, + int rightMinCardinality, int rightMaxCardinality, EntityType leftEntityType, EntityType rightEntityType) { + return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(id, leftLabel, rightLabel, + leftMinCardinality, leftMaxCardinality, + rightMinCardinality, + rightMaxCardinality, + leftEntityType.getId(), + leftEntityType.getLabel(), + rightEntityType.getId(), + rightEntityType.getLabel()); } - private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(int id, String leftLabel, String rightLabel, - int leftMinCardinality, int leftMaxCardinality, - int rightMinCardinality, int rightMaxCardinality, - int leftEntityTypeId, String leftEntityTypeLabel, - int rightEntityTypeId, String rightEntityTypeLabel) { + private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(int id, + String leftLabel, String rightLabel, int leftMinCardinality, int leftMaxCardinality, + int rightMinCardinality, int rightMaxCardinality, int leftEntityTypeId, String leftEntityTypeLabel, + int rightEntityTypeId, String rightEntityTypeLabel) { return allOf( hasJsonPath("$.id", is(id)), hasJsonPath("$.leftLabel", is(leftLabel)), @@ -67,4 +83,4 @@ public class RelationshipTypeMatcher { )) ); } -} +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java index da344e47b4..61ba0b48c6 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SearchFilterMatcher.java @@ -102,4 +102,13 @@ public class SearchFilterMatcher { )) ); } + public static Matcher entityTypeFilter() { + return allOf( + hasJsonPath("$.filter", is("entityType")), + hasJsonPath("$.hasFacets", is(true)), + hasJsonPath("$.type", is("text")), + hasJsonPath("$.openByDefault", is(false)), + checkOperators() + ); + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java index c92f99c5e1..d8e85f3495 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/SubmissionDefinitionsMatcher.java @@ -27,9 +27,9 @@ public class SubmissionDefinitionsMatcher { hasJsonPath("$.name", is(name)), hasJsonPath("$.id", is(id)), hasJsonPath("$.type", is("submissiondefinition")), - hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "api/config/submissiondefinitions/" + id)), + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "config/submissiondefinitions/" + id)), hasJsonPath("$._links.sections.href", - is(REST_SERVER_URL + "api/config/submissiondefinitions/" + id + "/sections")) + is(REST_SERVER_URL + "config/submissiondefinitions/" + id + "/sections")) ); } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java index ade7327c33..f0674e4251 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java @@ -34,7 +34,6 @@ import org.springframework.hateoas.MediaTypes; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.TestExecutionListeners; @@ -45,8 +44,6 @@ import org.springframework.test.context.transaction.TransactionalTestExecutionLi import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.RequestPostProcessor; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.test.web.servlet.request.RequestPostProcessor; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; import org.springframework.web.context.WebApplicationContext; @@ -59,7 +56,7 @@ import org.springframework.web.context.WebApplicationContext; */ @RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = {Application.class, ApplicationConfig.class, WebSecurityConfiguration.class, - MethodSecurityConfig.class}) + MethodSecurityConfig.class}) @TestExecutionListeners( {DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class, TransactionalTestExecutionListener.class}) @DirtiesContext @@ -72,11 +69,8 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi //sits before the actual authentication token and can be used to easily compose or parse the Authorization header. protected static final String AUTHORIZATION_TYPE = "Bearer "; - protected static final String REQUEST_SCHEME = "http"; - protected static final String REQUEST_NAME = "localhost"; - protected static final int REQUEST_PORT = 8080; - protected static final String REQUEST_CONTEXTPATH = "rest"; - public static final String REST_SERVER_URL = REQUEST_SCHEME + "://" + REQUEST_NAME + ":" + REQUEST_PORT + "/" + REQUEST_CONTEXTPATH +"/"; + public static final String REST_SERVER_URL = "http://localhost/api/"; + public static final String BASE_REST_SERVER_URL = "http://localhost"; protected MediaType contentType = new MediaType(MediaTypes.HAL_JSON.getType(), MediaTypes.HAL_JSON.getSubtype(), Charsets.UTF_8); @@ -116,19 +110,10 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi .addFilters(new ErrorPageFilter()) .addFilters(requestFilters.toArray(new Filter[requestFilters.size()])); - MockHttpServletRequestBuilder defaultRequestParameters = get("") - .with(request -> { - request.setScheme(REQUEST_SCHEME); - request.setServerName(REQUEST_NAME); - request.setServerPort(REQUEST_PORT); - request.setContextPath(REQUEST_CONTEXTPATH); - return request; - }); if (StringUtils.isNotBlank(authToken)) { mockMvcBuilder.defaultRequest( - get("").header(AUTHORIZATION_HEADER, AUTHORIZATION_TYPE + authToken)); + get("").header(AUTHORIZATION_HEADER, AUTHORIZATION_TYPE + authToken)); } - mockMvcBuilder.defaultRequest(defaultRequestParameters); return mockMvcBuilder .build(); @@ -143,8 +128,8 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi public String getAuthToken(String user, String password) throws Exception { return StringUtils.substringAfter( - getAuthResponse(user, password).getHeader(AUTHORIZATION_HEADER), - AUTHORIZATION_TYPE); + getAuthResponse(user, password).getHeader(AUTHORIZATION_HEADER), + AUTHORIZATION_TYPE); } public String getPatchContent(List ops) { @@ -163,5 +148,4 @@ public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWi return request; }; } -} - +} \ No newline at end of file diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 170e1af45a..1d9ad66117 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -175,6 +175,15 @@
+ + + + + + + + + - - - - - - diff --git a/dspace/config/launcher.xml b/dspace/config/launcher.xml index fb8f893ca3..834aabf42a 100644 --- a/dspace/config/launcher.xml +++ b/dspace/config/launcher.xml @@ -373,12 +373,4 @@ org.dspace.app.util.InitializeEntities - - - additional-relationship-demo - Creates additional relationships for the demo - - org.dspace.app.util.AdditionalRelationshipScript - - diff --git a/dspace/config/modules/bulkedit.cfg b/dspace/config/modules/bulkedit.cfg index 9bea4c4964..92a258fa1c 100644 --- a/dspace/config/modules/bulkedit.cfg +++ b/dspace/config/modules/bulkedit.cfg @@ -9,7 +9,7 @@ # bulkedit.valueseparator = || # The delimiter used to separate fields (defaults to a comma for CSV) -bulkedit.fieldseparator = , +# bulkedit.fieldseparator = , # The delimiter used to serarate authority data (defaults to a double colon ::) # bulkedit.authorityseparator = :: From c30e548533a24a8ba616697f352657c5293a1df9 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 12 Nov 2018 09:26:18 +0100 Subject: [PATCH 014/188] use only one extraction of the UUID --- .../main/java/org/dspace/app/bulkedit/MetadataImport.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 2de433fe78..b4cca2829c 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 @@ -692,11 +692,12 @@ public class MetadataImport { boolean left = false; List acceptableRelationshipTypes = new LinkedList<>(); String url = handleService.resolveToURL(c, values.get(0)); - if (UUIDUtils.fromString(values.get(0)) == null && StringUtils.isNotBlank(url)) { + UUID uuid = UUIDUtils.fromString(values.get(0)); + if (uuid == null && StringUtils.isNotBlank(url)) { return; } - Entity relationEntity = entityService.findByItemId(c, UUID.fromString(values.get(0))); + Entity relationEntity = entityService.findByItemId(c, uuid); List leftRelationshipTypesForEntity = entityService.getLeftRelationshipTypes(c, entity); From 45afa91d0e094bf7df608ede21fc2b063b9e9941 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 12 Nov 2018 09:32:40 +0100 Subject: [PATCH 015/188] Removed setter since it's no longer used --- .../src/main/java/org/dspace/content/Relationship.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/Relationship.java b/dspace-api/src/main/java/org/dspace/content/Relationship.java index e8ebcfa645..a21cfc7628 100644 --- a/dspace-api/src/main/java/org/dspace/content/Relationship.java +++ b/dspace-api/src/main/java/org/dspace/content/Relationship.java @@ -84,14 +84,6 @@ public class Relationship implements ReloadableEntity { return id; } - /** - * Standard setter for the ID field - * @param id The ID to be set - */ - public void setId(Integer id) { - this.id = id; - } - /** * Standard getter for the leftItem field * @return The leftItem Item object in this relationship From b3a4a196d8e1980a75ff31100ada3b505311fd80 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 12 Nov 2018 12:43:10 +0100 Subject: [PATCH 016/188] [Task 57107] changed the functionality of the VirtualMetadataPopulator to now support a bean --- .../org/dspace/content/ItemServiceImpl.java | 26 ++-- .../dspace/content/virtual/Concatenate.java | 25 ++++ dspace/config/spring/api/core-services.xml | 132 +++++++++++++----- 3 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java 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 9bed048031..ec5b133efe 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -41,6 +41,7 @@ import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.content.virtual.VirtualMetadataPopulator; +import org.dspace.content.virtual.Concatenate; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; @@ -1328,16 +1329,16 @@ prevent the generation of resource policy entry values with null dspace_object a Relationship relationship) { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); - HashMap> hashMaps = new HashMap<>(); + HashMap hashMaps = new HashMap<>(); String relationName = ""; Item otherItem = null; if (StringUtils.equals(relationshipType.getLeftType().getLabel(), entityType)) { - hashMaps = (HashMap>) virtualMetadataPopulator + hashMaps = (HashMap) virtualMetadataPopulator .getMap().get(relationshipType.getLeftLabel()); otherItem = relationship.getRightItem(); relationName = relationship.getRelationshipType().getLeftLabel(); } else if (StringUtils.equals(relationshipType.getRightType().getLabel(), entityType)) { - hashMaps = (HashMap>) virtualMetadataPopulator + hashMaps = (HashMap) virtualMetadataPopulator .getMap().get(relationshipType.getRightLabel()); otherItem = relationship.getLeftItem(); relationName = relationship.getRelationshipType().getRightLabel(); @@ -1352,16 +1353,16 @@ prevent the generation of resource policy entry values with null dspace_object a } private List handleRelationshipTypeMetadataMappping(Item item, - HashMap> hashMaps, + HashMap hashMaps, Item otherItem, String relationName) { List resultingMetadataValueList = new LinkedList<>(); - for (Map.Entry> entry : hashMaps.entrySet()) { + for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); - List value = entry.getValue(); + Concatenate concatenate = entry.getValue(); MetadataValue metadataValue = constructMetadataValue(key); - metadataValue = constructResultingMetadataValue(item, otherItem, value, metadataValue); + metadataValue = constructResultingMetadataValue(item, otherItem, concatenate, metadataValue); if (StringUtils.isNotBlank(metadataValue.getValue())) { resultingMetadataValueList.add(metadataValue); } @@ -1370,7 +1371,7 @@ prevent the generation of resource policy entry values with null dspace_object a } private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName) { - MetadataValue metadataValue = constructMetadataValue("relation_" + relationName); + MetadataValue metadataValue = constructMetadataValue("relation." + relationName); metadataValue.setAuthority("virtual"); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; @@ -1390,9 +1391,10 @@ prevent the generation of resource policy entry values with null dspace_object a return entityType; } - private MetadataValue constructResultingMetadataValue(Item item, Item otherItem, List value, + private MetadataValue constructResultingMetadataValue(Item item, Item otherItem, Concatenate concatenate, MetadataValue metadataValue) { List resultValues = new LinkedList<>(); + List value = concatenate.getFields(); for (String s : value) { String[] splittedString = s.split("\\."); @@ -1407,7 +1409,7 @@ prevent the generation of resource policy entry values with null dspace_object a String metadataValueString = resultList.get(i).getValue(); if (StringUtils.isNotBlank(metadataValueString)) { if (StringUtils.isNotBlank(resultString)) { - resultString += ", "; + resultString += concatenate.getSeparator(); } resultString += metadataValueString; } @@ -1417,7 +1419,7 @@ prevent the generation of resource policy entry values with null dspace_object a } } - String result = StringUtils.join(resultValues, ", "); + String result = StringUtils.join(resultValues, concatenate.getSeparator()); metadataValue.setValue(result); metadataValue.setAuthority("virtual"); metadataValue.setConfidence(-1); @@ -1426,7 +1428,7 @@ prevent the generation of resource policy entry values with null dspace_object a } private MetadataValue constructMetadataValue(String key) { - String[] splittedKey = key.split("_"); + String[] splittedKey = key.split("\\."); MetadataValue metadataValue = new MetadataValue(); MetadataField metadataField = new MetadataField(); MetadataSchema metadataSchema = new MetadataSchema(); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java new file mode 100644 index 0000000000..9e4e73f7aa --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -0,0 +1,25 @@ +package org.dspace.content.virtual; + +import java.util.List; + +public class Concatenate { + + private List fields; + private String separator; + + public List getFields() { + return fields; + } + + public void setFields(List fields) { + this.fields = fields; + } + + public String getSeparator() { + return separator; + } + + public void setSeparator(String separator) { + this.separator = separator; + } +} diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 02c363749e..f4399a1788 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -126,7 +126,7 @@ - + @@ -143,69 +143,131 @@
- + - - orgunit.identifier.name - person.identifier.lastname - person.identifier.firstname - + + + + person.identifier.lastname + person.identifier.firstname + + + + , + + - - orgunit.identifier.name - + + + + orgunit.identifier.name + + + + , + + - - person.identifier.lastname - person.identifier.firstname - + + + + person.identifier.lastname + person.identifier.firstname + + + + , + + - - orgunit.identifier.name - + + + + orgunit.identifier.name + + + + , + + - - orgunit.identifier.name - + + + + orgunit.identifier.name + + + + , + + - - journalvolume.identifier.volume - + + + + journalvolume.identifier.volume + + + + , + + - - + + - - journal.identifier.issn - - - journal.identifier.name - - + + + + journal.identifier.issn + + + + , + + + + + + journal.identifier.name + + + + , + + + - - journalissue.identifier.number - + + + + journalissue.identifier.number + + + + , + +
From b226666113fafab7503a9fb33d5454fec60cff37 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 12 Nov 2018 13:11:43 +0100 Subject: [PATCH 017/188] Added loops to set places on left and right places for relationships on create and delete --- .../java/org/dspace/content/RelationshipServiceImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 9e9fee8f85..7eb1dae6b4 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -73,6 +73,9 @@ public class RelationshipServiceImpl implements RelationshipService { if (!leftRelationships.isEmpty()) { leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); + for (int i = 0; i < leftRelationships.size(); i++) { + leftRelationships.get(i).setLeftPlace(i + 1); + } relationship.setLeftPlace(leftRelationships.get(0).getLeftPlace() + 1); } else { relationship.setLeftPlace(1); @@ -80,6 +83,9 @@ public class RelationshipServiceImpl implements RelationshipService { if (!rightRelationships.isEmpty()) { rightRelationships.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); + for (int i = 0; i < rightRelationships.size(); i++) { + rightRelationships.get(i).setRightPlace(i + 1); + } relationship.setRightPlace(rightRelationships.get(0).getRightPlace() + 1); } else { relationship.setRightPlace(1); @@ -215,6 +221,8 @@ public class RelationshipServiceImpl implements RelationshipService { "Only administrators can delete relationship"); } relationshipDAO.delete(context, relationship); + + updatePlaceInRelationship(context, relationship); } else { throw new IllegalArgumentException("The relationship given was not valid"); } From 37ffda5d21b9ed0fb291caa550bc5cf0df144be5 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 12 Nov 2018 15:56:28 +0100 Subject: [PATCH 018/188] Made sure that the delete and create functions in relationshipservice update the place attributes accordingly. Fixed checkstyle and added license header. Changed cacheable functions to false in relationshipDAO --- .../main/java/org/dspace/app/bulkedit/MetadataImport.java | 8 ++++++-- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 2 +- .../java/org/dspace/content/RelationshipServiceImpl.java | 4 ++-- .../org/dspace/content/dao/impl/RelationshipDAOImpl.java | 6 +++--- .../main/java/org/dspace/content/virtual/Concatenate.java | 7 +++++++ 5 files changed, 19 insertions(+), 8 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 492a657035..ef19942b55 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 @@ -638,9 +638,13 @@ public class MetadataImport { if (StringUtils.equals(schema, "relation")) { - List relationshipTypeList = relationshipTypeService.findByLeftOrRightLabel(c, element); + List relationshipTypeList = relationshipTypeService + .findByLeftOrRightLabel(c, element); for (RelationshipType relationshipType : relationshipTypeList) { - for (Relationship relationship : relationshipService.findByItemAndRelationshipType(c, item, relationshipType)) { + for (Relationship relationship : relationshipService + .findByItemAndRelationshipType(c, + item, + relationshipType)) { relationshipService.delete(c, relationship); relationshipService.update(c, relationship); } 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 9c4075cd69..0b7fa47b2f 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -40,8 +40,8 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.content.virtual.Concatenate; +import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index e7bdb8a745..e996f21e2b 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -74,7 +74,7 @@ public class RelationshipServiceImpl implements RelationshipService { if (!leftRelationships.isEmpty()) { leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); for (int i = 0; i < leftRelationships.size(); i++) { - leftRelationships.get(i).setLeftPlace(i + 1); + leftRelationships.get(leftRelationships.size() - 1 - i).setLeftPlace(i + 1); } relationship.setLeftPlace(leftRelationships.get(0).getLeftPlace() + 1); } else { @@ -84,7 +84,7 @@ public class RelationshipServiceImpl implements RelationshipService { if (!rightRelationships.isEmpty()) { rightRelationships.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); for (int i = 0; i < rightRelationships.size(); i++) { - rightRelationships.get(i).setRightPlace(i + 1); + rightRelationships.get(rightRelationships.size() - 1 - i).setRightPlace(i + 1); } relationship.setRightPlace(rightRelationships.get(0).getRightPlace() + 1); } else { diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java index 5b3e33f5b5..ecc5fd84b4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java @@ -30,7 +30,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl criteriaQuery .where(criteriaBuilder.or(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item), criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item))); - return list(context, criteriaQuery, true, Relationship.class, -1, -1); + return list(context, criteriaQuery, false, Relationship.class, -1, -1); } public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { @@ -39,7 +39,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl Root relationshipRoot = criteriaQuery.from(Relationship.class); criteriaQuery.select(relationshipRoot); criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item)); - List list = list(context, criteriaQuery, true, Relationship.class, -1, -1); + List list = list(context, criteriaQuery, false, Relationship.class, -1, -1); list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); if (!list.isEmpty()) { return list.get(0).getLeftPlace(); @@ -54,7 +54,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl Root relationshipRoot = criteriaQuery.from(Relationship.class); criteriaQuery.select(relationshipRoot); criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)); - List list = list(context, criteriaQuery, true, Relationship.class, -1, -1); + List list = list(context, criteriaQuery, false, Relationship.class, -1, -1); list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); if (!list.isEmpty()) { return list.get(0).getLeftPlace(); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index 9e4e73f7aa..e36813d9ee 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.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.content.virtual; import java.util.List; From 353d4c9d60b10cc23dadb565d8c5646d64f551d8 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 14 Nov 2018 16:06:33 +0100 Subject: [PATCH 019/188] [Task 57103] implemented the support for related beans and added the option for config to supply virtual metadata throughout many nested relations --- .../org/dspace/content/ItemServiceImpl.java | 62 ++++-------- .../dspace/content/virtual/Concatenate.java | 49 +++++++++- .../org/dspace/content/virtual/Related.java | 96 +++++++++++++++++++ .../dspace/content/virtual/VirtualBean.java | 11 +++ dspace/config/spring/api/core-services.xml | 19 +++- 5 files changed, 192 insertions(+), 45 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/Related.java create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java 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 0b7fa47b2f..866e112545 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -41,6 +41,7 @@ import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.content.virtual.Concatenate; +import org.dspace.content.virtual.VirtualBean; import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -1327,54 +1328,56 @@ prevent the generation of resource policy entry values with null dspace_object a if (StringUtils.isNotBlank(entityType)) { List relationships = relationshipService.findByItem(context, item); for (Relationship relationship : relationships) { - fullMetadataValueList.addAll(handleItemRelationship(item, entityType, relationship, extra)); + fullMetadataValueList.addAll(handleItemRelationship(context, item, entityType, relationship, extra)); } } } catch (SQLException e) { log.error(e, e); + } finally { + context.close(); } return fullMetadataValueList; } - private List handleItemRelationship(Item item, String entityType, - Relationship relationship, boolean extra) { + private List handleItemRelationship(Context context, Item item, String entityType, + Relationship relationship, boolean extra) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); - HashMap hashMaps = new HashMap<>(); + HashMap hashMaps = new HashMap<>(); String relationName = ""; Item otherItem = null; if (StringUtils.equals(relationshipType.getLeftType().getLabel(), entityType)) { - hashMaps = (HashMap) virtualMetadataPopulator + hashMaps = (HashMap) virtualMetadataPopulator .getMap().get(relationshipType.getLeftLabel()); otherItem = relationship.getRightItem(); relationName = relationship.getRelationshipType().getLeftLabel(); } else if (StringUtils.equals(relationshipType.getRightType().getLabel(), entityType)) { - hashMaps = (HashMap) virtualMetadataPopulator + hashMaps = (HashMap) virtualMetadataPopulator .getMap().get(relationshipType.getRightLabel()); otherItem = relationship.getLeftItem(); relationName = relationship.getRelationshipType().getRightLabel(); } if (hashMaps != null && extra) { - resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(item, hashMaps, + resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(context, item, hashMaps, otherItem, relationName)); } resultingMetadataValueList.add(getRelationMetadataFromOtherItem(otherItem, relationName)); return resultingMetadataValueList; } - private List handleRelationshipTypeMetadataMappping(Item item, - HashMap hashMaps, + private List handleRelationshipTypeMetadataMappping(Context context, Item item, + HashMap hashMaps, Item otherItem, - String relationName) { + String relationName) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); - for (Map.Entry entry : hashMaps.entrySet()) { + for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); - Concatenate concatenate = entry.getValue(); + VirtualBean virtualBean = entry.getValue(); MetadataValue metadataValue = constructMetadataValue(key); - metadataValue = constructResultingMetadataValue(item, otherItem, concatenate, metadataValue); + metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue); if (StringUtils.isNotBlank(metadataValue.getValue())) { resultingMetadataValueList.add(metadataValue); } @@ -1403,36 +1406,9 @@ prevent the generation of resource policy entry values with null dspace_object a return entityType; } - private MetadataValue constructResultingMetadataValue(Item item, Item otherItem, Concatenate concatenate, - MetadataValue metadataValue) { - List resultValues = new LinkedList<>(); - List value = concatenate.getFields(); - for (String s : value) { - String[] splittedString = s.split("\\."); - - List resultList = this.getMetadata(otherItem, - splittedString.length > 0 ? splittedString[0] : null, - splittedString.length > 1 ? splittedString[1] : null, - splittedString.length > 2 ? splittedString[2] : null, - Item.ANY); - - String resultString = ""; - for (int i = 0; i < resultList.size(); i++) { - String metadataValueString = resultList.get(i).getValue(); - if (StringUtils.isNotBlank(metadataValueString)) { - if (StringUtils.isNotBlank(resultString)) { - resultString += concatenate.getSeparator(); - } - resultString += metadataValueString; - } - } - if (StringUtils.isNotBlank(resultString)) { - resultValues.add(resultString); - } - } - - String result = StringUtils.join(resultValues, concatenate.getSeparator()); - metadataValue.setValue(result); + private MetadataValue constructResultingMetadataValue(Context context, Item item, Item otherItem, VirtualBean virtualBean, + MetadataValue metadataValue) throws SQLException { + metadataValue.setValue(virtualBean.getValue(context, otherItem)); metadataValue.setAuthority("virtual"); metadataValue.setConfidence(-1); metadataValue.setDSpaceObject(item); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index e36813d9ee..43f3d9319f 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -7,9 +7,20 @@ */ package org.dspace.content.virtual; +import java.util.LinkedList; import java.util.List; -public class Concatenate { +import org.apache.commons.lang.StringUtils; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class Concatenate implements VirtualBean { + + @Autowired + private ItemService itemService; private List fields; private String separator; @@ -29,4 +40,40 @@ public class Concatenate { public void setSeparator(String separator) { this.separator = separator; } + + public String getValue(Context context, Item item) { + + List resultValues = new LinkedList<>(); + List value = this.getFields(); + for (String s : value) { + String[] splittedString = s.split("\\."); + + List resultList = itemService.getMetadata(item, + splittedString.length > 0 ? splittedString[0] : + null, + splittedString.length > 1 ? splittedString[1] : + null, + splittedString.length > 2 ? splittedString[2] : + null, + Item.ANY); + + String resultString = ""; + for (int i = 0; i < resultList.size(); i++) { + String metadataValueString = resultList.get(i).getValue(); + if (StringUtils.isNotBlank(metadataValueString)) { + if (StringUtils.isNotBlank(resultString)) { + resultString += this.getSeparator(); + } + resultString += metadataValueString; + } + } + if (StringUtils.isNotBlank(resultString)) { + resultValues.add(resultString); + } + } + + String result = StringUtils.join(resultValues, this.getSeparator()); + + return result; + } } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java new file mode 100644 index 0000000000..5defb559a4 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -0,0 +1,96 @@ +package org.dspace.content.virtual; + +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.dspace.content.Entity; +import org.dspace.content.EntityType; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityService; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class Related implements VirtualBean { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private RelationshipService relationshipService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private EntityService entityService; + + private String relationshipTypeString; + private Integer place; + private VirtualBean virtualBean; + + public String getRelationshipTypeString() { + return relationshipTypeString; + } + + public void setRelationshipTypeString(String relationshipTypeString) { + this.relationshipTypeString = relationshipTypeString; + } + + public Integer getPlace() { + return place; + } + + public void setPlace(Integer place) { + this.place = place; + } + + public VirtualBean getVirtualBean() { + return virtualBean; + } + + public void setVirtualBean(VirtualBean virtualBean) { + this.virtualBean = virtualBean; + } + + public String getValue(Context context, Item item) throws SQLException { + Entity entity = entityService.findByItemId(context, item.getID()); + EntityType entityType = entityService.getType(context, entity); + + List relationshipTypes = entityService.getAllRelationshipTypes(context, entity); + List possibleRelationshipTypes = new LinkedList<>(); + for (RelationshipType relationshipType : relationshipTypes) { + if (StringUtils.equals(relationshipType.getLeftLabel(), relationshipTypeString) || StringUtils + .equals(relationshipType.getRightLabel(), relationshipTypeString)) { + possibleRelationshipTypes.add(relationshipType); + } + } + + List relationships = new LinkedList<>(); + for (RelationshipType relationshipType : possibleRelationshipTypes) { + relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType)); + } + + for (Relationship relationship : relationships) { + if (relationship.getRelationshipType().getLeftType() == entityType) { + if (relationship.getLeftPlace() == place) { + Item otherItem = relationship.getRightItem(); + return virtualBean.getValue(context, otherItem); + } + } else if (relationship.getRelationshipType().getRightType() == entityType) { + if (relationship.getRightPlace() == place) { + Item otherItem = relationship.getLeftItem(); + return virtualBean.getValue(context, otherItem); + } + } + } + + return null; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java new file mode 100644 index 0000000000..41946eb420 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java @@ -0,0 +1,11 @@ +package org.dspace.content.virtual; + +import java.sql.SQLException; + +import org.dspace.content.Item; +import org.dspace.core.Context; + +public interface VirtualBean { + + String getValue(Context context, Item item) throws SQLException; +} diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index f4399a1788..565a6a4f8d 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -128,6 +128,7 @@ +
@@ -215,7 +216,8 @@
- + + @@ -227,6 +229,11 @@ , + + + + + @@ -269,5 +276,15 @@ ,
+ + + + + + + + + + From 86cd0c702582df8bd916385ea6d03cf89c44cd9b Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 15 Nov 2018 09:27:56 +0100 Subject: [PATCH 020/188] [Task 57103] added javadoc --- .../dspace/content/virtual/Concatenate.java | 33 +++++++++++++ .../org/dspace/content/virtual/Related.java | 47 +++++++++++++++++++ .../dspace/content/virtual/VirtualBean.java | 17 +++++++ 3 files changed, 97 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index 43f3d9319f..78096d5b41 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -17,30 +17,63 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; +/** + * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + */ public class Concatenate implements VirtualBean { @Autowired private ItemService itemService; + /** + * The fields for which the metadata will be retrieved + */ private List fields; + /** + * The seperator that will be used to concatenate the values retrieved from the above mentioned fields + */ private String separator; + /** + * Generic getter for the fields property + * @return The list of fields to be used in this bean + */ public List getFields() { return fields; } + /** + * Generic setter for the fields property + * @param fields the list of fields to which the fields property will be set to + */ public void setFields(List fields) { this.fields = fields; } + /** + * Generic getter for the seperator + * @return the seperator to be used by this bean + */ public String getSeparator() { return separator; } + /** + * Generic setter for the seperator property + * @param separator The String seperator value to which this seperator value will be set to + */ public void setSeparator(String separator) { this.separator = separator; } + /** + * this method will retrieve the metadata values from the given item for all the metadata fields listed + * in the fields property and it'll concatenate all those values together with the seperrator specified + * in this class + * @param context The relevant DSpace context + * @param item The item that will be used to either retrieve metadata values from + * @return The String value for all of the retrieved metadatavalues combined with the seperator + */ public String getValue(Context context, Item item) { List resultValues = new LinkedList<>(); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 5defb559a4..50b0f1b74b 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -17,6 +17,10 @@ import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; +/** + * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + * by traversing the path of relation specified in the config for this bean + */ public class Related implements VirtualBean { @Autowired @@ -31,34 +35,77 @@ public class Related implements VirtualBean { @Autowired private EntityService entityService; + /** + * The String representing the relationshipType that needs to be used to find the next item + */ private String relationshipTypeString; + /** + * The left or right place that this relationship needs to have to retrieve the proper item + */ private Integer place; + /** + * The next bean to call its getValue() method on + */ private VirtualBean virtualBean; + /** + * Generic getter for the relationshipTypeString property of this class + * @return The relationshipTypeString property + */ public String getRelationshipTypeString() { return relationshipTypeString; } + /** + * Generic setter for the relationshipTypeString property of this class + * @param relationshipTypeString The String to which the relationshipTypeString will be set to + */ public void setRelationshipTypeString(String relationshipTypeString) { this.relationshipTypeString = relationshipTypeString; } + /** + * Generic getter for the place property of this class + * @return The place property + */ public Integer getPlace() { return place; } + /** + * Generic setter for the place property of this class + * @param place The Integer to which the place property will be set to + */ public void setPlace(Integer place) { this.place = place; } + /** + * Generic getter for the virtualBean property of this class + * @return The virtualBean property + */ public VirtualBean getVirtualBean() { return virtualBean; } + /** + * Generic setter for the virtualBean property of this class + * @param virtualBean The VirtualBean to which the virtualBean property will be set to + */ public void setVirtualBean(VirtualBean virtualBean) { this.virtualBean = virtualBean; } + /** + * This method will find the correct Relationship from the given item to retrieve the other item from it + * and pass this along to the next VirtualBean that's stored in this class. + * @param context The relevant DSpace context + * @param item The item that will be used to find the related item through its relationships + * @return The String value of the metadata fields concatened with a seperator as defined + * in the deepest Concatened bean in the chain + * Will return null if no relationships are found + * @throws SQLException If something goes wrong + */ public String getValue(Context context, Item item) throws SQLException { Entity entity = entityService.findByItemId(context, item.getID()); EntityType entityType = entityService.getType(context, entity); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java index 41946eb420..b3f20f1054 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java @@ -5,7 +5,24 @@ import java.sql.SQLException; import org.dspace.content.Item; import org.dspace.core.Context; +/** + * This interface describes beans to be used for the {@link VirtualMetadataPopulator} implementation. + * The config is located in core-services.xml whilst the actual code implementation is located in + * {@link org.dspace.content.ItemServiceImpl} + */ public interface VirtualBean { + /** + * This method will return the String value for the metadata field that is configured in the + * {@link Concatenate} bean in the config and it will traverse all the {@link Related} beans + * in the config that are chained together until it finds a {@link Concatenate} bean for which + * the value can be retrieved. + * @param context The relevant DSpace context + * @param item The item that will be used to either retrieve metadata values from or to find + * the related item through its relationships + * @return The String value of all the metadata values of all fields defined in {@link Concatenate} + * bean which will be concatenated with a seperator that's defined in the same bean + * @throws SQLException If something goes wrong + */ String getValue(Context context, Item item) throws SQLException; } From 7b2233a9b7c4740d1601115d89dac0de9b26b5ff Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 15 Nov 2018 10:45:45 +0100 Subject: [PATCH 021/188] [Task 57186] added useForPlace property to the beans and added setters and getters to the interface. defaulting to false. Added this property to the isAuthorOfPublication config --- .../dspace/content/virtual/Concatenate.java | 22 +++++++++++++++++++ .../org/dspace/content/virtual/Related.java | 22 +++++++++++++++++++ .../dspace/content/virtual/VirtualBean.java | 12 ++++++++++ dspace/config/spring/api/core-services.xml | 1 + 4 files changed, 57 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index 78096d5b41..6016de52e9 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -34,6 +34,11 @@ public class Concatenate implements VirtualBean { */ private String separator; + /** + * The boolean value indicating whether this field should be used for place or not + */ + private boolean useForPlace = false; + /** * Generic getter for the fields property * @return The list of fields to be used in this bean @@ -66,6 +71,22 @@ public class Concatenate implements VirtualBean { this.separator = separator; } + /** + * Generic setter for the useForPlace property + * @param useForPlace The boolean value that the useForPlace property will be set to + */ + public void setUseForPlace(boolean useForPlace) { + this.useForPlace = useForPlace; + } + + /** + * Generic getter for the useForPlace property + * @return The useForPlace to be used by this bean + */ + public boolean getUseForPlace() { + return useForPlace; + } + /** * this method will retrieve the metadata values from the given item for all the metadata fields listed * in the fields property and it'll concatenate all those values together with the seperrator specified @@ -109,4 +130,5 @@ public class Concatenate implements VirtualBean { return result; } + } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 50b0f1b74b..28b6054471 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -48,6 +48,11 @@ public class Related implements VirtualBean { */ private VirtualBean virtualBean; + /** + * The boolean value indicating whether this field should be used for place or not + */ + private boolean useForPlace = false; + /** * Generic getter for the relationshipTypeString property of this class * @return The relationshipTypeString property @@ -96,6 +101,22 @@ public class Related implements VirtualBean { this.virtualBean = virtualBean; } + /** + * Generic setter for the useForPlace property + * @param useForPlace The boolean value that the useForPlace property will be set to + */ + public void setUseForPlace(boolean useForPlace) { + this.useForPlace = useForPlace; + } + + /** + * Generic getter for the useForPlace property + * @return The useForPlace to be used by this bean + */ + public boolean getUseForPlace() { + return useForPlace; + } + /** * This method will find the correct Relationship from the given item to retrieve the other item from it * and pass this along to the next VirtualBean that's stored in this class. @@ -140,4 +161,5 @@ public class Related implements VirtualBean { return null; } + } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java index b3f20f1054..10b720bb43 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java @@ -25,4 +25,16 @@ public interface VirtualBean { * @throws SQLException If something goes wrong */ String getValue(Context context, Item item) throws SQLException; + + /** + * Generic setter for the useForPlace property + * @param useForPlace The boolean value that the useForPlace property will be set to + */ + void setUseForPlace(boolean useForPlace); + + /** + * Generic getter for the useForPlace property + * @return The useForPlace to be used by this bean + */ + boolean getUseForPlace(); } diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 565a6a4f8d..44dcaecf6a 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -156,6 +156,7 @@ , +
From 01c1c0cddf89fc961a589884931b3784e0a76322 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 15 Nov 2018 12:50:01 +0100 Subject: [PATCH 022/188] [Task 57265] added the request search filters --- dspace/config/spring/api/discovery.xml | 54 ++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index ba57e659ea..fd095e40dd 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -117,6 +117,10 @@ + + + + @@ -230,6 +234,10 @@ + + + + @@ -392,6 +400,52 @@
+ + + + + relation.isAuthorOfPublication + + + + + + + + + + + relation.isProjectOfPublication + + + + + + + + + + + + relation.isOrgUnitOfPublication + + + + + + + + + + + relation.isPublicationOfJournalIssue + + + + + + + From 8e8bb65f75934783a02530bf9ad3743f64930cc5 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 15 Nov 2018 15:13:16 +0100 Subject: [PATCH 023/188] Removed a problematic context.close() --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 2 -- 1 file changed, 2 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 866e112545..5f97ee6a4f 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1334,8 +1334,6 @@ prevent the generation of resource policy entry values with null dspace_object a } } catch (SQLException e) { log.error(e, e); - } finally { - context.close(); } return fullMetadataValueList; } From 255de212719606130510d25f5fdf5e8b929e994c Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 16 Nov 2018 10:10:02 +0100 Subject: [PATCH 024/188] [Task 57187] added the relationship ID after the virtual:: in the metadata field authority --- .../content/DSpaceObjectServiceImpl.java | 4 +-- .../org/dspace/content/ItemServiceImpl.java | 35 +++++++++++-------- .../org/dspace/content/virtual/Related.java | 7 ++++ .../dspace/content/virtual/VirtualBean.java | 7 ++++ 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 014d32f44a..b0b3cea37f 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -239,7 +239,7 @@ public abstract class DSpaceObjectServiceImpl implements for (int i = 0; i < values.size(); i++) { if (authorities != null && authorities.size() >= i) { - if (StringUtils.equals(authorities.get(i), "virtual")) { + if (StringUtils.startsWith(authorities.get(i), "virtual::")) { continue; } } @@ -549,7 +549,7 @@ public abstract class DSpaceObjectServiceImpl implements List metadataValues = dso.getMetadata(); for (MetadataValue metadataValue : metadataValues) { //Retrieve & store the place for each metadata value - if (!StringUtils.equals(metadataValue.getAuthority(), "virtual")) { + if (!StringUtils.startsWith(metadataValue.getAuthority(), "virtual::")) { int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); metadataValue.setPlace(mvPlace); } 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 5f97ee6a4f..46ea8dc7c9 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -20,7 +20,7 @@ import java.util.Map; import java.util.UUID; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.util.AuthorizeUtil; import org.dspace.authorize.AuthorizeConfiguration; @@ -40,7 +40,6 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.content.virtual.Concatenate; import org.dspace.content.virtual.VirtualBean; import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; @@ -1188,7 +1187,7 @@ prevent the generation of resource policy entry values with null dspace_object a @Override public int countAllItems(Context context, Collection collection) throws SQLException { return itemDAO.countItems(context, collection, true, false) + itemDAO.countItems(context, collection, - false, true); + false, true); } @Override @@ -1207,7 +1206,7 @@ prevent the generation of resource policy entry values with null dspace_object a // Now, lets count unique items across that list of collections return itemDAO.countItems(context, collections, true, false) + itemDAO.countItems(context, collections, - false, true); + false, true); } @Override @@ -1318,6 +1317,7 @@ prevent the generation of resource policy entry values with null dspace_object a } } + @Override public List getRelationshipMetadata(Item item, boolean extra) { Context context = new Context(); @@ -1328,7 +1328,8 @@ prevent the generation of resource policy entry values with null dspace_object a if (StringUtils.isNotBlank(entityType)) { List relationships = relationshipService.findByItem(context, item); for (Relationship relationship : relationships) { - fullMetadataValueList.addAll(handleItemRelationship(context, item, entityType, relationship, extra)); + fullMetadataValueList + .addAll(handleItemRelationship(context, item, entityType, relationship, extra)); } } @@ -1359,23 +1360,26 @@ prevent the generation of resource policy entry values with null dspace_object a if (hashMaps != null && extra) { resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(context, item, hashMaps, - otherItem, relationName)); + otherItem, relationName, + relationship.getID())); } - resultingMetadataValueList.add(getRelationMetadataFromOtherItem(otherItem, relationName)); + resultingMetadataValueList.add(getRelationMetadataFromOtherItem(otherItem, relationName, relationship.getID())); return resultingMetadataValueList; } private List handleRelationshipTypeMetadataMappping(Context context, Item item, HashMap hashMaps, Item otherItem, - String relationName) throws SQLException { + String relationName, Integer relationshipId) + throws SQLException { List resultingMetadataValueList = new LinkedList<>(); for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); VirtualBean virtualBean = entry.getValue(); MetadataValue metadataValue = constructMetadataValue(key); - metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue); + metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue, + relationshipId); if (StringUtils.isNotBlank(metadataValue.getValue())) { resultingMetadataValueList.add(metadataValue); } @@ -1383,9 +1387,10 @@ prevent the generation of resource policy entry values with null dspace_object a return resultingMetadataValueList; } - private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName) { + private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName, + Integer relationshipId) { MetadataValue metadataValue = constructMetadataValue("relation." + relationName); - metadataValue.setAuthority("virtual"); + metadataValue.setAuthority("virtual::" + relationshipId); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; } @@ -1404,10 +1409,12 @@ prevent the generation of resource policy entry values with null dspace_object a return entityType; } - private MetadataValue constructResultingMetadataValue(Context context, Item item, Item otherItem, VirtualBean virtualBean, - MetadataValue metadataValue) throws SQLException { + private MetadataValue constructResultingMetadataValue(Context context, Item item, Item otherItem, + VirtualBean virtualBean, + MetadataValue metadataValue, Integer relationshipId) + throws SQLException { metadataValue.setValue(virtualBean.getValue(context, otherItem)); - metadataValue.setAuthority("virtual"); + metadataValue.setAuthority("virtual::" + relationshipId); metadataValue.setConfidence(-1); metadataValue.setDSpaceObject(item); return metadataValue; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 28b6054471..8388ac2185 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.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.content.virtual; import java.sql.SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java index 10b720bb43..a57ee81fac 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.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.content.virtual; import java.sql.SQLException; From a755f296bf474ce49f16802a7c3cbbf6116f4d79 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 16 Nov 2018 11:14:28 +0100 Subject: [PATCH 025/188] Added relation.isJournalOfPublication metadata field on the publication with config and addition of a new uuidvalue bean --- .../org/dspace/content/virtual/UUIDValue.java | 23 +++++++++++++++++++ dspace/config/spring/api/core-services.xml | 14 +++++++++++ 2 files changed, 37 insertions(+) create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java new file mode 100644 index 0000000000..4e512d3dfb --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java @@ -0,0 +1,23 @@ +package org.dspace.content.virtual; + +import java.sql.SQLException; + +import org.dspace.content.Item; +import org.dspace.core.Context; + +public class UUIDValue implements VirtualBean { + + private boolean useForPlace; + + public void setUseForPlace(boolean useForPlace) { + this.useForPlace = useForPlace; + } + + public boolean getUseForPlace() { + return useForPlace; + } + + public String getValue(Context context, Item item) throws SQLException { + return String.valueOf(item.getID()); + } +} diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 44dcaecf6a..f878bbb898 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -280,6 +280,7 @@ + @@ -287,5 +288,18 @@ + + + + + + + + + + + + + From 3a972ba5b97f8d95a27896c9f888affc36255ad4 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 16 Nov 2018 15:17:23 +0100 Subject: [PATCH 026/188] Added config for virtual metadata fields on the journalIssue and Publication item pages --- dspace/config/spring/api/core-services.xml | 32 +++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index f878bbb898..23a588b55c 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -219,6 +219,7 @@ + @@ -236,6 +237,12 @@ + + + + + + @@ -280,15 +287,38 @@ + + - + + + + journalvolume.identifier.name + + + + , + + + + + + + + + + + + + + From ad7bd23038cb8ccb889ba4f86c184530144cc350 Mon Sep 17 00:00:00 2001 From: benbosman Date: Fri, 16 Nov 2018 17:39:36 +0100 Subject: [PATCH 027/188] Additional search filter --- dspace/config/spring/api/discovery.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index fd095e40dd..290ae584d0 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -121,6 +121,7 @@ + @@ -238,6 +239,7 @@ + @@ -445,6 +447,16 @@ + + + + + relation.isJournalOfPublication + + + + + From 0ba6d75a3081868d9f2cec5c6d20f2c80c6d1160 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 19 Nov 2018 16:14:51 +0100 Subject: [PATCH 028/188] Constructed a RelationshipMetadataValue object and refactored the getRelationshipMetadata methods in the ItemServiceImpl to use this object instead of it's parent MetadataValue --- .../org/dspace/content/ItemServiceImpl.java | 47 ++++++++++--------- .../content/RelationshipMetadataValue.java | 14 ++++++ .../dspace/content/service/ItemService.java | 3 +- 3 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java 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 46ea8dc7c9..fe96d6539f 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1294,7 +1294,7 @@ prevent the generation of resource policy entry values with null dspace_object a public List getMetadata(Item item, String schema, String element, String qualifier, String lang) { if (StringUtils.equals(schema, "relation") && !StringUtils.equals(element, "type")) { - List relationMetadata = getRelationshipMetadata(item, false); + List relationMetadata = getRelationshipMetadata(item, false); List listToReturn = new LinkedList<>(); for (MetadataValue metadataValue : relationMetadata) { if (StringUtils.equals(metadataValue.getMetadataField().getElement(), element)) { @@ -1310,7 +1310,8 @@ prevent the generation of resource policy entry values with null dspace_object a StringUtils.equals(qualifier, "*") && StringUtils.equals(lang, "*"))) { return dbMetadataValues; } - List fullMetadataValueList = getRelationshipMetadata(item, true); + List fullMetadataValueList = new LinkedList<>(); + fullMetadataValueList.addAll(getRelationshipMetadata(item, true)); fullMetadataValueList.addAll(dbMetadataValues); return fullMetadataValueList; @@ -1319,9 +1320,9 @@ prevent the generation of resource policy entry values with null dspace_object a } @Override - public List getRelationshipMetadata(Item item, boolean extra) { + public List getRelationshipMetadata(Item item, boolean extra) { Context context = new Context(); - List fullMetadataValueList = new LinkedList<>(); + List fullMetadataValueList = new LinkedList<>(); try { List list = item.getMetadata(); String entityType = getEntityTypeStringFromMetadata(list); @@ -1339,9 +1340,10 @@ prevent the generation of resource policy entry values with null dspace_object a return fullMetadataValueList; } - private List handleItemRelationship(Context context, Item item, String entityType, - Relationship relationship, boolean extra) throws SQLException { - List resultingMetadataValueList = new LinkedList<>(); + private List handleItemRelationship(Context context, Item item, String entityType, + Relationship relationship, boolean extra) + throws SQLException { + List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); HashMap hashMaps = new HashMap<>(); String relationName = ""; @@ -1367,19 +1369,21 @@ prevent the generation of resource policy entry values with null dspace_object a return resultingMetadataValueList; } - private List handleRelationshipTypeMetadataMappping(Context context, Item item, - HashMap hashMaps, - Item otherItem, - String relationName, Integer relationshipId) + private List handleRelationshipTypeMetadataMappping(Context context, Item item, + HashMap hashMaps, + Item otherItem, + String relationName, + Integer relationshipId) throws SQLException { - List resultingMetadataValueList = new LinkedList<>(); + List resultingMetadataValueList = new LinkedList<>(); for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); VirtualBean virtualBean = entry.getValue(); - MetadataValue metadataValue = constructMetadataValue(key); + RelationshipMetadataValue metadataValue = constructMetadataValue(key); metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue, relationshipId); + metadataValue.setUseForPlace(virtualBean.getUseForPlace()); if (StringUtils.isNotBlank(metadataValue.getValue())) { resultingMetadataValueList.add(metadataValue); } @@ -1387,9 +1391,9 @@ prevent the generation of resource policy entry values with null dspace_object a return resultingMetadataValueList; } - private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName, - Integer relationshipId) { - MetadataValue metadataValue = constructMetadataValue("relation." + relationName); + private RelationshipMetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName, + Integer relationshipId) { + RelationshipMetadataValue metadataValue = constructMetadataValue("relation." + relationName); metadataValue.setAuthority("virtual::" + relationshipId); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; @@ -1409,9 +1413,10 @@ prevent the generation of resource policy entry values with null dspace_object a return entityType; } - private MetadataValue constructResultingMetadataValue(Context context, Item item, Item otherItem, - VirtualBean virtualBean, - MetadataValue metadataValue, Integer relationshipId) + private RelationshipMetadataValue constructResultingMetadataValue(Context context, Item item, Item otherItem, + VirtualBean virtualBean, + RelationshipMetadataValue metadataValue, + Integer relationshipId) throws SQLException { metadataValue.setValue(virtualBean.getValue(context, otherItem)); metadataValue.setAuthority("virtual::" + relationshipId); @@ -1420,9 +1425,9 @@ prevent the generation of resource policy entry values with null dspace_object a return metadataValue; } - private MetadataValue constructMetadataValue(String key) { + private RelationshipMetadataValue constructMetadataValue(String key) { String[] splittedKey = key.split("\\."); - MetadataValue metadataValue = new MetadataValue(); + RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); MetadataField metadataField = new MetadataField(); MetadataSchema metadataSchema = new MetadataSchema(); metadataSchema.setName(splittedKey.length > 0 ? splittedKey[0] : null); diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java new file mode 100644 index 0000000000..5c8daa0929 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -0,0 +1,14 @@ +package org.dspace.content; + +public class RelationshipMetadataValue extends MetadataValue { + + private boolean useForPlace; + + public boolean isUseForPlace() { + return useForPlace; + } + + public void setUseForPlace(boolean useForPlace) { + this.useForPlace = useForPlace; + } +} 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 e9aee14eaa..659d869f6f 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 @@ -24,6 +24,7 @@ import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataValue; +import org.dspace.content.RelationshipMetadataValue; import org.dspace.content.Thumbnail; import org.dspace.content.WorkspaceItem; import org.dspace.content.virtual.VirtualMetadataPopulator; @@ -648,6 +649,6 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * @param item The Item that will be processed through it's Relationships * @return The list of MetadataValue objects constructed through the Relationships */ - public List getRelationshipMetadata(Item item, boolean extra); + public List getRelationshipMetadata(Item item, boolean extra); } From cfeabe349c017b22a79d27d1cf1165b22bab24ae Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 20 Nov 2018 14:32:12 +0100 Subject: [PATCH 029/188] [Task 57188] added the logic for the advanced place column calculation. Enforced that all virtual metadata are valid metadatafields --- .../content/DSpaceObjectServiceImpl.java | 31 +++++- .../org/dspace/content/ItemServiceImpl.java | 44 +++++--- .../content/RelationshipMetadataValue.java | 18 +++ dspace/config/registries/person-types.xml | 7 ++ dspace/config/registries/project-types.xml | 14 +++ .../registries/relationship-formats.xml | 105 ++++++++++++++++++ dspace/config/spring/api/core-services.xml | 12 +- 7 files changed, 206 insertions(+), 25 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index b0b3cea37f..8e30936bfd 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -12,6 +12,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -25,8 +26,10 @@ import org.dspace.content.authority.Choices; import org.dspace.content.authority.service.ChoiceAuthorityService; import org.dspace.content.authority.service.MetadataAuthorityService; import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataValueService; +import org.dspace.content.service.RelationshipService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.handle.service.HandleService; @@ -60,6 +63,10 @@ public abstract class DSpaceObjectServiceImpl implements protected MetadataFieldService metadataFieldService; @Autowired(required = true) protected MetadataAuthorityService metadataAuthorityService; + @Autowired(required = true) + protected ItemService itemService; + @Autowired(required = true) + protected RelationshipService relationshipService; public DSpaceObjectServiceImpl() { @@ -546,10 +553,28 @@ public abstract class DSpaceObjectServiceImpl implements */ // A map created to store the latest place for each metadata field Map fieldToLastPlace = new HashMap<>(); - List metadataValues = dso.getMetadata(); + List metadataValues = new LinkedList<>(); + if (dso.getType() == Constants.ITEM) { + metadataValues = itemService.getMetadata((Item) dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + } else { + metadataValues = dso.getMetadata(); + } for (MetadataValue metadataValue : metadataValues) { //Retrieve & store the place for each metadata value - if (!StringUtils.startsWith(metadataValue.getAuthority(), "virtual::")) { + if (StringUtils.startsWith(metadataValue.getAuthority(), "virtual::") && ((RelationshipMetadataValue) metadataValue).isUseForPlace()) { + int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); + metadataValue.setPlace(mvPlace); + String authority = metadataValue.getAuthority(); + String relationshipId = StringUtils.split(authority, "::")[1]; + Relationship relationship = relationshipService.find(context, Integer.parseInt(relationshipId)); + if (relationship.getLeftItem() == (Item) dso) { + relationship.setLeftPlace(mvPlace); + } else { + relationship.setRightPlace(mvPlace); + } + relationshipService.update(context, relationship); + + } else if (!StringUtils.startsWith(metadataValue.getAuthority(), "virtual::")) { int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); metadataValue.setPlace(mvPlace); } @@ -569,7 +594,7 @@ public abstract class DSpaceObjectServiceImpl implements if (fieldToLastPlace.containsKey(metadataField)) { fieldToLastPlace.put(metadataField, fieldToLastPlace.get(metadataField) + 1); } else { - // The metadata value place starts at 0 + // The metadata value place starts at 0q fieldToLastPlace.put(metadataField, 0); } return fieldToLastPlace.get(metadataField); 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 fe96d6539f..093e88ee51 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1365,7 +1365,8 @@ prevent the generation of resource policy entry values with null dspace_object a otherItem, relationName, relationship.getID())); } - resultingMetadataValueList.add(getRelationMetadataFromOtherItem(otherItem, relationName, relationship.getID())); + resultingMetadataValueList + .add(getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID())); return resultingMetadataValueList; } @@ -1380,7 +1381,7 @@ prevent the generation of resource policy entry values with null dspace_object a String key = entry.getKey(); VirtualBean virtualBean = entry.getValue(); - RelationshipMetadataValue metadataValue = constructMetadataValue(key); + RelationshipMetadataValue metadataValue = constructMetadataValue(context, key); metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue, relationshipId); metadataValue.setUseForPlace(virtualBean.getUseForPlace()); @@ -1391,9 +1392,10 @@ prevent the generation of resource policy entry values with null dspace_object a return resultingMetadataValueList; } - private RelationshipMetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName, + private RelationshipMetadataValue getRelationMetadataFromOtherItem(Context context, Item otherItem, + String relationName, Integer relationshipId) { - RelationshipMetadataValue metadataValue = constructMetadataValue("relation." + relationName); + RelationshipMetadataValue metadataValue = constructMetadataValue(context, "relation." + relationName); metadataValue.setAuthority("virtual::" + relationshipId); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; @@ -1425,17 +1427,27 @@ prevent the generation of resource policy entry values with null dspace_object a return metadataValue; } - private RelationshipMetadataValue constructMetadataValue(String key) { - String[] splittedKey = key.split("\\."); - RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); - MetadataField metadataField = new MetadataField(); - MetadataSchema metadataSchema = new MetadataSchema(); - metadataSchema.setName(splittedKey.length > 0 ? splittedKey[0] : null); - metadataField.setMetadataSchema(metadataSchema); - metadataField.setElement(splittedKey.length > 1 ? splittedKey[1] : null); - metadataField.setQualifier(splittedKey.length > 2 ? splittedKey[2] : null); - metadataValue.setMetadataField(metadataField); - metadataValue.setLanguage(Item.ANY); - return metadataValue; + private RelationshipMetadataValue constructMetadataValue(Context context, String key) { + try { + String[] splittedKey = key.split("\\."); + RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); + String metadataSchema = splittedKey.length > 0 ? splittedKey[0] : null; + String metadataElement = splittedKey.length > 1 ? splittedKey[1] : null; + String metadataQualifier = splittedKey.length > 2 ? splittedKey[2] : null; + MetadataField metadataField = metadataFieldService + .findByElement(context, metadataSchema, metadataElement, metadataQualifier); + if (metadataField == null) { + log.error( + "A MetadataValue was attempted to construct with MetadataField for paremeters: metadataschema: " + + metadataSchema + ", metadataelement:" + metadataElement + ", metadataqualifier: " + metadataQualifier); + return null; + } + metadataValue.setMetadataField(metadataField); + metadataValue.setLanguage(Item.ANY); + return metadataValue; + } catch (SQLException e) { + log.error(e.getMessage(), e); + } + return null; } } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index 5c8daa0929..700b0fc21f 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -1,5 +1,7 @@ package org.dspace.content; +import org.hibernate.proxy.HibernateProxyHelper; + public class RelationshipMetadataValue extends MetadataValue { private boolean useForPlace; @@ -11,4 +13,20 @@ public class RelationshipMetadataValue extends MetadataValue { public void setUseForPlace(boolean useForPlace) { this.useForPlace = useForPlace; } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); + if (getClass() != objClass) { + return false; + } + final RelationshipMetadataValue other = (RelationshipMetadataValue) obj; + if (this.isUseForPlace() != other.isUseForPlace()) { + return false; + } + return super.equals(obj); + } } diff --git a/dspace/config/registries/person-types.xml b/dspace/config/registries/person-types.xml index 49e6880deb..63947ff366 100644 --- a/dspace/config/registries/person-types.xml +++ b/dspace/config/registries/person-types.xml @@ -58,4 +58,11 @@ jobtitle + + + person + contributor + other + + diff --git a/dspace/config/registries/project-types.xml b/dspace/config/registries/project-types.xml index 8ed1b84cf2..866bb85439 100644 --- a/dspace/config/registries/project-types.xml +++ b/dspace/config/registries/project-types.xml @@ -58,4 +58,18 @@ description + + + project + contributor + other + + + + + project + contributor + author + + diff --git a/dspace/config/registries/relationship-formats.xml b/dspace/config/registries/relationship-formats.xml index 00dd43d8a9..ddc8296ddb 100644 --- a/dspace/config/registries/relationship-formats.xml +++ b/dspace/config/registries/relationship-formats.xml @@ -9,6 +9,10 @@ http://dspace.org/relationship + + relation + http://dspace.org/relation + relationship @@ -16,4 +20,105 @@ Metadata field used for the type of entity, stored in the item + + relation + isAuthorOfPublication + + + + + relation + isPublicationOfAuthor + + + + relation + isProjectOfPublication + + + + relation + isPublicationOfProject + + + + relation + isOrgUnitOfPublication + + + + relation + isPublicationOfOrgUnit + + + + relation + isProjectOfPerson + + + + relation + isPersonOfProject + + + + relation + isOrgUnitOfPerson + + + + relation + isPersonOfOrgUnit + + + + relation + isOrgUnitOfProject + + + + relation + isProjectOfOrgUnit + + + + + + relation + isVolumeOfJournal + + + + relation + isJournalOfVolume + + + + relation + isIssueOfJournalVolume + + + + relation + isJournalVolumeOfIssue + + + + relation + isJournalOfPublication + + + + + relation + isJournalIssueOfPublication + + + + + + relation + isPublicationOfJournalIssue + + diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 23a588b55c..4cabc4dcfb 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -160,7 +160,7 @@ - + @@ -174,7 +174,7 @@ - + @@ -189,7 +189,7 @@ - + @@ -203,7 +203,7 @@ - + @@ -272,7 +272,7 @@ - + @@ -288,7 +288,7 @@ - + From b8d6fa2fba2ebd00be28033d89ede1d75726768d Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 20 Nov 2018 15:51:41 +0100 Subject: [PATCH 030/188] [Task 57442] Added the MetadataSchemaEnum with DC and RELATION, rewrote methods using relation String --- .../org/dspace/app/bulkedit/DSpaceCSV.java | 3 +- .../dspace/app/bulkedit/MetadataImport.java | 5 ++- .../dspace/content/MetadataSchemaEnum.java | 39 +++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java index 0bf17b8d9b..a14f57bf95 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java @@ -35,6 +35,7 @@ import org.dspace.content.Collection; 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.authority.Choices; import org.dspace.content.factory.ContentServiceFactory; @@ -199,7 +200,7 @@ public class DSpaceCSV implements Serializable { } // Check that the scheme exists - if (!StringUtils.equals(metadataSchema, "relation")) { + if (!StringUtils.equals(metadataSchema, MetadataSchemaEnum.RELATION.getName())) { MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema); if (foundSchema == null) { throw new MetadataImportInvalidHeadingException(clean[0], 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 b4cca2829c..67390a56a3 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 @@ -37,6 +37,7 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.Entity; import org.dspace.content.EntityType; import org.dspace.content.Item; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; @@ -356,7 +357,7 @@ public class MetadataImport { // Add the metadata to the item List relationships = new LinkedList<>(); for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) { - if (StringUtils.equals(dcv.getSchema(), "relation")) { + if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) { if (!StringUtils.equals(dcv.getElement(), "type")) { relationships.add(dcv); @@ -637,7 +638,7 @@ public class MetadataImport { } - if (StringUtils.equals(schema, "relation")) { + if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName())) { handleRelationMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences); } else { itemService.clearMetadata(c, item, schema, element, qualifier, language); diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java new file mode 100644 index 0000000000..cac4485ec9 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java @@ -0,0 +1,39 @@ +/** + * 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; + +/** + * This is an enum that holds track of a few special MetadataSchema types. + * It is important to note that this list is not exhaustive for the MetadataSchema + * types and different MetadataSchema can easily be made. + * These MetadataSchema objects are simply required. + */ +public enum MetadataSchemaEnum { + DC("dc"), RELATION("relation"); + + /** + * The String representation of the MetadataSchemaEnum + */ + private String name; + + /** + * Default constructor with the name parameter + * @param name The name parameter + */ + MetadataSchemaEnum(String name) { + this.name = name; + } + + /** + * Generic getter for the String representation of the enum object + * @return The name of the enum object + */ + public String getName() { + return name; + } +} From b905f69d63b4c1bb52c91d1c13cd13d07f09274c Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 21 Nov 2018 09:35:11 +0100 Subject: [PATCH 031/188] Refactored the usages of MetadataSchema.DC to use the enum instead --- .../dspace/administer/MetadataImporter.java | 3 +- .../app/itemexport/ItemExportServiceImpl.java | 4 +-- .../app/itemimport/ItemImportServiceImpl.java | 3 +- .../app/itemupdate/MetadataUtilities.java | 3 +- .../app/statistics/ReportGenerator.java | 7 +++-- .../java/org/dspace/app/util/DCInput.java | 4 +-- .../org/dspace/app/util/DCInputsReader.java | 6 ++-- .../java/org/dspace/content/Bitstream.java | 20 ++++++++----- .../dspace/content/BitstreamServiceImpl.java | 4 +-- .../main/java/org/dspace/content/Bundle.java | 5 ++-- .../java/org/dspace/content/Collection.java | 2 +- .../dspace/content/CollectionServiceImpl.java | 10 ++++--- .../java/org/dspace/content/Community.java | 2 +- .../dspace/content/CommunityServiceImpl.java | 15 ++++++---- .../content/DSpaceObjectServiceImpl.java | 20 ++++++------- .../content/InstallItemServiceImpl.java | 25 +++++++++------- .../main/java/org/dspace/content/Item.java | 2 +- .../org/dspace/content/ItemComparator.java | 2 +- .../org/dspace/content/ItemServiceImpl.java | 8 ++--- .../org/dspace/content/MetadataSchema.java | 4 --- .../crosswalk/OAIDCIngestionCrosswalk.java | 5 ++-- .../crosswalk/OREDisseminationCrosswalk.java | 9 +++--- .../content/crosswalk/QDCCrosswalk.java | 3 +- .../SimpleDCDisseminationCrosswalk.java | 4 +-- .../dspace/content/packager/PDFPackager.java | 21 ++++++++----- .../dspace/content/packager/PackageUtils.java | 4 +-- .../dspace/embargo/EmbargoServiceImpl.java | 6 ++-- .../org/dspace/eperson/SubscribeCLITool.java | 4 +-- .../identifier/HandleIdentifierProvider.java | 7 +++-- .../VersionedHandleIdentifierProvider.java | 9 +++--- ...dentifierProviderWithCanonicalHandles.java | 9 +++--- .../conversion/MetadataConverterPlugin.java | 3 +- .../BasicWorkflowServiceImpl.java | 14 ++++----- .../xmlworkflow/XmlWorkflowServiceImpl.java | 10 ++++--- .../AcceptEditRejectAction.java | 4 +-- .../processingaction/FinalEditAction.java | 4 +-- .../processingaction/ReviewAction.java | 4 +-- .../ScoreEvaluationAction.java | 6 ++-- .../SingleUserReviewAction.java | 4 +-- .../org/dspace/content/CollectionTest.java | 12 ++++---- .../org/dspace/content/CommunityTest.java | 30 +++++++++++-------- .../java/org/dspace/content/ItemTest.java | 8 ++--- .../org/dspace/content/MetadataFieldTest.java | 19 ++++++------ .../dspace/content/MetadataSchemaTest.java | 4 +-- .../org/dspace/content/MetadataValueTest.java | 2 +- .../dspace/content/packager/ITDSpaceAIP.java | 24 ++++++++------- .../content/packager/PackageUtilsTest.java | 7 +++-- .../app/rest/builder/CollectionBuilder.java | 4 +-- .../app/rest/builder/CommunityBuilder.java | 4 +-- .../dspace/app/rest/builder/ItemBuilder.java | 11 +++---- .../rest/builder/WorkspaceItemBuilder.java | 10 +++---- 51 files changed, 229 insertions(+), 185 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java b/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java index ac547f1839..aee48f71e8 100644 --- a/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java +++ b/dspace-api/src/main/java/org/dspace/administer/MetadataImporter.java @@ -21,6 +21,7 @@ import org.apache.xpath.XPathAPI; import org.dspace.authorize.AuthorizeException; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.NonUniqueMetadataException; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.MetadataFieldService; @@ -248,7 +249,7 @@ public class MetadataImporter { // If the schema is not provided default to DC if (schema == null) { - schema = MetadataSchema.DC_SCHEMA; + schema = MetadataSchemaEnum.DC.getName(); } diff --git a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java index 170aa0c620..8f08600042 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/itemexport/ItemExportServiceImpl.java @@ -42,7 +42,7 @@ import org.dspace.content.Community; import org.dspace.content.DSpaceObject; 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.service.BitstreamService; import org.dspace.content.service.CommunityService; @@ -214,7 +214,7 @@ public class ItemExportServiceImpl implements ItemExportService { protected void writeMetadata(Context c, String schema, Item i, File destDir, boolean migrate) throws Exception { String filename; - if (schema.equals(MetadataSchema.DC_SCHEMA)) { + if (schema.equals(MetadataSchemaEnum.DC.getName())) { filename = "dublin_core.xml"; } else { filename = "metadata_" + schema + ".xml"; 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 829594f448..1e209f030c 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 @@ -74,6 +74,7 @@ import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamService; @@ -677,7 +678,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea Node schemaAttr = metadata.item(0).getAttributes().getNamedItem( "schema"); if (schemaAttr == null) { - schema = MetadataSchema.DC_SCHEMA; + schema = MetadataSchemaEnum.DC.getName(); } else { schema = schemaAttr.getNodeValue(); } diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java index 82ed5f75a0..362c14d782 100644 --- a/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java +++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/MetadataUtilities.java @@ -34,6 +34,7 @@ import org.dspace.authorize.AuthorizeException; 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.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -189,7 +190,7 @@ public class MetadataUtilities { NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core"); Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema"); if (schemaAttr == null) { - schema = MetadataSchema.DC_SCHEMA; + schema = MetadataSchemaEnum.DC.getName(); } else { schema = schemaAttr.getNodeValue(); } diff --git a/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java b/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java index 8c38cc842d..7e9b438547 100644 --- a/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java +++ b/dspace-api/src/main/java/org/dspace/app/statistics/ReportGenerator.java @@ -28,7 +28,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -763,9 +763,10 @@ public class ReportGenerator { // build the referece // FIXME: here we have blurred the line between content and presentation // and it should probably be un-blurred - List title = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + List title = itemService.getMetadata(item, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY); List author = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "contributor", "author", Item.ANY); StringBuffer authors = new StringBuffer(); if (author.size() > 0) { diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInput.java b/dspace-api/src/main/java/org/dspace/app/util/DCInput.java index 5564b66806..4e884ea112 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInput.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInput.java @@ -14,7 +14,7 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import org.apache.commons.lang.StringUtils; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -160,7 +160,7 @@ public class DCInput { // Default the schema to dublin core dcSchema = fieldMap.get("dc-schema"); if (dcSchema == null) { - dcSchema = MetadataSchema.DC_SCHEMA; + dcSchema = MetadataSchemaEnum.DC.getName(); } //check if the input have a language tag diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java index b473e602b8..736458116e 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java @@ -21,7 +21,7 @@ import javax.xml.parsers.FactoryConfigurationError; import org.apache.commons.lang3.StringUtils; import org.dspace.content.Collection; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Utils; import org.dspace.services.factory.DSpaceServicesFactory; import org.w3c.dom.Document; @@ -464,7 +464,7 @@ public class DCInputsReader { String elem = field.get("dc-element"); String qual = field.get("dc-qualifier"); if ((schema == null) || (schema.equals(""))) { - schema = MetadataSchema.DC_SCHEMA; + schema = MetadataSchemaEnum.DC.getName(); } String schemaTest; @@ -474,7 +474,7 @@ public class DCInputsReader { Map fld = pg.get(j); if ((fld.get("dc-schema") == null) || ((fld.get("dc-schema")).equals(""))) { - schemaTest = MetadataSchema.DC_SCHEMA; + schemaTest = MetadataSchemaEnum.DC.getName(); } else { schemaTest = fld.get("dc-schema"); } diff --git a/dspace-api/src/main/java/org/dspace/content/Bitstream.java b/dspace-api/src/main/java/org/dspace/content/Bitstream.java index 3be9b1feb1..cc4ecd139e 100644 --- a/dspace-api/src/main/java/org/dspace/content/Bitstream.java +++ b/dspace-api/src/main/java/org/dspace/content/Bitstream.java @@ -122,7 +122,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport */ @Override public String getName() { - return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY); } /** @@ -133,7 +134,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @throws SQLException if database error */ public void setName(Context context, String n) throws SQLException { - getBitstreamService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "title", null, null, n); + getBitstreamService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(), + "title", null, null, n); } /** @@ -144,7 +146,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @return the source of the bitstream */ public String getSource() { - return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "source", null, Item.ANY); + return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), + "source", null, Item.ANY); } /** @@ -155,7 +158,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @throws SQLException if database error */ public void setSource(Context context, String n) throws SQLException { - getBitstreamService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "source", null, null, n); + getBitstreamService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(), + "source", null, null, n); } /** @@ -166,7 +170,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport */ public String getDescription() { return getBitstreamService() - .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "description", null, Item.ANY); + .getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "description", + null, Item.ANY); } /** @@ -178,7 +183,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport */ public void setDescription(Context context, String n) throws SQLException { getBitstreamService() - .setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "description", null, null, n); + .setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(), "description", null, null, n); } /** @@ -227,7 +232,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport * @return the user's format description. */ public String getUserFormatDescription() { - return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY); + return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), + "format", null, Item.ANY); } protected BitstreamFormat getBitstreamFormat() { diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java index e5e7cc57e4..461f5078b3 100644 --- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java @@ -203,7 +203,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp @Override public void setUserFormatDescription(Context context, Bitstream bitstream, String desc) throws SQLException { setFormat(context, bitstream, null); - setMetadataSingleValue(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, null, desc); + setMetadataSingleValue(context, bitstream, MetadataSchemaEnum.DC.getName(), "format", null, null, desc); } @Override @@ -233,7 +233,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl imp } // Remove user type description - clearMetadata(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY); + clearMetadata(context, bitstream, MetadataSchemaEnum.DC.getName(), "format", null, Item.ANY); // Update the ID in the table row bitstream.setFormat(bitstreamFormat); diff --git a/dspace-api/src/main/java/org/dspace/content/Bundle.java b/dspace-api/src/main/java/org/dspace/content/Bundle.java index 5fe7100d4f..88f21c2c2f 100644 --- a/dspace-api/src/main/java/org/dspace/content/Bundle.java +++ b/dspace-api/src/main/java/org/dspace/content/Bundle.java @@ -88,7 +88,7 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport { */ @Override public String getName() { - return getBundleService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + return getBundleService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); } /** @@ -100,7 +100,8 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport { * @throws SQLException if database error */ public void setName(Context context, String name) throws SQLException { - getBundleService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "title", null, null, name); + getBundleService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(), + "title", null, null, name); } /** 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 249c5a19a2..e8431dca1c 100644 --- a/dspace-api/src/main/java/org/dspace/content/Collection.java +++ b/dspace-api/src/main/java/org/dspace/content/Collection.java @@ -134,7 +134,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor @Override public String getName() { String value = getCollectionService() - .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + .getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); return value == null ? "" : value; } 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 bd7034856f..31abfffa48 100644 --- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java @@ -143,10 +143,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findAll(Context context) throws SQLException { - MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); + MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + "title", null); if (nameField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!"); } return collectionDAO.findAll(context, nameField); @@ -154,10 +155,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i @Override public List findAll(Context context, Integer limit, Integer offset) throws SQLException { - MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); + MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + "title", null); if (nameField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!"); } return collectionDAO.findAll(context, nameField, limit, offset); 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 448e86e039..5bcf623b61 100644 --- a/dspace-api/src/main/java/org/dspace/content/Community.java +++ b/dspace-api/src/main/java/org/dspace/content/Community.java @@ -254,7 +254,7 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport @Override public String getName() { String value = getCommunityService() - .getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + .getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); return value == null ? "" : value; } 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 667b0268b1..996f79479b 100644 --- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java @@ -139,10 +139,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public List findAll(Context context) throws SQLException { - MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); + MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + "title", null); if (sortField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!"); } return communityDAO.findAll(context, sortField); @@ -150,10 +151,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public List findAll(Context context, Integer limit, Integer offset) throws SQLException { - MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); + MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + "title", null); if (nameField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!"); } return communityDAO.findAll(context, nameField, limit, offset); @@ -162,10 +164,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp @Override public List findAllTop(Context context) throws SQLException { // get all communities that are not children - MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null); + MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + "title", null); if (sortField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!"); } return communityDAO.findAllNoParent(context, sortField); diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 014d32f44a..b50d513ba4 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -67,7 +67,7 @@ public abstract class DSpaceObjectServiceImpl implements @Override public String getName(T dso) { - String value = getMetadataFirstValue(dso, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + String value = getMetadataFirstValue(dso, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); return value == null ? "" : value; } @@ -578,23 +578,23 @@ public abstract class DSpaceObjectServiceImpl implements protected String[] getMDValueByLegacyField(String field) { switch (field) { case "introductory_text": - return new String[] {MetadataSchema.DC_SCHEMA, "description", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "description", null}; case "short_description": - return new String[] {MetadataSchema.DC_SCHEMA, "description", "abstract"}; + return new String[] {MetadataSchemaEnum.DC.getName(), "description", "abstract"}; case "side_bar_text": - return new String[] {MetadataSchema.DC_SCHEMA, "description", "tableofcontents"}; + return new String[] {MetadataSchemaEnum.DC.getName(), "description", "tableofcontents"}; case "copyright_text": - return new String[] {MetadataSchema.DC_SCHEMA, "rights", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "rights", null}; case "name": - return new String[] {MetadataSchema.DC_SCHEMA, "title", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "title", null}; case "provenance_description": - return new String[] {MetadataSchema.DC_SCHEMA, "provenance", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "provenance", null}; case "license": - return new String[] {MetadataSchema.DC_SCHEMA, "rights", "license"}; + return new String[] {MetadataSchemaEnum.DC.getName(), "rights", "license"}; case "user_format_description": - return new String[] {MetadataSchema.DC_SCHEMA, "format", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "format", null}; case "source": - return new String[] {MetadataSchema.DC_SCHEMA, "source", null}; + return new String[] {MetadataSchemaEnum.DC.getName(), "source", null}; case "firstname": return new String[] {"eperson", "firstname", null}; case "lastname": diff --git a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java index 59298e4c31..11cd4c107c 100644 --- a/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/InstallItemServiceImpl.java @@ -104,9 +104,10 @@ public class InstallItemServiceImpl implements InstallItemService { // If the item doesn't have a date.accessioned, set it to today List dateAccessioned = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "accessioned", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "accessioned", Item.ANY); if (dateAccessioned.isEmpty()) { - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString()); + itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(), + "date", "accessioned", null, now.toString()); } // If issue date is set as "today" (literal string), then set it to current date @@ -114,8 +115,8 @@ public class InstallItemServiceImpl implements InstallItemService { // replacing "today" with today's date. // NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default List currentDateIssued = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY); + itemService.clearMetadata(c, item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY); for (MetadataValue dcv : currentDateIssued) { if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) { DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1); @@ -127,7 +128,8 @@ public class InstallItemServiceImpl implements InstallItemService { // Record that the item was restored String provDescription = "Restored into DSpace on " + now + " (GMT)."; - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); return finishItem(c, item, is); } @@ -137,14 +139,16 @@ public class InstallItemServiceImpl implements InstallItemService { throws SQLException, AuthorizeException { // create accession date DCDate now = DCDate.getCurrent(); - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString()); + itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(), + "date", "accessioned", null, now.toString()); // add date available if not under embargo, otherwise it will // be set when the embargo is lifted. // this will flush out fatal embargo metadata // problems before we set inArchive. if (embargoService.getEmbargoTermsAsDate(c, item) == null) { - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "available", null, now.toString()); + itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(), + "date", "available", null, now.toString()); } // If issue date is set as "today" (literal string), then set it to current date @@ -152,8 +156,8 @@ public class InstallItemServiceImpl implements InstallItemService { // replacing "today" with today's date. // NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default List currentDateIssued = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); - itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY); + itemService.clearMetadata(c, item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY); for (MetadataValue dcv : currentDateIssued) { if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) { DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1); @@ -178,7 +182,8 @@ public class InstallItemServiceImpl implements InstallItemService { } // Add provenance description - itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); } /** diff --git a/dspace-api/src/main/java/org/dspace/content/Item.java b/dspace-api/src/main/java/org/dspace/content/Item.java index cfe86147f8..fdcffcb4c1 100644 --- a/dspace-api/src/main/java/org/dspace/content/Item.java +++ b/dspace-api/src/main/java/org/dspace/content/Item.java @@ -352,7 +352,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport { @Override public String getName() { - return getItemService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + return getItemService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/ItemComparator.java b/dspace-api/src/main/java/org/dspace/content/ItemComparator.java index 27e869d40b..5598550067 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemComparator.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemComparator.java @@ -174,7 +174,7 @@ public class ItemComparator implements Comparator, Serializable { protected String getValue(Item item) { // The overall array and each element are guaranteed non-null List dcvalues = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, element, qualifier, language); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), element, qualifier, language); if (dcvalues.isEmpty()) { return null; 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 9bed048031..eb1a84329b 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -229,10 +229,10 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It throws SQLException { MetadataField metadataField = metadataFieldService - .findByElement(context, MetadataSchema.DC_SCHEMA, "date", "accessioned"); + .findByElement(context, MetadataSchemaEnum.DC.getName(), "date", "accessioned"); if (metadataField == null) { throw new IllegalArgumentException( - "Required metadata field '" + MetadataSchema.DC_SCHEMA + ".date.accessioned' doesn't exist!"); + "Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".date.accessioned' doesn't exist!"); } return itemDAO.findBySubmitter(context, eperson, metadataField, limit); @@ -553,7 +553,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It prov.append(installItemService.getBitstreamProvenanceMessage(context, item)); - addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", prov.toString()); + addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", prov.toString()); // Update item in DB update(context, item); @@ -608,7 +608,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It // bitstream checksums prov.append(installItemService.getBitstreamProvenanceMessage(context, item)); - addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", prov.toString()); + addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", prov.toString()); // Update item in DB update(context, item); diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java index 511cda3f7b..96bef0fa2c 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchema.java @@ -39,10 +39,6 @@ import org.hibernate.proxy.HibernateProxyHelper; @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Table(name = "metadataschemaregistry") public class MetadataSchema implements ReloadableEntity { - /** - * Short Name of built-in Dublin Core schema. - */ - public static final String DC_SCHEMA = "dc"; @Id @Column(name = "metadata_schema_id") diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java index 98b4df7d8c..10bd5ce6fa 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/OAIDCIngestionCrosswalk.java @@ -15,7 +15,7 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.MetadataField; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; import org.dspace.core.Constants; @@ -67,7 +67,8 @@ public class OAIDCIngestionCrosswalk lang = element.getAttributeValue("lang"); } MetadataField metadataField = metadataValidator - .checkMetadata(context, MetadataSchema.DC_SCHEMA, element.getName(), null, createMissingMetadataFields); + .checkMetadata(context, MetadataSchemaEnum.DC.getName(), + element.getName(), null, createMissingMetadataFields); itemService.addMetadata(context, item, metadataField, lang, element.getText()); } diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java index aad95da99a..3508f6793d 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/OREDisseminationCrosswalk.java @@ -22,7 +22,7 @@ import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -122,7 +122,7 @@ public class OREDisseminationCrosswalk Element aggLink; List uris = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); for (MetadataValue uri : uris) { aggLink = new Element("link", ATOM_NS); aggLink.setAttribute("rel", "alternate"); @@ -159,7 +159,8 @@ public class OREDisseminationCrosswalk // Information about the aggregation (item) itself Element aggTitle = new Element("title", ATOM_NS); - List titles = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + List titles = itemService.getMetadata(item, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY); if (titles != null && titles.size() > 0) { aggTitle.addContent(titles.get(0).getValue()); } else { @@ -170,7 +171,7 @@ public class OREDisseminationCrosswalk Element aggAuthor; Element aggAuthorName; List authors = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "contributor", "author", Item.ANY); for (MetadataValue author : authors) { aggAuthor = new Element("author", ATOM_NS); aggAuthorName = new Element("name", ATOM_NS); diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java index a20699bf1a..9a3035a279 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/QDCCrosswalk.java @@ -26,6 +26,7 @@ import org.dspace.content.DSpaceObject; 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.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -353,7 +354,7 @@ public class QDCCrosswalk extends SelfNamedPlugin // only complain about missing elements in the DC schema: if (elt == null) { - if (metadataField.getMetadataSchema().getName().equals(MetadataSchema.DC_SCHEMA)) { + if (metadataField.getMetadataSchema().getName().equals(MetadataSchemaEnum.DC.getName())) { log.warn("WARNING: " + myName + ": No QDC mapping for \"" + qdc + "\""); } } else { diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java index 789fa9d6fb..b7c43bf37a 100644 --- a/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java +++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/SimpleDCDisseminationCrosswalk.java @@ -17,7 +17,7 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; 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.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -101,7 +101,7 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin Item item = (Item) dso; List allDC = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), Item.ANY, Item.ANY, Item.ANY); List dcl = new ArrayList(allDC.size()); diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java b/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java index 0b26cc867b..868d6f63bf 100644 --- a/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java +++ b/dspace-api/src/main/java/org/dspace/content/packager/PDFPackager.java @@ -33,7 +33,7 @@ import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.MetadataValidationException; @@ -377,10 +377,11 @@ public class PDFPackager if (log.isDebugEnabled()) { log.debug("PDF Info dict title=\"" + title + "\""); } - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "title", null, "en", title); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "title", null, "en", title); String value = docinfo.getAuthor(); if (value != null) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "contributor", "author", null, value); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "contributor", "author", null, value); if (log.isDebugEnabled()) { log.debug("PDF Info dict author=\"" + value + "\""); } @@ -388,25 +389,29 @@ public class PDFPackager value = docinfo.getCreator(); if (value != null) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", "Application that created the original document: " + value); } value = docinfo.getProducer(); if (value != null) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", "Original document converted to PDF by: " + value); } value = docinfo.getSubject(); if (value != null) { itemService - .addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "abstract", null, value); + .addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "description", "abstract", null, value); } value = docinfo.getKeywords(); if (value != null) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "subject", "other", null, value); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "subject", "other", null, value); } // Take either CreationDate or ModDate as "date.created", @@ -417,7 +422,7 @@ public class PDFPackager } if (calValue != null) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "created", null, + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "date", "created", null, (new DCDate(calValue.getTime())).toString()); } itemService.update(context, item); 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 045f7963d0..eab36aefed 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 @@ -30,7 +30,7 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.WorkspaceItem; import org.dspace.content.factory.ContentServiceFactory; @@ -158,7 +158,7 @@ public class PackageUtils { */ public static void checkItemMetadata(Item item) throws PackageValidationException { - List t = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + List t = itemService.getMetadata(item, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); if (t == null || t.size() == 0) { throw new PackageValidationException("Item cannot be created without the required \"title\" DC metadata."); } diff --git a/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java b/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java index 68efce46e1..d76ad8be0e 100644 --- a/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/embargo/EmbargoServiceImpl.java @@ -17,7 +17,7 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.Context; @@ -153,8 +153,8 @@ public class EmbargoServiceImpl implements EmbargoService { itemService.clearMetadata(context, item, lift_schema, lift_element, lift_qualifier, Item.ANY); // set the dc.date.available value to right now - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "available", Item.ANY); - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "date", "available", null, + itemService.clearMetadata(context, item, MetadataSchemaEnum.DC.getName(), "date", "available", Item.ANY); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "date", "available", null, DCDate.getCurrent().toString()); log.info("Lifting embargo on Item " + item.getHandle()); diff --git a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java index 1cdefcbbdd..3d446c8d1b 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java +++ b/dspace-api/src/main/java/org/dspace/eperson/SubscribeCLITool.java @@ -31,7 +31,7 @@ import org.apache.log4j.Logger; import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.ItemService; @@ -229,7 +229,7 @@ public class SubscribeCLITool { } List authors = itemService - .getMetadata(hii.item, MetadataSchema.DC_SCHEMA, "contributor", Item.ANY, Item.ANY); + .getMetadata(hii.item, MetadataSchemaEnum.DC.getName(), "contributor", Item.ANY, Item.ANY); if (authors.size() > 0) { emailText.append("\n ").append(labels.getString("org.dspace.eperson.Subscribe.authors")) diff --git a/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java index a91e6d06cd..d4e0482517 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/HandleIdentifierProvider.java @@ -15,7 +15,7 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; @@ -228,14 +228,15 @@ public class HandleIdentifierProvider extends IdentifierProvider { // First check that identifier doesn't already exist. boolean identifierExists = false; List identifiers = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); for (MetadataValue identifier : identifiers) { if (handleref.equals(identifier.getValue())) { identifierExists = true; } } if (!identifierExists) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "identifier", "uri", null, handleref); } } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java index da7f1d7882..9d936e7893 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java +++ b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProvider.java @@ -19,7 +19,7 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; @@ -417,9 +417,9 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { // load all identifiers, clear the metadata field, re add all // identifiers which are not from type handle and add the new handle. List identifiers = itemService.getMetadata(item, - MetadataSchema.DC_SCHEMA, "identifier", "uri", + MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, + itemService.clearMetadata(context, item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); for (MetadataValue identifier : identifiers) { if (this.supports(identifier.getValue())) { @@ -439,7 +439,8 @@ public class VersionedHandleIdentifierProvider extends IdentifierProvider { // Add handle as identifier.uri DC value. if (StringUtils.isNotBlank(handleref)) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "identifier", "uri", null, handleref); } itemService.update(context, item); } diff --git a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java index 72cbf7d4e7..7a51f301f3 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java +++ b/dspace-api/src/main/java/org/dspace/identifier/VersionedHandleIdentifierProviderWithCanonicalHandles.java @@ -17,7 +17,7 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; @@ -492,8 +492,8 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident // identifiers which are not from type handle and add the new handle. String handleref = handleService.getCanonicalForm(handle); List identifiers = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); - itemService.clearMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); + itemService.clearMetadata(context, item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); for (MetadataValue identifier : identifiers) { if (this.supports(identifier.getValue())) { // ignore handles @@ -508,7 +508,8 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident identifier.getConfidence()); } if (!StringUtils.isEmpty(handleref)) { - itemService.addMetadata(context, item, MetadataSchema.DC_SCHEMA, "identifier", "uri", null, handleref); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "identifier", "uri", null, handleref); } itemService.update(context, item); } diff --git a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java index 5dcd8c2e4a..aad4a5c444 100644 --- a/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java +++ b/dspace-api/src/main/java/org/dspace/rdf/conversion/MetadataConverterPlugin.java @@ -33,6 +33,7 @@ import org.dspace.content.DSpaceObject; 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.factory.ContentServiceFactory; import org.dspace.content.service.DSpaceObjectService; @@ -133,7 +134,7 @@ public class MetadataConverterPlugin implements ConverterPlugin { } List metadata_values = dsoService - .getMetadata(dso, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY); + .getMetadata(dso, MetadataSchemaEnum.DC.getName(), Item.ANY, Item.ANY, Item.ANY); for (MetadataValue value : metadata_values) { MetadataField metadataField = value.getMetadataField(); MetadataSchema metadataSchema = metadataField.getMetadataSchema(); diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java index c20de75ff8..7a2b3f2f30 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/BasicWorkflowServiceImpl.java @@ -31,7 +31,7 @@ import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.CollectionService; import org.dspace.content.service.InstallItemService; @@ -910,8 +910,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService { + rejection_message + " on " + now + " (GMT) "; // Add to item as a DC field - itemService - .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); itemService.update(context, myitem); // convert into personal workspace @@ -1135,8 +1135,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService { provDescription += installItemService.getBitstreamProvenanceMessage(context, item); // Add to item as a DC field - itemService - .addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); itemService.update(context, item); } @@ -1163,8 +1163,8 @@ public class BasicWorkflowServiceImpl implements BasicWorkflowService { provmessage += installItemService.getBitstreamProvenanceMessage(context, myitem); // Add message to the DC - itemService - .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); + itemService.addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provmessage); itemService.update(context, myitem); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java index a6cbf73007..e13540e47e 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java @@ -31,7 +31,7 @@ import org.dspace.content.Bundle; import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.InstallItemService; @@ -573,7 +573,7 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Get title List titles = itemService - .getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); + .getMetadata(item, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); String title = ""; try { title = I18nUtil.getMessage("org.dspace.workflow.WorkflowManager.untitled"); @@ -874,7 +874,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Add to item as a DC field itemService - .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription); + .addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); //Clear any workflow schema related metadata itemService @@ -1002,7 +1003,8 @@ public class XmlWorkflowServiceImpl implements XmlWorkflowService { // Add message to the DC itemService - .addMetadata(context, myitem, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provmessage); + .addMetadata(context, myitem, MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provmessage); itemService.update(context, myitem); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java index 072e2289d7..b83cfae00e 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/AcceptEditRejectAction.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; @@ -112,7 +112,7 @@ public class AcceptEditRejectAction extends ProcessingAction { + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", provDescription); itemService.update(c, wfi.getItem()); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java index 2b05f3d0d1..50686f3993 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/FinalEditAction.java @@ -13,7 +13,7 @@ import javax.servlet.http.HttpServletRequest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; @@ -68,7 +68,7 @@ public class FinalEditAction extends ProcessingAction { + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", provDescription); itemService.update(c, wfi.getItem()); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java index 1db060d39d..50ca0c0e6c 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ReviewAction.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; @@ -85,7 +85,7 @@ public class ReviewAction extends ProcessingAction { + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", provDescription); itemService.update(c, wfi.getItem()); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java index 97f26eb3c7..df06c6b0de 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/ScoreEvaluationAction.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataValue; import org.dspace.core.Context; import org.dspace.workflow.WorkflowException; @@ -66,8 +66,8 @@ public class ScoreEvaluationAction extends ProcessingAction { String provDescription = getProvenanceStartId() + " Approved for entry into archive with a score of: " + scoreMean; - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", - provDescription); + itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), + "description", "provenance", "en", provDescription); itemService.update(c, wfi.getItem()); } if (hasPassed) { diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java index 74eea2d448..215eaaf645 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/state/actions/processingaction/SingleUserReviewAction.java @@ -14,7 +14,7 @@ import javax.servlet.http.HttpServletRequest; import org.dspace.app.util.Util; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCDate; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.core.Context; import org.dspace.xmlworkflow.factory.XmlWorkflowServiceFactory; import org.dspace.xmlworkflow.state.Step; @@ -91,7 +91,7 @@ public class SingleUserReviewAction extends ProcessingAction { + usersName + " on " + now + " (GMT) "; // Add to item as a DC field - itemService.addMetadata(c, wfi.getItem(), MetadataSchema.DC_SCHEMA, "description", "provenance", "en", + itemService.addMetadata(c, wfi.getItem(), MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", provDescription); itemService.update(c, wfi.getItem()); } diff --git a/dspace-api/src/test/java/org/dspace/content/CollectionTest.java b/dspace-api/src/test/java/org/dspace/content/CollectionTest.java index 1e05353dcf..1913582c3f 100644 --- a/dspace-api/src/test/java/org/dspace/content/CollectionTest.java +++ b/dspace-api/src/test/java/org/dspace/content/CollectionTest.java @@ -1834,16 +1834,16 @@ public class CollectionTest extends AbstractDSpaceObjectTest { public void testGetCommunities() throws Exception { context.turnOffAuthorisationSystem(); Community community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "community 3"); + communityService.setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "community 3"); this.collection.addCommunity(community); community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "community 1"); + communityService.setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "community 1"); this.collection.addCommunity(community); community = communityService.create(null, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "community 2"); + communityService.setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "community 2"); this.collection.addCommunity(community); context.restoreAuthSystemState(); assertTrue("testGetCommunities 0", collection.getCommunities().size() == 4); diff --git a/dspace-api/src/test/java/org/dspace/content/CommunityTest.java b/dspace-api/src/test/java/org/dspace/content/CommunityTest.java index 65bf7f6f73..14af4b2b86 100644 --- a/dspace-api/src/test/java/org/dspace/content/CommunityTest.java +++ b/dspace-api/src/test/java/org/dspace/content/CommunityTest.java @@ -673,14 +673,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest { context.turnOffAuthorisationSystem(); Collection collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "collection B"); + collectionService + .setMetadataSingleValue(context, collection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "collection B"); collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "collection C"); + collectionService + .setMetadataSingleValue(context, collection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "collection C"); collection = collectionService.create(context, c); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "collection A"); + collectionService + .setMetadataSingleValue(context, collection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "collection A"); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); @@ -712,14 +715,17 @@ public class CommunityTest extends AbstractDSpaceObjectTest { context.turnOffAuthorisationSystem(); Community community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "subcommunity B"); + communityService + .setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "subcommunity B"); community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "subcommunity A"); + communityService + .setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "subcommunity A"); community = communityService.create(c, context); - communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "subcommunity C"); + communityService + .setMetadataSingleValue(context, community, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "subcommunity C"); //we need to commit the changes so we don't block the table for testing context.restoreAuthSystemState(); diff --git a/dspace-api/src/test/java/org/dspace/content/ItemTest.java b/dspace-api/src/test/java/org/dspace/content/ItemTest.java index 32e6e5deb5..003b870698 100644 --- a/dspace-api/src/test/java/org/dspace/content/ItemTest.java +++ b/dspace-api/src/test/java/org/dspace/content/ItemTest.java @@ -737,12 +737,12 @@ public class ItemTest extends AbstractDSpaceObjectTest { public void testGetCollections() throws Exception { context.turnOffAuthorisationSystem(); Collection collection = collectionService.create(context, owningCommunity); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "collection B"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "collection B"); it.addCollection(collection); collection = collectionService.create(context, owningCommunity); - collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, - "collection A"); + collectionService.setMetadataSingleValue(context, collection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY, "collection A"); it.addCollection(collection); context.restoreAuthSystemState(); assertThat("testGetCollections 0", it.getCollections(), notNullValue()); diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java index b41e8acd97..bfb1945a9d 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataFieldTest.java @@ -78,14 +78,14 @@ public class MetadataFieldTest extends AbstractUnitTest { public void init() { super.init(); try { - this.dcSchema = metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA); + this.dcSchema = metadataSchemaService.find(context, MetadataSchemaEnum.DC.getName()); this.mf = metadataFieldService.findByElement(context, - MetadataSchema.DC_SCHEMA, element, qualifier); + MetadataSchemaEnum.DC.getName(), element, qualifier); if (mf == null) { context.turnOffAuthorisationSystem(); this.mf = metadataFieldService - .create(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA), element, qualifier, - scopeNote); + .create(context, metadataSchemaService.find(context, MetadataSchemaEnum.DC.getName()), + element, qualifier, scopeNote); context.restoreAuthSystemState(); } @@ -165,7 +165,7 @@ public class MetadataFieldTest extends AbstractUnitTest { */ @Test public void testGetSchema() { - assertThat("testGetSchemaID 0", mf.getMetadataSchema().getName(), equalTo(MetadataSchema.DC_SCHEMA)); + assertThat("testGetSchemaID 0", mf.getMetadataSchema().getName(), equalTo(MetadataSchemaEnum.DC.getName())); } /** @@ -259,7 +259,8 @@ public class MetadataFieldTest extends AbstractUnitTest { */ @Test public void testFindByElement() throws Exception { - MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, element, qualifier); + MetadataField found = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), + element, qualifier); assertThat("testFindByElement 0", found, notNullValue()); assertThat("testFindByElement 1", found.getID(), equalTo(mf.getID())); assertThat("testFindByElement 2", found.getElement(), equalTo(mf.getElement())); @@ -290,7 +291,7 @@ public class MetadataFieldTest extends AbstractUnitTest { @Test public void testFindAllInSchema() throws Exception { List found = metadataFieldService - .findAllInSchema(context, metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA)); + .findAllInSchema(context, metadataSchemaService.find(context, MetadataSchemaEnum.DC.getName())); assertThat("testFindAllInSchema 0", found, notNullValue()); assertTrue("testFindAllInSchema 1", found.size() >= 1); assertTrue("testFindAllInSchema 2", found.size() <= metadataFieldService.findAll(context).size()); @@ -320,7 +321,7 @@ public class MetadataFieldTest extends AbstractUnitTest { MetadataField m = metadataFieldService.create(context, dcSchema, elem, qual, null); metadataFieldService.update(context, m); - MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, elem, qual); + MetadataField found = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), elem, qual); assertThat("testUpdateAuth 0", found.getID(), equalTo(m.getID())); } @@ -380,7 +381,7 @@ public class MetadataFieldTest extends AbstractUnitTest { metadataFieldService.delete(context, m); - MetadataField found = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, elem, qual); + MetadataField found = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(), elem, qual); assertThat("testDeleteAuth 0", found, nullValue()); } diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java index 35a82a9cec..145e20d90f 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataSchemaTest.java @@ -59,7 +59,7 @@ public class MetadataSchemaTest extends AbstractUnitTest { public void init() { super.init(); try { - this.ms = metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA); + this.ms = metadataSchemaService.find(context, MetadataSchemaEnum.DC.getName()); } catch (SQLException ex) { log.error("SQL Error in init", ex); fail("SQL Error in init: " + ex.getMessage()); @@ -122,7 +122,7 @@ public class MetadataSchemaTest extends AbstractUnitTest { @Test public void testGetSchemaID() throws SQLException { assertThat("testGetSchemaID 0", ms.getID(), - equalTo(metadataSchemaService.find(context, MetadataSchema.DC_SCHEMA).getID())); + equalTo(metadataSchemaService.find(context, MetadataSchemaEnum.DC.getName()).getID())); } /** diff --git a/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java b/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java index bee228aa05..79dfebcc6b 100644 --- a/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java +++ b/dspace-api/src/test/java/org/dspace/content/MetadataValueTest.java @@ -95,7 +95,7 @@ public class MetadataValueTest extends AbstractUnitTest { this.it = installItemService.installItem(context, workspaceItem); this.mf = metadataFieldService.findByElement(context, - MetadataSchema.DC_SCHEMA, element, qualifier); + MetadataSchemaEnum.DC.getName(), element, qualifier); this.mv = metadataValueService.create(context, it, mf); context.restoreAuthSystemState(); } catch (AuthorizeException ex) { diff --git a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java index 9ea23718b7..86b0022f0d 100644 --- a/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java +++ b/dspace-api/src/test/java/org/dspace/content/packager/ITDSpaceAIP.java @@ -36,7 +36,7 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.factory.ContentServiceFactory; @@ -164,17 +164,18 @@ public class ITDSpaceAIP extends AbstractUnitTest { // Community topCommunity = communityService.create(null, context); communityService - .addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); + .addMetadata(context, topCommunity, MetadataSchemaEnum.DC.getName(), + "title", null, null, "Top Community"); communityService.update(context, topCommunity); topCommunityHandle = topCommunity.getHandle(); Community child = communityService.createSubcommunity(context, topCommunity); communityService - .addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); + .addMetadata(context, child, MetadataSchemaEnum.DC.getName(), "title", null, null, "Child Community"); communityService.update(context, child); Community grandchild = communityService.createSubcommunity(context, child); - communityService.addMetadata(context, grandchild, MetadataSchema.DC_SCHEMA, "title", null, null, + communityService.addMetadata(context, grandchild, MetadataSchemaEnum.DC.getName(), "title", null, null, "Grandchild Community"); communityService.update(context, grandchild); @@ -558,8 +559,9 @@ public class ITDSpaceAIP extends AbstractUnitTest { // Change the Community name String newName = "This is NOT my Community name!"; - communityService.clearMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - communityService.addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, newName); + communityService.clearMetadata(context, topCommunity, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); + communityService.addMetadata(context, topCommunity, MetadataSchemaEnum.DC.getName(), + "title", null, null, newName); // Ensure name is changed assertEquals("testReplaceCommunityOnly() new name", topCommunity.getName(), newName); @@ -781,8 +783,10 @@ public class ITDSpaceAIP extends AbstractUnitTest { // Change the Collection name String newName = "This is NOT my Collection name!"; - collectionService.clearMetadata(context, testCollection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - collectionService.addMetadata(context, testCollection, MetadataSchema.DC_SCHEMA, "title", null, null, newName); + collectionService.clearMetadata(context, testCollection, MetadataSchemaEnum.DC.getName(), + "title", null, Item.ANY); + collectionService.addMetadata(context, testCollection, MetadataSchemaEnum.DC.getName(), + "title", null, null, newName); // Ensure name is changed assertEquals("testReplaceCollectionOnly() new name", testCollection.getName(), newName); @@ -1029,8 +1033,8 @@ public class ITDSpaceAIP extends AbstractUnitTest { // Change the Item name String newName = "This is NOT my Item name!"; - itemService.clearMetadata(context, testItem, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY); - itemService.addMetadata(context, testItem, MetadataSchema.DC_SCHEMA, "title", null, null, newName); + itemService.clearMetadata(context, testItem, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY); + itemService.addMetadata(context, testItem, MetadataSchemaEnum.DC.getName(), "title", null, null, newName); // Ensure name is changed assertEquals("testReplaceItem() new name", testItem.getName(), newName); diff --git a/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java b/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java index a0b21f8221..8bc61c0202 100644 --- a/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java +++ b/dspace-api/src/test/java/org/dspace/content/packager/PackageUtilsTest.java @@ -20,7 +20,7 @@ import org.dspace.AbstractUnitTest; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Community; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; @@ -87,13 +87,14 @@ public class PackageUtilsTest extends AbstractUnitTest { // Community topCommunity = communityService.create(null, context); communityService - .addMetadata(context, topCommunity, MetadataSchema.DC_SCHEMA, "title", null, null, "Top Community"); + .addMetadata(context, topCommunity, MetadataSchemaEnum.DC.getName(), "title", null, null, + "Top Community"); communityService.update(context, topCommunity); topCommunityHandle = topCommunity.getHandle(); Community child = communityService.createSubcommunity(context, topCommunity); communityService - .addMetadata(context, child, MetadataSchema.DC_SCHEMA, "title", null, null, "Child Community"); + .addMetadata(context, child, MetadataSchemaEnum.DC.getName(), "title", null, null, "Child Community"); communityService.update(context, child); // Create our primary Test Collection diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java index d14630b90b..8ac3876bb3 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CollectionBuilder.java @@ -16,7 +16,7 @@ import org.apache.commons.lang3.CharEncoding; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Collection; import org.dspace.content.Community; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.service.DSpaceObjectService; import org.dspace.core.Context; @@ -50,7 +50,7 @@ public class CollectionBuilder extends AbstractDSpaceObjectBuilder { } public CollectionBuilder withName(final String name) { - return setMetadataSingleValue(collection, MetadataSchema.DC_SCHEMA, "title", null, name); + return setMetadataSingleValue(collection, MetadataSchemaEnum.DC.getName(), "title", null, name); } public CollectionBuilder withLogo(final String content) throws AuthorizeException, IOException, SQLException { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java index 1cf9ba74cb..a517d71f2a 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java @@ -15,7 +15,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.CharEncoding; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Community; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.service.DSpaceObjectService; import org.dspace.core.Context; @@ -59,7 +59,7 @@ public class CommunityBuilder extends AbstractDSpaceObjectBuilder { } public CommunityBuilder withName(final String communityName) { - return setMetadataSingleValue(community, MetadataSchema.DC_SCHEMA, "title", null, communityName); + return setMetadataSingleValue(community, MetadataSchemaEnum.DC.getName(), "title", null, communityName); } public CommunityBuilder withLogo(String content) throws AuthorizeException, IOException, SQLException { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java index cf498cf0fb..b2127100e3 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java @@ -10,7 +10,7 @@ package org.dspace.app.rest.builder; import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.DSpaceObjectService; import org.dspace.core.Context; @@ -52,19 +52,20 @@ public class ItemBuilder extends AbstractDSpaceObjectBuilder { } public ItemBuilder withTitle(final String title) { - return setMetadataSingleValue(item, MetadataSchema.DC_SCHEMA, "title", null, title); + return setMetadataSingleValue(item, MetadataSchemaEnum.DC.getName(), "title", null, title); } public ItemBuilder withIssueDate(final String issueDate) { - return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "date", "issued", new DCDate(issueDate).toString()); + return addMetadataValue(item, MetadataSchemaEnum.DC.getName(), + "date", "issued", new DCDate(issueDate).toString()); } public ItemBuilder withAuthor(final String authorName) { - return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "contributor", "author", authorName); + return addMetadataValue(item, MetadataSchemaEnum.DC.getName(), "contributor", "author", authorName); } public ItemBuilder withSubject(final String subject) { - return addMetadataValue(item, MetadataSchema.DC_SCHEMA, "subject", null, subject); + return addMetadataValue(item, MetadataSchemaEnum.DC.getName(), "subject", null, subject); } public ItemBuilder withRelationshipType(final String relationshipType) { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java index 4d73d23b19..ce71acac3e 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java @@ -14,7 +14,7 @@ import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; import org.dspace.content.LicenseUtils; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; @@ -101,19 +101,19 @@ public class WorkspaceItemBuilder extends AbstractBuilder Date: Wed, 21 Nov 2018 11:37:14 +0100 Subject: [PATCH 032/188] Fixed checkstyle --- .../main/java/org/dspace/app/bulkedit/MetadataImport.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 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 de5a1e70d1..c8e4f5f4af 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 @@ -638,9 +638,11 @@ public class MetadataImport { if (StringUtils.equals(schema, "relation")) { - List relationshipTypeList = relationshipTypeService.findByLeftOrRightLabel(c, element); + List relationshipTypeList = relationshipTypeService + .findByLeftOrRightLabel(c, element); for (RelationshipType relationshipType : relationshipTypeList) { - for (Relationship relationship : relationshipService.findByItemAndRelationshipType(c, item, relationshipType)) { + for (Relationship relationship : relationshipService + .findByItemAndRelationshipType(c, item, relationshipType)) { relationshipService.delete(c, relationship); relationshipService.update(c, relationship); } From e7b6aded69a5752799a538ceea7ecb14d0ee20f3 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 22 Nov 2018 10:41:45 +0100 Subject: [PATCH 033/188] Fixed tests and added license headers --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 2 -- .../src/main/java/org/dspace/content/virtual/Related.java | 7 +++++++ .../main/java/org/dspace/content/virtual/VirtualBean.java | 7 +++++++ 3 files changed, 14 insertions(+), 2 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 6864a5c629..8232028af3 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1334,8 +1334,6 @@ prevent the generation of resource policy entry values with null dspace_object a } } catch (SQLException e) { log.error(e, e); - } finally { - context.close(); } return fullMetadataValueList; } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 50b0f1b74b..e16173f3db 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.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.content.virtual; import java.sql.SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java index b3f20f1054..bc818a80be 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.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.content.virtual; import java.sql.SQLException; From 925b83bc02b6c44970753f866c7847013513533a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 22 Nov 2018 16:05:27 +0100 Subject: [PATCH 034/188] [Task 57441] Implemented the requested endpoints, except for one todo --- .../app/rest/RelationshipRestController.java | 37 ++++++++++++++----- .../rest/RelationshipTypeRestController.java | 12 +++++- .../relation/EntityTypeHalLinkFactory.java | 25 +++++++++++++ ...tionshipResourceWrapperHalLinkFactory.java | 28 ++++++++++++++ ...shipTypeResourceWrapperHalLinkFactory.java | 27 ++++++++++++++ .../rest/model/RelationshipRestWrapper.java | 21 +++++++++++ .../model/RelationshipTypeRestWrapper.java | 21 +++++++++++ 7 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index b2509f4e88..fadf7a6fc9 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -14,7 +14,9 @@ import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang.StringUtils; import org.dspace.app.rest.converter.RelationshipConverter; +import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RelationshipRest; import org.dspace.app.rest.model.RelationshipRestWrapper; import org.dspace.app.rest.model.hateoas.RelationshipResourceWrapper; @@ -27,16 +29,17 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Context; +import org.dspace.util.UUIDUtils; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController -@RequestMapping("/api/core/items/" + - "{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}/relationships") +@RequestMapping("/api/core/relationships") public class RelationshipRestController { @Autowired @@ -54,20 +57,33 @@ public class RelationshipRestController { @Autowired Utils utils; + @Autowired + private HalLinkService halLinkService; + @RequestMapping(method = RequestMethod.GET, value = "/{label}") - public RelationshipResourceWrapper retrieveByLabel(@PathVariable UUID uuid, HttpServletResponse response, - HttpServletRequest request, @PathVariable String label) + public RelationshipResourceWrapper retrieveByLabel(HttpServletResponse response, + HttpServletRequest request, @PathVariable String label, + @RequestParam(name = "dso", required = false) String dsoId) throws SQLException { Context context = ContextUtil.obtainContext(request); List relationshipTypeList = relationshipTypeService.findByLeftOrRightLabel(context, label); - Item item = itemService.find(context, uuid); - List relationships = new LinkedList<>(); + if (StringUtils.isNotBlank(dsoId)) { - for (RelationshipType relationshipType : relationshipTypeList) { - relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType)); + UUID uuid = UUIDUtils.fromString(dsoId); + Item item = itemService.find(context, uuid); + + if (item == null) { + throw new ResourceNotFoundException("The request DSO with id: " + dsoId + " was not found"); + } + for (RelationshipType relationshipType : relationshipTypeList) { + relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType)); + } + } else { + //TODO Find by label + relationships = relationshipService.findAll(context); } List relationshipRests = new LinkedList<>(); @@ -76,11 +92,14 @@ public class RelationshipRestController { } RelationshipRestWrapper relationshipRestWrapper = new RelationshipRestWrapper(); + relationshipRestWrapper.setLabel(label); + relationshipRestWrapper.setDsoId(dsoId); relationshipRestWrapper.setRelationshipRestList(relationshipRests); RelationshipResourceWrapper relationshipResourceWrapper = new RelationshipResourceWrapper( relationshipRestWrapper, utils); + halLinkService.addLinks(relationshipResourceWrapper); return relationshipResourceWrapper; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java index 1038864883..3e80426805 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java @@ -14,6 +14,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.dspace.app.rest.converter.RelationshipTypeConverter; +import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RelationshipTypeRest; import org.dspace.app.rest.model.RelationshipTypeRestWrapper; import org.dspace.app.rest.model.hateoas.RelationshipTypeResourceWrapper; @@ -47,6 +48,9 @@ public class RelationshipTypeRestController { @Autowired private Utils utils; + @Autowired + private HalLinkService halLinkService; + @RequestMapping(method = RequestMethod.GET) public RelationshipTypeResourceWrapper retrieve(@PathVariable Integer id, HttpServletResponse response, HttpServletRequest request) throws SQLException { @@ -62,7 +66,13 @@ public class RelationshipTypeRestController { RelationshipTypeRestWrapper relationshipTypeRestWrapper = new RelationshipTypeRestWrapper(); + relationshipTypeRestWrapper.setEntityTypeId(id); + relationshipTypeRestWrapper.setEntityTypeLabel(entityType.getLabel()); relationshipTypeRestWrapper.setRelationshipTypeRestList(relationshipTypeRests); - return new RelationshipTypeResourceWrapper(relationshipTypeRestWrapper, utils); + + RelationshipTypeResourceWrapper relationshipTypeResourceWrapper = new RelationshipTypeResourceWrapper( + relationshipTypeRestWrapper, utils); + halLinkService.addLinks(relationshipTypeResourceWrapper); + return relationshipTypeResourceWrapper; } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java new file mode 100644 index 0000000000..a721dfbe42 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java @@ -0,0 +1,25 @@ +package org.dspace.app.rest.link.relation; + +import java.util.LinkedList; + +import org.dspace.app.rest.RelationshipTypeRestController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.hateoas.EntityTypeResource; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; + +@Component +public class EntityTypeHalLinkFactory extends HalLinkFactory { + protected void addLinks(EntityTypeResource halResource, Pageable pageable, LinkedList list) throws Exception { + list.add(buildLink("relationshiptypes", getMethodOn().retrieve(halResource.getContent().getId(), null, null))); + } + + protected Class getControllerClass() { + return RelationshipTypeRestController.class; + } + + protected Class getResourceClass() { + return EntityTypeResource.class; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java new file mode 100644 index 0000000000..57f6edb245 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java @@ -0,0 +1,28 @@ +package org.dspace.app.rest.link.relation; + +import java.util.LinkedList; + +import org.dspace.app.rest.RelationshipRestController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.hateoas.RelationshipResourceWrapper; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; + +@Component +public class RelationshipResourceWrapperHalLinkFactory + extends HalLinkFactory { + protected void addLinks(RelationshipResourceWrapper halResource, Pageable pageable, LinkedList list) + throws Exception { + list.add(buildLink(Link.REL_SELF, getMethodOn() + .retrieveByLabel(null, null, halResource.getContent().getLabel(), halResource.getContent().getDsoId()))); + } + + protected Class getControllerClass() { + return RelationshipRestController.class; + } + + protected Class getResourceClass() { + return RelationshipResourceWrapper.class; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java new file mode 100644 index 0000000000..b4a59f7953 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java @@ -0,0 +1,27 @@ +package org.dspace.app.rest.link.relation; + +import java.util.LinkedList; + +import org.dspace.app.rest.RelationshipTypeRestController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.hateoas.RelationshipTypeResourceWrapper; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; + +@Component +public class RelationshipTypeResourceWrapperHalLinkFactory + extends HalLinkFactory { + protected void addLinks(RelationshipTypeResourceWrapper halResource, Pageable pageable, LinkedList list) + throws Exception { + list.add(buildLink(Link.REL_SELF, getMethodOn().retrieve(halResource.getContent().getEntityTypeId(), null, null))); + } + + protected Class getControllerClass() { + return RelationshipTypeRestController.class; + } + + protected Class getResourceClass() { + return RelationshipTypeResourceWrapper.class; + } +} diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java index cf5804045c..43f0439a23 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java @@ -17,6 +17,11 @@ public class RelationshipRestWrapper implements RestAddressableModel { @JsonIgnore private List relationshipRestList; + private String label; + private String dsoId; + + + public List getRelationshipRestList() { return relationshipRestList; } @@ -36,4 +41,20 @@ public class RelationshipRestWrapper implements RestAddressableModel { public String getType() { return "relationship"; } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDsoId() { + return dsoId; + } + + public void setDsoId(String dsoId) { + this.dsoId = dsoId; + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRestWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRestWrapper.java index 577fc276be..3a6e22ebd2 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRestWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipTypeRestWrapper.java @@ -17,6 +17,11 @@ public class RelationshipTypeRestWrapper implements RestAddressableModel { @JsonIgnore private List relationshipTypeRestList; + private String entityTypeLabel; + private Integer entityTypeId; + + + public List getRelationshipTypeRestList() { return relationshipTypeRestList; } @@ -37,4 +42,20 @@ public class RelationshipTypeRestWrapper implements RestAddressableModel { public String getType() { return "relationshiptype"; } + + public String getEntityTypeLabel() { + return entityTypeLabel; + } + + public void setEntityTypeLabel(String label) { + this.entityTypeLabel = label; + } + + public Integer getEntityTypeId() { + return entityTypeId; + } + + public void setEntityTypeId(Integer entityTypeId) { + this.entityTypeId = entityTypeId; + } } From c6dfae90de2533f07076a92cfcea32bd5cfb6655 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 26 Nov 2018 09:02:30 +0100 Subject: [PATCH 035/188] intermediary commit --- .../dspace/content/RelationshipServiceImpl.java | 5 +++++ .../org/dspace/content/dao/RelationshipDAO.java | 3 +++ .../content/dao/impl/RelationshipDAOImpl.java | 14 ++++++++++++++ .../content/service/RelationshipService.java | 2 ++ .../app/rest/RelationshipRestController.java | 6 ++++-- 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index eecc80bc5d..3f5886e4bc 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -300,4 +300,9 @@ public class RelationshipServiceImpl implements RelationshipService { } return listToReturn; } + + public List findByRelationshipType(Context context, RelationshipType relationshipType) + throws SQLException { + return relationshipDAO.findByRelationshipType(context, relationshipType); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java index 9f532f4c01..bcf2ba8183 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java @@ -12,6 +12,7 @@ import java.util.List; import org.dspace.content.Item; import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; import org.dspace.core.Context; import org.dspace.core.GenericDAO; @@ -56,4 +57,6 @@ public interface RelationshipDAO extends GenericDAO { * @throws SQLException If something goes wrong */ int findRightPlaceByRightItem(Context context,Item item) throws SQLException; + + List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java index 5b3e33f5b5..b7fbb3710e 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java @@ -15,6 +15,7 @@ import javax.persistence.criteria.Root; import org.dspace.content.Item; import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; import org.dspace.content.Relationship_; import org.dspace.content.dao.RelationshipDAO; import org.dspace.core.AbstractHibernateDAO; @@ -62,4 +63,17 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl return 1; } } + + public List findByRelationshipType(Context context, RelationshipType relationshipType) + throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); + Root relationshipRoot = criteriaQuery.from(Relationship.class); + criteriaQuery.select(relationshipRoot); + criteriaQuery + .where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType), relationshipType)); + return list(context, criteriaQuery, true, Relationship.class, -1, -1); + } + + } diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index a8052e1e6f..feadaaaba3 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -76,4 +76,6 @@ public interface RelationshipService extends DSpaceCRUDService { public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) throws SQLException; + + List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException; } \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index fadf7a6fc9..94b801ddc6 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -82,8 +82,10 @@ public class RelationshipRestController { relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType)); } } else { - //TODO Find by label - relationships = relationshipService.findAll(context); + for (RelationshipType relationshipType : relationshipTypeList) { + relationships.addAll(relationshipService.findByRelationshipType(context, relationshipType)); + } +// relationships = relationshipService.findAll(context); } List relationshipRests = new LinkedList<>(); From 41ff37de1b0230f8e48cdc059a2331fb0f5f270a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 27 Nov 2018 08:33:10 +0100 Subject: [PATCH 036/188] [Task 57441] fixed pagination on the /label endpoint --- .../app/rest/RelationshipRestController.java | 10 +++-- ...tionshipResourceWrapperHalLinkFactory.java | 22 ++++++++++- .../hateoas/RelationshipResourceWrapper.java | 39 +++++++++++++++++-- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index 94b801ddc6..74620a2358 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -31,6 +31,7 @@ import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Context; import org.dspace.util.UUIDUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -63,8 +64,9 @@ public class RelationshipRestController { @RequestMapping(method = RequestMethod.GET, value = "/{label}") public RelationshipResourceWrapper retrieveByLabel(HttpServletResponse response, HttpServletRequest request, @PathVariable String label, - @RequestParam(name = "dso", required = false) String dsoId) - throws SQLException { + @RequestParam(name = "dso", required = false) String dsoId, + Pageable pageable) + throws Exception { Context context = ContextUtil.obtainContext(request); @@ -99,9 +101,9 @@ public class RelationshipRestController { relationshipRestWrapper.setRelationshipRestList(relationshipRests); RelationshipResourceWrapper relationshipResourceWrapper = new RelationshipResourceWrapper( - relationshipRestWrapper, utils); + relationshipRestWrapper, utils, relationshipRests.size(), pageable); - halLinkService.addLinks(relationshipResourceWrapper); + halLinkService.addLinks(relationshipResourceWrapper, pageable); return relationshipResourceWrapper; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java index 57f6edb245..dd3dd90f07 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java @@ -4,18 +4,36 @@ import java.util.LinkedList; import org.dspace.app.rest.RelationshipRestController; import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.RelationshipRestWrapper; +import org.dspace.app.rest.model.hateoas.EmbeddedPageHeader; +import org.dspace.app.rest.model.hateoas.RelationshipResource; import org.dspace.app.rest.model.hateoas.RelationshipResourceWrapper; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.hateoas.Link; import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponentsBuilder; @Component public class RelationshipResourceWrapperHalLinkFactory extends HalLinkFactory { protected void addLinks(RelationshipResourceWrapper halResource, Pageable pageable, LinkedList list) throws Exception { - list.add(buildLink(Link.REL_SELF, getMethodOn() - .retrieveByLabel(null, null, halResource.getContent().getLabel(), halResource.getContent().getDsoId()))); + + PageImpl page = new PageImpl<>(halResource.getFullList(), pageable, + halResource.getTotalElements()); + halResource.setPageHeader(new EmbeddedPageHeader(getSelfLink(halResource.getContent(), pageable), + page, true)); + } + + public String getSelfLink(RelationshipRestWrapper content, Pageable pageable) throws Exception { + if (content != null) { + UriComponentsBuilder uriBuilderSelfLink = uriBuilder(getMethodOn() + .retrieveByLabel(null, null, content.getLabel(), + content.getDsoId(), pageable)); + return uriBuilderSelfLink.build().toString(); + } + return null; } protected Class getControllerClass() { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java index 5262d23746..f4cbd1e102 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java @@ -10,23 +10,54 @@ package org.dspace.app.rest.model.hateoas; import java.util.LinkedList; import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.dspace.app.rest.model.RelationshipRest; import org.dspace.app.rest.model.RelationshipRestWrapper; import org.dspace.app.rest.utils.Utils; +import org.springframework.data.domain.Pageable; public class RelationshipResourceWrapper extends HALResource { - public RelationshipResourceWrapper(RelationshipRestWrapper content, Utils utils) { + + @JsonIgnore + private List list; + + @JsonIgnore + private List fullList; + + @JsonIgnore + private Integer totalElements; + + public RelationshipResourceWrapper(RelationshipRestWrapper content, Utils utils, Integer totalElements, + Pageable pageable) { super(content); - addEmbeds(content, utils); + this.totalElements = totalElements; + addEmbeds(content, utils, pageable); } - private void addEmbeds(RelationshipRestWrapper content, Utils utils) { + private void addEmbeds(RelationshipRestWrapper content, Utils utils, + Pageable pageable) { List list = new LinkedList<>(); for (RelationshipRest relationshipRest : content.getRelationshipRestList()) { list.add(new RelationshipResource(relationshipRest, utils)); } - + this.fullList = list; + int begin = pageable.getOffset(); + int end = (pageable.getOffset() + pageable.getPageSize()) > list.size() ? list.size() : pageable.getOffset() + pageable.getPageSize(); + list = list.subList(begin, end); + this.list = list; embedResource("relationships", list); } + + public List getList() { + return list; + } + + public Integer getTotalElements() { + return totalElements; + } + + public List getFullList() { + return fullList; + } } From 13fea6312e33ce2ff934468e2c7347dbee4818cf Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 27 Nov 2018 09:37:17 +0100 Subject: [PATCH 037/188] Cleaned up and fix license headers --- .../app/rest/RelationshipRestController.java | 1 - .../relation/EntityTypeHalLinkFactory.java | 7 ++++++ ...tionshipResourceWrapperHalLinkFactory.java | 20 ++++++++++----- ...shipTypeResourceWrapperHalLinkFactory.java | 7 ++++++ .../hateoas/RelationshipResourceWrapper.java | 25 ------------------- 5 files changed, 28 insertions(+), 32 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index 74620a2358..b760c8d0ea 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -87,7 +87,6 @@ public class RelationshipRestController { for (RelationshipType relationshipType : relationshipTypeList) { relationships.addAll(relationshipService.findByRelationshipType(context, relationshipType)); } -// relationships = relationshipService.findAll(context); } List relationshipRests = new LinkedList<>(); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java index a721dfbe42..8aa4620617 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/EntityTypeHalLinkFactory.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.rest.link.relation; import java.util.LinkedList; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java index dd3dd90f07..8c05fdd1b0 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java @@ -1,12 +1,19 @@ +/** + * 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.rest.link.relation; import java.util.LinkedList; import org.dspace.app.rest.RelationshipRestController; import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.RelationshipRest; import org.dspace.app.rest.model.RelationshipRestWrapper; -import org.dspace.app.rest.model.hateoas.EmbeddedPageHeader; -import org.dspace.app.rest.model.hateoas.RelationshipResource; +import org.dspace.app.rest.model.hateoas.EmbeddedPage; import org.dspace.app.rest.model.hateoas.RelationshipResourceWrapper; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; @@ -20,10 +27,11 @@ public class RelationshipResourceWrapperHalLinkFactory protected void addLinks(RelationshipResourceWrapper halResource, Pageable pageable, LinkedList list) throws Exception { - PageImpl page = new PageImpl<>(halResource.getFullList(), pageable, - halResource.getTotalElements()); - halResource.setPageHeader(new EmbeddedPageHeader(getSelfLink(halResource.getContent(), pageable), - page, true)); + PageImpl page = new PageImpl<>(halResource.getContent().getRelationshipRestList(), pageable, + halResource.getContent().getRelationshipRestList().size()); + + halResource.setPageHeader(new EmbeddedPage(getSelfLink(halResource.getContent(), pageable), + page, halResource.getContent().getRelationshipRestList(), true, "relationships")); } public String getSelfLink(RelationshipRestWrapper content, Pageable pageable) throws Exception { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java index b4a59f7953..88b98af27f 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.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.rest.link.relation; import java.util.LinkedList; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java index f4cbd1e102..0081638157 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java @@ -10,7 +10,6 @@ package org.dspace.app.rest.model.hateoas; import java.util.LinkedList; import java.util.List; -import com.fasterxml.jackson.annotation.JsonIgnore; import org.dspace.app.rest.model.RelationshipRest; import org.dspace.app.rest.model.RelationshipRestWrapper; import org.dspace.app.rest.utils.Utils; @@ -18,20 +17,9 @@ import org.springframework.data.domain.Pageable; public class RelationshipResourceWrapper extends HALResource { - - @JsonIgnore - private List list; - - @JsonIgnore - private List fullList; - - @JsonIgnore - private Integer totalElements; - public RelationshipResourceWrapper(RelationshipRestWrapper content, Utils utils, Integer totalElements, Pageable pageable) { super(content); - this.totalElements = totalElements; addEmbeds(content, utils, pageable); } @@ -41,23 +29,10 @@ public class RelationshipResourceWrapper extends HALResource list.size() ? list.size() : pageable.getOffset() + pageable.getPageSize(); list = list.subList(begin, end); - this.list = list; embedResource("relationships", list); } - public List getList() { - return list; - } - - public Integer getTotalElements() { - return totalElements; - } - - public List getFullList() { - return fullList; - } } From 8f81f2860775d1feba4a4642a6aa6a4406e0d55d Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 28 Nov 2018 14:17:11 +0100 Subject: [PATCH 038/188] [Task 57160] implemented CRUD methods on relationship endpoint --- .../java/org/dspace/content/Relationship.java | 8 -- .../content/RelationshipServiceImpl.java | 10 +- .../content/service/RelationshipService.java | 3 + .../app/rest/RestResourceController.java | 22 ++++ .../rest/converter/RelationshipConverter.java | 2 +- .../app/rest/model/RelationshipRest.java | 8 ++ .../model/hateoas/RelationshipResource.java | 1 + .../rest/repository/DSpaceRestRepository.java | 18 +++ .../RelationshipRestRepository.java | 121 ++++++++++++++++++ 9 files changed, 180 insertions(+), 13 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/Relationship.java b/dspace-api/src/main/java/org/dspace/content/Relationship.java index e8ebcfa645..c998e43fa1 100644 --- a/dspace-api/src/main/java/org/dspace/content/Relationship.java +++ b/dspace-api/src/main/java/org/dspace/content/Relationship.java @@ -76,14 +76,6 @@ public class Relationship implements ReloadableEntity { @Column(name = "right_place") private int rightPlace; - /** - * Standard getter for the ID field - * @return the ID - */ - public Integer getId() { - return id; - } - /** * Standard setter for the ID field * @param id The ID to be set diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index e996f21e2b..8f13bd995a 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -62,7 +62,7 @@ public class RelationshipServiceImpl implements RelationshipService { } } - private void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException { + public void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException { List leftRelationships = findByItemAndRelationshipType(context, relationship.getLeftItem(), relationship.getRelationshipType(), true); @@ -209,7 +209,9 @@ public class RelationshipServiceImpl implements RelationshipService { } for (Relationship relationship : relationships) { - relationshipDAO.save(context, relationship); + if (isRelationshipValidToCreate(context, relationship)) { + relationshipDAO.save(context, relationship); + } } } } @@ -233,12 +235,12 @@ public class RelationshipServiceImpl implements RelationshipService { log.warn("The relationship has been deemed invalid since the relation was null"); return false; } - if (relationship.getId() == null) { + if (relationship.getID() == null) { log.warn("The relationship has been deemed invalid since the ID" + " off the given relationship was null"); return false; } - if (this.find(context, relationship.getId()) == null) { + if (this.find(context, relationship.getID()) == null) { log.warn("The relationship has been deemed invalid since the relationship" + " is not present in the DB with the current ID"); logRelationshipTypeDetails(relationship.getRelationshipType()); diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index a8052e1e6f..edfa433d03 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -76,4 +76,7 @@ public interface RelationshipService extends DSpaceCRUDService { public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) throws SQLException; + + public void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException; + } \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index 864383d687..7af6544553 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -981,4 +981,26 @@ public class RestResourceController implements InitializingBean { repository.delete(id); return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT); } + + @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT) + public DSpaceResource put(HttpServletRequest request, + @PathVariable String apiCategory, @PathVariable String model, + @PathVariable Integer id, + @RequestBody(required = true) JsonNode jsonNode) { + return putOneInternal(request, apiCategory, model, id, jsonNode); + } + + private DSpaceResource putOneInternal(HttpServletRequest request, String apiCategory, String model, ID id, JsonNode jsonNode) { + checkModelPluralForm(apiCategory, model); + DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); + RestAddressableModel modelObject = null; + modelObject = repository.put(request, apiCategory, model, id, jsonNode); + if (modelObject == null) { + throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); + } + DSpaceResource result = repository.wrapResource(modelObject); + linkService.addLinks(result); + return result; + + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java index ca172604ba..9f5d4ba66f 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipConverter.java @@ -32,7 +32,7 @@ public class RelationshipConverter extends DSpaceConverter { public static final String CATEGORY = "core"; private UUID leftId; + private int relationshipTypeId; private RelationshipTypeRest relationshipType; private UUID rightId; private int leftPlace; @@ -81,4 +82,11 @@ public class RelationshipRest extends BaseObjectRest { this.rightPlace = rightPlace; } + public int getRelationshipTypeId() { + return relationshipTypeId; + } + + public void setRelationshipTypeId(int relationshipTypeId) { + this.relationshipTypeId = relationshipTypeId; + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java index 099725d6f7..8bebdac35d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResource.java @@ -19,5 +19,6 @@ import org.dspace.app.rest.utils.Utils; public class RelationshipResource extends DSpaceResource { public RelationshipResource(RelationshipRest data, Utils utils, String... rels) { super(data, utils, rels); + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index e853121c6f..a27ffbf2e4 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -14,6 +14,7 @@ import java.sql.SQLException; import javax.servlet.http.HttpServletRequest; +import com.fasterxml.jackson.databind.JsonNode; import org.apache.log4j.Logger; import org.dspace.app.rest.exception.PatchBadRequestException; import org.dspace.app.rest.exception.RESTAuthorizationException; @@ -407,4 +408,21 @@ public abstract class DSpaceRestRepository { + private static final Logger log = Logger.getLogger(RelationshipRestRepository.class); + + @Autowired private RelationshipService relationshipService; @Autowired private RelationshipConverter relationshipConverter; + @Autowired + private RelationshipTypeConverter relationshipTypeConverter; + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private AuthorizeService authorizeService; + + @Autowired + private ItemService itemService; + public RelationshipRest findOne(Context context, Integer integer) { try { return relationshipConverter.fromModel(relationshipService.find(context, integer)); @@ -60,4 +93,92 @@ public class RelationshipRestRepository extends DSpaceRestRepository wrapResource(RelationshipRest model, String... rels) { return new RelationshipResource(model, utils, rels); } + + protected RelationshipRest createAndReturn(Context context) + throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { + + HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest(); + ObjectMapper mapper = new ObjectMapper(); + RelationshipRest relationshipRest = null; + try { + relationshipRest = mapper.readValue(req.getInputStream(), RelationshipRest.class); + } catch (IOException e1) { + throw new UnprocessableEntityException("error parsing the body"); + } + + Relationship relationship = new Relationship(); + Item leftItem = itemService.find(context, relationshipRest.getLeftId()); + Item rightItem = itemService.find(context, relationshipRest.getRightId()); + EPerson ePerson = context.getCurrentUser(); + if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) && authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + relationship + .setRelationshipType(relationshipTypeService.find(context, relationshipRest.getRelationshipTypeId())); + relationship = relationshipService.create(context, relationship); + return relationshipConverter.fromModel(relationship); + } else { + throw new AccessDeniedException("You do not have write rights on this relationship's items"); + } + + } + + @Override + protected RelationshipRest put(Context context, HttpServletRequest request, String apiCategory, String model, + Integer id, + JsonNode jsonNode) + throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException { + + ObjectMapper mapper = new ObjectMapper(); + RelationshipRest relationshipRest = null; + try { + relationshipRest = mapper.readValue(jsonNode.toString(), RelationshipRest.class); + } catch (IOException e) { + throw new UnprocessableEntityException("error parsing the body"); + } + Relationship relationship = relationshipService.find(context, id); + if (relationship == null) { + throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); + } + Item leftItem = itemService.find(context, relationshipRest.getLeftId()); + Item rightItem = itemService.find(context, relationshipRest.getRightId()); + if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) && authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { + relationship.setId(relationshipRest.getId()); + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + + relationship.setRelationshipType(relationshipTypeService.find(context, relationshipRest.getRelationshipTypeId())); + if (relationshipRest.getLeftPlace() != -1) { + relationship.setLeftPlace(relationshipRest.getLeftPlace()); + } + if (relationshipRest.getRightPlace() != -1) { + relationship.setRightPlace(relationshipRest.getRightPlace()); + } + + relationshipService.updatePlaceInRelationship(context, relationship); + relationshipService.update(context, relationship); + + return relationshipConverter.fromModel(relationship); + } else { + throw new AccessDeniedException("You do not have write rights on this relationship's items"); + } + } + + @Override + protected void delete(Context context, Integer id) throws AuthorizeException { + + Relationship relationship = null; + try { + relationship = relationshipService.find(context, id); + if (relationship != null) { + if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) && authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) { + relationshipService.delete(context, relationship); + } else { + throw new AccessDeniedException("You do not have write rights on this relationship's items"); + } + } + } catch (SQLException e) { + log.error(e.getMessage(), e); + } + } } From 699fb42683f748fa17bb06729a8492485026620a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 29 Nov 2018 13:56:38 +0100 Subject: [PATCH 039/188] [Task 57441] fixed the label vs id conflicting issue --- .../org/dspace/app/rest/RelationshipRestController.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index b760c8d0ea..dc9439166c 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -43,6 +43,13 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/api/core/relationships") public class RelationshipRestController { + /** + * Regular expression in the request mapping to accept a string as identifier but not the other kind of + * identifier (digits or uuid) + */ + private static final String REGEX_REQUESTMAPPING_LABEL = "/{label:^(?!^\\d+$)" + + "(?!^[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}$)[\\w+\\-]+$+}"; + @Autowired private RelationshipTypeService relationshipTypeService; @@ -61,7 +68,7 @@ public class RelationshipRestController { @Autowired private HalLinkService halLinkService; - @RequestMapping(method = RequestMethod.GET, value = "/{label}") + @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_LABEL) public RelationshipResourceWrapper retrieveByLabel(HttpServletResponse response, HttpServletRequest request, @PathVariable String label, @RequestParam(name = "dso", required = false) String dsoId, From dcf21c04cf510cfd5314dcf91474d9fd7d201db6 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 29 Nov 2018 15:25:48 +0100 Subject: [PATCH 040/188] [Task 57718] added the leftItem and rightItem links to the relationship endpoint return --- .../relation/RelationshipHalLinkFactory.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java new file mode 100644 index 0000000000..d2729027a9 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java @@ -0,0 +1,33 @@ +package org.dspace.app.rest.link.relation; + +import java.util.LinkedList; + +import org.atteo.evo.inflector.English; +import org.dspace.app.rest.RestResourceController; +import org.dspace.app.rest.link.HalLinkFactory; +import org.dspace.app.rest.model.ItemRest; +import org.dspace.app.rest.model.hateoas.RelationshipResource; +import org.springframework.data.domain.Pageable; +import org.springframework.hateoas.Link; +import org.springframework.stereotype.Component; + +@Component +public class RelationshipHalLinkFactory extends HalLinkFactory { + protected void addLinks(RelationshipResource halResource, Pageable pageable, LinkedList list) + throws Exception { + + list.add(buildLink("leftItem", getMethodOn() + .findOne(ItemRest.CATEGORY, English.plural(ItemRest.NAME), halResource.getContent().getLeftId(), null))); + + list.add(buildLink("rightItem", getMethodOn() + .findOne(ItemRest.CATEGORY, English.plural(ItemRest.NAME), halResource.getContent().getRightId(), null))); + } + + protected Class getControllerClass() { + return RestResourceController.class; + } + + protected Class getResourceClass() { + return RelationshipResource.class; + } +} From 4c1fdfc49cbdc7a7a1652c3f964a4779d792c781 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 29 Nov 2018 15:45:32 +0100 Subject: [PATCH 041/188] Added a license header --- .../app/rest/link/relation/RelationshipHalLinkFactory.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java index d2729027a9..ff0fb5b386 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipHalLinkFactory.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.rest.link.relation; import java.util.LinkedList; From 09faec3f1733c8923428fe82fc6de209ba3154fe Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 6 Dec 2018 17:43:15 +0000 Subject: [PATCH 042/188] Update Entities code to use log4j2 and commons-lang v3 (per master merge) --- .../src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java | 2 +- .../java/org/dspace/app/util/InitializeEntities.java | 7 ++++--- .../main/java/org/dspace/content/EntityServiceImpl.java | 2 +- .../java/org/dspace/content/RelationshipServiceImpl.java | 9 +++++---- .../org/dspace/app/rest/RootRestResourceController.java | 5 +++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java index a14f57bf95..ea95be7e72 100644 --- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java +++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java @@ -27,7 +27,7 @@ import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.dspace.authority.AuthorityValue; import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.service.AuthorityValueService; diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index 909fcd930e..6d90826e32 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -22,8 +22,9 @@ import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.EntityType; import org.dspace.content.RelationshipType; @@ -45,7 +46,7 @@ import org.xml.sax.SAXException; */ public class InitializeEntities { - private final static Logger log = Logger.getLogger(InitializeEntities.class); + private final static Logger log = LogManager.getLogger(); private RelationshipTypeService relationshipTypeService; private RelationshipService relationshipService; diff --git a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java index a3785a756b..5339fb440e 100644 --- a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java @@ -12,7 +12,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.dspace.content.service.EntityService; import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.ItemService; diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 9e9fee8f85..fee8e978ae 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -12,9 +12,10 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; -import org.apache.log4j.Logger; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.dao.RelationshipDAO; @@ -26,7 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; public class RelationshipServiceImpl implements RelationshipService { - private static final Logger log = Logger.getLogger(RelationshipServiceImpl.class); + private static final Logger log = LogManager.getLogger(); @Autowired(required = true) protected RelationshipDAO relationshipDAO; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java index 87b68aa08d..93eb7c3c55 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java @@ -9,7 +9,8 @@ package org.dspace.app.rest; import javax.servlet.http.HttpServletRequest; -import org.apache.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RootRest; import org.dspace.app.rest.model.hateoas.RootResource; @@ -40,7 +41,7 @@ public class RootRestResourceController { @Autowired RootRestRepository rootRestRepository; - private static Logger log = Logger.getLogger(RootRestResourceController.class); + private static Logger log = LogManager.getLogger(); @RequestMapping(method = RequestMethod.GET) public RootResource listDefinedEndpoint(HttpServletRequest request) { From 6e16a3ed620b088ce12dba8a0fa22474d9f51f28 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 7 Dec 2018 16:09:29 +0100 Subject: [PATCH 043/188] Applied community feedback --- .../main/java/org/dspace/content/ItemServiceImpl.java | 9 +++++---- .../org/dspace/content/dao/RelationshipTypeDAO.java | 9 +++++++++ .../java/org/dspace/content/service/ItemService.java | 5 ++++- .../dspace/content/service/RelationshipService.java | 11 +++++++++++ 4 files changed, 29 insertions(+), 5 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 1a7cae56b7..167c326553 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1317,7 +1317,7 @@ prevent the generation of resource policy entry values with null dspace_object a } @Override - public List getRelationshipMetadata(Item item, boolean extra) { + public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata) { Context context = new Context(); List fullMetadataValueList = new LinkedList<>(); try { @@ -1326,7 +1326,8 @@ prevent the generation of resource policy entry values with null dspace_object a if (StringUtils.isNotBlank(entityType)) { List relationships = relationshipService.findByItem(context, item); for (Relationship relationship : relationships) { - fullMetadataValueList.addAll(handleItemRelationship(item, entityType, relationship, extra)); + fullMetadataValueList.addAll(handleItemRelationship(item, entityType, + relationship, enableVirtualMetadata)); } } @@ -1337,7 +1338,7 @@ prevent the generation of resource policy entry values with null dspace_object a } private List handleItemRelationship(Item item, String entityType, - Relationship relationship, boolean extra) { + Relationship relationship, boolean enableVirtualMetadata) { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); HashMap> hashMaps = new HashMap<>(); @@ -1355,7 +1356,7 @@ prevent the generation of resource policy entry values with null dspace_object a relationName = relationship.getRelationshipType().getRightLabel(); } - if (hashMaps != null && extra) { + if (hashMaps != null && enableVirtualMetadata) { resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(item, hashMaps, otherItem, relationName)); } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java index 24abb4724b..f03037f8bc 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java @@ -37,6 +37,15 @@ public interface RelationshipTypeDAO extends GenericDAO { RelationshipType findbyTypesAndLabels(Context context, EntityType leftType,EntityType rightType,String leftLabel,String rightLabel) throws SQLException; + + /** + * This method will query the Database for a list of RelationshipType objects that have the given label + * either as a left or right label in its attributes + * @param context The relevant DSpace context + * @param label The label that the RelationshipType must have as a leftLabel or rightLabel attribute + * @return The list of RelationshipType objects that fit the criteria + * @throws SQLException If something goes wrong + */ List findByLeftOrRightLabel(Context context, String label) throws SQLException; } 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 e9aee14eaa..107d8d698a 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 @@ -646,8 +646,11 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega * This method retrieves a list of MetadataValue objects that get constructed from processing * the given Item's Relationships through the config given to the {@link VirtualMetadataPopulator} * @param item The Item that will be processed through it's Relationships + * @param enableVirtualMetadata This parameter will determine whether the list of Relationship metadata + * should be populated with metadata that is being generated through the + * VirtualMetadataPopulator functionality or not * @return The list of MetadataValue objects constructed through the Relationships */ - public List getRelationshipMetadata(Item item, boolean extra); + public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata); } diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index a8052e1e6f..106eb74252 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -73,6 +73,17 @@ public interface RelationshipService extends DSpaceCRUDService { */ int findRightPlaceByRightItem(Context context, Item item) throws SQLException; + /** + * This method will retrieve a list of Relationship objects by retrieving the list of Relationship objects + * for the given item and then filtering the Relationship objects on the RelationshipType object that is + * passed along to this method. + * @param context The relevant DSpace context + * @param item The Item for which the list of Relationship objects will be retrieved + * @param relationshipType The RelationshipType object on which the list of Relationship objects for the given + * Item will be filtered + * @return The list of Relationship objects for the given Item filtered on the RelationshipType object + * @throws SQLException If something goes wrong + */ public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) throws SQLException; From 8024242fd13b6bdd9eeaebcc4bccb5c48a0b3875 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 10 Dec 2018 09:56:43 +0100 Subject: [PATCH 044/188] Added @Override to applicable methods --- .../main/java/org/dspace/content/RelationshipServiceImpl.java | 1 + .../java/org/dspace/content/RelationshipTypeServiceImpl.java | 1 + .../org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java | 1 + 3 files changed, 3 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index f928c4d0bb..44a1848697 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -288,6 +288,7 @@ public class RelationshipServiceImpl implements RelationshipService { return listToReturn; } + @Override public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) throws SQLException { diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index 299d44447d..64489c02b9 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -85,6 +85,7 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { relationshipTypeDAO.delete(context, relationshipType); } + @Override public List findByLeftOrRightLabel(Context context, String label) throws SQLException { return relationshipTypeDAO.findByLeftOrRightLabel(context, label); } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java index 8fe5d18c56..5d311eabb5 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java @@ -38,6 +38,7 @@ public class RelationshipTypeDAOImpl extends AbstractHibernateDAO findByLeftOrRightLabel(Context context, String label) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class); From 4171729f848478a74490accf18c9dfa23ad84260 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 11 Dec 2018 09:30:13 +0100 Subject: [PATCH 045/188] Wrote IT test for CSV import and fixed a small error --- .../dspace/app/bulkedit/MetadataImport.java | 2 +- .../org/dspace/app/rest/csv/CsvImportIT.java | 291 ++++++++++++++++++ 2 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java 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 4b5c6266a0..0712f8d92a 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 @@ -767,7 +767,7 @@ public class MetadataImport { } relationship.setRelationshipType(acceptedRelationshipType); relationship.setLeftPlace(relationshipService.findLeftPlaceByLeftItem(c, relationship.getLeftItem()) + 1); - relationship.setRightPlace(relationshipService.findRightPlaceByRightItem(c, relationship.getLeftItem()) + 1); + relationship.setRightPlace(relationshipService.findRightPlaceByRightItem(c, relationship.getRightItem()) + 1); Relationship persistedRelationship = relationshipService.create(c, relationship); relationshipService.update(c, persistedRelationship); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java new file mode 100644 index 0000000000..bd5478dc95 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java @@ -0,0 +1,291 @@ +/** + * 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.rest.csv; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.matcher.RelationshipMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.EntityType; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.ItemService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class CsvImportIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private RelationshipService relationshipService; + + @Autowired + private ItemService itemService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + } + + @After + public void destroy() throws Exception { + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); + Iterator itemIterator = itemService.findAll(context); + + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); + relationshipTypeService.delete(context, relationshipType); + } + + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); + entityTypeService.delete(context, entityType); + } + + while (itemIterator.hasNext()) { + Item item = itemIterator.next(); + itemIterator.remove(); + itemService.delete(context, item); + } + + super.destroy(); + } + + @Test + public void createRelationshipsWithCsvImportTest() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item article = ItemBuilder.createItem(context, col1) + .withTitle("Article") + .withIssueDate("2017-10-17") + .withRelationshipType("Publication") + .build(); + + Item itemB = validateSpecificItemRelationCreationCsvImport(col1, article, "TestItemB", "Person", + "isPublicationOfAuthor", + "Relationship list size is 1", 1, 1, 1); + Item itemC = validateSpecificItemRelationCreationCsvImport(col1, article, "TestItemC", "Person", + "isPublicationOfAuthor", + "Relationship list size is 1", 1, 2, 1); + Item itemD = validateSpecificItemRelationCreationCsvImport(col1, article, "TestItemD", "Project", + "isPublicationOfProject", + "Relationship list size is 1", 1, 1, 1); + Item itemE = validateSpecificItemRelationCreationCsvImportMultiple(col1, "TestItemE", "Publication", + "isAuthorOfPublication", + "Relationship list size is 2", 2, 1, 2, + itemC, itemB); + + List relationships = relationshipService.findByItem(context, itemE); + getClient().perform(get("/api/core/relationships/" + relationships.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftPlace", is(1))) + .andExpect(jsonPath("$.rightId", is(itemC.getID().toString()))) + .andExpect(jsonPath("$.rightPlace", is(2))) + .andExpect(jsonPath("$", Matchers.is(RelationshipMatcher.matchRelationship(relationships.get(0))))); + getClient().perform(get("/api/core/relationships/" + relationships.get(1).getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftPlace", is(2))) + .andExpect(jsonPath("$.rightId", is(itemB.getID().toString()))) + .andExpect(jsonPath("$.rightPlace", is(2))) + .andExpect(jsonPath("$", Matchers.is(RelationshipMatcher.matchRelationship(relationships.get(1))))); + + Item itemF = validateSpecificItemRelationCreationCsvImport(col1, itemE, "TestItemF", "Person", + "isPublicationOfAuthor", + "Relationship list size is 1", 1, 3, 1); + + UpdateItemEToDeleteRelationshipToC(itemE, itemB, itemF, col1, "TestItemE"); + + getClient().perform(get("/api/core/items/" + itemE.getID())).andExpect(status().isOk()); + + assertItemERelationships(itemB, itemE, itemF); + + updateArticleItemToAddAnotherRelationship(col1, article, itemB, itemC, itemF); + + getClient().perform(get("/api/core/items/" + article.getID())).andExpect(status().isOk()); + + assertArticleRelationships(article, itemB, itemC, itemF); + + } + + private void assertItemERelationships(Item itemB, Item itemE, Item itemF) throws SQLException { + List relationshipsForItemE = relationshipService.findByItem(context, itemE); + assertThat(relationshipsForItemE.size(), is(2)); + assertThat(relationshipsForItemE.get(0).getRightItem(), is(itemF)); + assertThat(relationshipsForItemE.get(1).getRightItem(), is(itemB)); + } + + private void assertArticleRelationships(Item article, Item itemB, Item itemC, Item itemF) throws SQLException { + List relationshipsForArticle = relationshipService + .findByItemAndRelationshipType(context, article, relationshipTypeService + .findByLeftOrRightLabel(context,"isPublicationOfAuthor").get(0)); + assertThat(relationshipsForArticle.size(), is(3)); + List expectedRelationshipsItemsForArticle = new ArrayList<>(); + expectedRelationshipsItemsForArticle.add(itemC); + expectedRelationshipsItemsForArticle.add(itemF); + expectedRelationshipsItemsForArticle.add(itemB); + + List actualRelationshipsItemsForArticle = new ArrayList<>(); + for (Relationship relationship : relationshipsForArticle) { + if (relationship.getLeftItem().getID() == article.getID()) { + actualRelationshipsItemsForArticle.add(relationship.getLeftItem()); + } else { + actualRelationshipsItemsForArticle.add(relationship.getRightItem()); + } + } + assertThat(true, Matchers.is(actualRelationshipsItemsForArticle + .containsAll(expectedRelationshipsItemsForArticle))); + } + + private void updateArticleItemToAddAnotherRelationship(Collection col1, Item article, Item itemB, Item itemC, + Item itemF) throws Exception { + String csvLineString = article.getID().toString() + "," + col1 + .getHandle() + "," + "Article" + "," + "Publication" + "," + + itemB.getID().toString() + "||" + itemC.getID().toString() + "||" + itemF + .getID().toString(); + String[] csv = {"id,collection,dc.title,relationship.type,relation." + "isAuthorOfPublication", csvLineString}; + performImportScript(csv); + } + + private void UpdateItemEToDeleteRelationshipToC(Item itemE, Item itemB, Item itemF, Collection owningCollection, + String title) throws Exception { + String csvLineString = itemE.getID().toString() + "," + owningCollection + .getHandle() + "," + title + "," + "Person" + "," + itemB.getID().toString() + "||" + itemF.getID() + .toString(); + String[] csv = {"id,collection,dc.title,relationship.type,relation." + "isAuthorOfPublication", csvLineString}; + performImportScript(csv); + + } + + private Item validateSpecificItemRelationCreationCsvImport(Collection col1, Item relatedItem, String itemTitle, + String relationshipType, + String relationshipTypeLabel, + String reasonAssertCheck, Integer sizeToCheck, + Integer leftPlaceToCheck, + Integer rightPlaceToCheck) throws Exception { + String csvLineString = "+," + col1.getHandle() + "," + itemTitle + "," + relationshipType + "," + relatedItem + .getID().toString(); + String[] csv = {"id,collection,dc.title,relationship.type,relation." + relationshipTypeLabel, csvLineString}; + performImportScript(csv); + Iterator itemIteratorItem = itemService.findByMetadataField(context, "dc", "title", null, itemTitle); + Item item = itemIteratorItem.next(); + + List relationships = relationshipService.findByItem(context, item); + assertThat(reasonAssertCheck, relationships.size(), equalTo(sizeToCheck)); + getClient().perform(get("/api/core/items/" + item.getID())).andExpect(status().isOk()); + getClient().perform(get("/api/core/relationships/" + relationships.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftPlace", is(leftPlaceToCheck))) + .andExpect(jsonPath("$.rightPlace", is(rightPlaceToCheck))) + .andExpect(jsonPath("$", Matchers.is(RelationshipMatcher.matchRelationship(relationships.get(0))))); + + return item; + } + + private Item validateSpecificItemRelationCreationCsvImportMultiple(Collection col1, String itemTitle, + String relationshipType, + String relationshipTypeLabel, + String reasonAssertCheck, Integer sizeToCheck, + Integer leftPlaceToCheck, + Integer rightPlaceToCheck, Item... relatedItem) + throws Exception { + String idStringRelatedItems = ""; + for (Item item : relatedItem) { + idStringRelatedItems += item.getID().toString(); + idStringRelatedItems += "||"; + } + idStringRelatedItems = idStringRelatedItems.substring(0, idStringRelatedItems.length() - 2); + String csvLineString = "+," + col1 + .getHandle() + "," + itemTitle + "," + relationshipType + "," + idStringRelatedItems; + String[] csv = {"id,collection,dc.title,relationship.type,relation." + relationshipTypeLabel, csvLineString}; + performImportScript(csv); + Iterator itemIteratorItem = itemService.findByMetadataField(context, "dc", "title", null, itemTitle); + Item item = itemIteratorItem.next(); + + + return item; + } + + private void performImportScript(String[] csv) throws Exception { + String filename = "test.csv"; + BufferedWriter out = new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(filename), "UTF-8")); + for (String csvLine : csv) { + out.write(csvLine + "\n"); + } + out.flush(); + out.close(); + out = null; + + runDSpaceScript("metadata-import", "-f", "test.csv", "-e", "admin@email.com", "-s"); + } +} From 1b2cc563d7cb6bf7de3ce47bd74b16dd2167b3f8 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 11 Dec 2018 15:32:11 +0000 Subject: [PATCH 046/188] Increase memory available to Unit/Integration Tests --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 21bcef9015..585cccda45 100644 --- a/pom.xml +++ b/pom.xml @@ -424,7 +424,7 @@ @@ -435,7 +435,7 @@ - -Xmx512m + -Xmx1024m From d95c378edc8ee1c2eaf222e9b77a26761b8cef3f Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 13 Dec 2018 15:45:15 +0100 Subject: [PATCH 047/188] Implemented the feedback --- .../org/dspace/content/ItemServiceImpl.java | 16 ++--- .../org/dspace/content/virtual/Collected.java | 71 +++++++++++++++++++ .../dspace/content/virtual/Concatenate.java | 7 +- .../org/dspace/content/virtual/Related.java | 8 +-- .../dspace/content/virtual/VirtualBean.java | 12 ++-- .../content/StatisticsDataVisits.java | 8 +-- dspace/config/spring/api/core-services.xml | 35 ++------- 7 files changed, 103 insertions(+), 54 deletions(-) create mode 100644 dspace-api/src/main/java/org/dspace/content/virtual/Collected.java 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 00709923e7..49180a40f8 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1375,10 +1375,12 @@ prevent the generation of resource policy entry values with null dspace_object a String key = entry.getKey(); VirtualBean virtualBean = entry.getValue(); - MetadataValue metadataValue = constructMetadataValue(key); - metadataValue = constructResultingMetadataValue(context, item, otherItem, virtualBean, metadataValue); - if (StringUtils.isNotBlank(metadataValue.getValue())) { - resultingMetadataValueList.add(metadataValue); + for (String value : virtualBean.getValues(context, otherItem)) { + MetadataValue metadataValue = constructMetadataValue(key); + metadataValue = constructResultingMetadataValue(item, value, metadataValue); + if (StringUtils.isNotBlank(metadataValue.getValue())) { + resultingMetadataValueList.add(metadataValue); + } } } return resultingMetadataValueList; @@ -1405,10 +1407,8 @@ prevent the generation of resource policy entry values with null dspace_object a return entityType; } - private MetadataValue constructResultingMetadataValue(Context context, Item item, - Item otherItem, VirtualBean virtualBean, - MetadataValue metadataValue) throws SQLException { - metadataValue.setValue(virtualBean.getValue(context, otherItem)); + private MetadataValue constructResultingMetadataValue(Item item, String value, MetadataValue metadataValue) { + metadataValue.setValue(value); metadataValue.setAuthority("virtual"); metadataValue.setConfidence(-1); metadataValue.setDSpaceObject(item); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java new file mode 100644 index 0000000000..a1c9a57cd2 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -0,0 +1,71 @@ +/** + * 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.virtual; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.dspace.content.Item; +import org.dspace.content.MetadataValue; +import org.dspace.content.service.ItemService; +import org.dspace.core.Context; +import org.springframework.beans.factory.annotation.Autowired; + +public class Collected implements VirtualBean { + + @Autowired + private ItemService itemService; + + /** + * The fields for which the metadata will be retrieved + */ + private List fields; + + /** + * Generic getter for the fields property + * @return The list of fields to be used in this bean + */ + public List getFields() { + return fields; + } + + /** + * Generic setter for the fields property + * @param fields the list of fields to which the fields property will be set to + */ + public void setFields(List fields) { + this.fields = fields; + } + + + public List getValues(Context context, Item item) { + List resultValues = new LinkedList<>(); + List value = this.getFields(); + for (String s : value) { + String[] splittedString = s.split("\\."); + + List resultList = itemService.getMetadata(item, + splittedString.length > 0 ? splittedString[0] : + null, + splittedString.length > 1 ? splittedString[1] : + null, + splittedString.length > 2 ? splittedString[2] : + null, + Item.ANY); + + for (MetadataValue metadataValue : resultList) { + if (StringUtils.isNotBlank(metadataValue.getValue())) { + resultValues.add(metadataValue.getValue()); + } + } + } + + return resultValues; + } +} diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index 940a0cf952..c1c6547aa6 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -74,7 +74,7 @@ public class Concatenate implements VirtualBean { * @param item The item that will be used to either retrieve metadata values from * @return The String value for all of the retrieved metadatavalues combined with the seperator */ - public String getValue(Context context, Item item) { + public List getValues(Context context, Item item) { List resultValues = new LinkedList<>(); List value = this.getFields(); @@ -106,7 +106,8 @@ public class Concatenate implements VirtualBean { } String result = StringUtils.join(resultValues, this.getSeparator()); - - return result; + List listToReturn = new LinkedList<>(); + listToReturn.add(result); + return listToReturn; } } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 6ac10ce43f..a5f5f3a8e0 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -51,7 +51,7 @@ public class Related implements VirtualBean { */ private Integer place; /** - * The next bean to call its getValue() method on + * The next bean to call its getValues() method on */ private VirtualBean virtualBean; @@ -113,7 +113,7 @@ public class Related implements VirtualBean { * Will return null if no relationships are found * @throws SQLException If something goes wrong */ - public String getValue(Context context, Item item) throws SQLException { + public List getValues(Context context, Item item) throws SQLException { Entity entity = entityService.findByItemId(context, item.getID()); EntityType entityType = entityService.getType(context, entity); @@ -135,12 +135,12 @@ public class Related implements VirtualBean { if (relationship.getRelationshipType().getLeftType() == entityType) { if (relationship.getLeftPlace() == place) { Item otherItem = relationship.getRightItem(); - return virtualBean.getValue(context, otherItem); + return virtualBean.getValues(context, otherItem); } } else if (relationship.getRelationshipType().getRightType() == entityType) { if (relationship.getRightPlace() == place) { Item otherItem = relationship.getLeftItem(); - return virtualBean.getValue(context, otherItem); + return virtualBean.getValues(context, otherItem); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java index bc818a80be..e149d10106 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java @@ -8,6 +8,7 @@ package org.dspace.content.virtual; import java.sql.SQLException; +import java.util.List; import org.dspace.content.Item; import org.dspace.core.Context; @@ -20,16 +21,13 @@ import org.dspace.core.Context; public interface VirtualBean { /** - * This method will return the String value for the metadata field that is configured in the - * {@link Concatenate} bean in the config and it will traverse all the {@link Related} beans - * in the config that are chained together until it finds a {@link Concatenate} bean for which - * the value can be retrieved. + * This method will return a list filled with String values which will be determine by the bean that's responsible + * of handling the metadata fields when fully traversed through all the {@link Related} beans * @param context The relevant DSpace context * @param item The item that will be used to either retrieve metadata values from or to find * the related item through its relationships - * @return The String value of all the metadata values of all fields defined in {@link Concatenate} - * bean which will be concatenated with a seperator that's defined in the same bean + * @return The list of String values of all the metadata values as constructed by the responsible bean * @throws SQLException If something goes wrong */ - String getValue(Context context, Item item) throws SQLException; + List getValues(Context context, Item item) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java index 5b003b3741..25458358c5 100644 --- a/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java +++ b/dspace-api/src/main/java/org/dspace/statistics/content/StatisticsDataVisits.java @@ -353,13 +353,13 @@ public class StatisticsDataVisits extends StatisticsData { /* for (int j = 0; j < topCounts2.length; j++) { ObjectCount count2 = topCounts2[j]; - String query = firsDataset.getFacetField() + ":" + count1.getValue(); + String query = firsDataset.getFacetField() + ":" + count1.getValues(); // Check if we also have a type present (if so this should be put into the query if ("id".equals(firsDataset.getFacetField()) && firsDataset.getQueries().get(0).getDsoType() != -1) query += " AND type:" + firsDataset.getQueries().get(0).getDsoType(); - query += " AND " + secondDataSet.getFacetField() + ":" + count2.getValue(); + query += " AND " + secondDataSet.getFacetField() + ":" + count2.getValues(); // Check if we also have a type present (if so this should be put into the query if ("id".equals(secondDataSet.getFacetField()) && secondDataSet.getQueries().get(0) .getDsoType() != -1) @@ -371,8 +371,8 @@ public class StatisticsDataVisits extends StatisticsData { // No need to add this many times // TODO: dit vervangen door te displayen value if (i == 0) { - dataset.setRowLabel(j, getResultName(count2.getValue(), secondDataSet, context)); - dataset.setRowLabelAttr(j, getAttributes(count2.getValue(), secondDataSet, context)); + dataset.setRowLabel(j, getResultName(count2.getValues(), secondDataSet, context)); + dataset.setRowLabelAttr(j, getAttributes(count2.getValues(), secondDataSet, context)); } diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 42dd3f9ea0..9b1684dbc1 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -162,15 +162,12 @@ - + orgunit.identifier.name - - , - @@ -191,44 +188,35 @@ - + orgunit.identifier.name - - , - - + orgunit.identifier.name - - , - - + journalvolume.identifier.volume - - , - @@ -240,25 +228,19 @@ - + journal.identifier.issn - - , - - + journal.identifier.name - - , - @@ -267,15 +249,12 @@ - + journalissue.identifier.number - - , - From 3123c1dd6178883fa4796b021ee10aab50ebd985 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 14 Dec 2018 09:54:26 +0100 Subject: [PATCH 048/188] Wrote documentation for the spring beans --- dspace/config/spring/api/core-services.xml | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 9b1684dbc1..8b0b755a35 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -119,6 +119,10 @@ --> + @@ -144,9 +148,21 @@ + + @@ -159,6 +175,9 @@ + @@ -173,6 +192,15 @@ + @@ -188,6 +216,16 @@ + @@ -211,6 +249,18 @@ + @@ -218,6 +268,22 @@ + @@ -261,6 +327,23 @@ + From e932075d039275430a866247965c381d9e548193 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 14 Dec 2018 13:26:16 +0100 Subject: [PATCH 049/188] Added documentation and @Override where applicable --- .../content/RelationshipServiceImpl.java | 7 +++++++ .../content/RelationshipTypeServiceImpl.java | 7 ++++++- .../dspace/content/dao/RelationshipDAO.java | 10 ++++++++++ .../content/dao/RelationshipTypeDAO.java | 18 ++++++++++++++++++ .../content/dao/impl/RelationshipDAOImpl.java | 4 ++++ .../dao/impl/RelationshipTypeDAOImpl.java | 3 +++ .../content/service/RelationshipService.java | 19 +++++++++++++++++++ .../service/RelationshipTypeService.java | 9 +++++++++ 8 files changed, 76 insertions(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 3f5886e4bc..46bfde95f0 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -48,6 +48,7 @@ public class RelationshipServiceImpl implements RelationshipService { return relationshipDAO.create(context, new Relationship()); } + @Override public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException { if (isRelationshipValidToCreate(context, relationship)) { if (!authorizeService.isAdmin(context)) { @@ -86,10 +87,12 @@ public class RelationshipServiceImpl implements RelationshipService { } } + @Override public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { return relationshipDAO.findLeftPlaceByLeftItem(context, item); } + @Override public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { return relationshipDAO.findRightPlaceByRightItem(context, item); } @@ -165,6 +168,7 @@ public class RelationshipServiceImpl implements RelationshipService { return relationship; } + @Override public List findByItem(Context context, Item item) throws SQLException { List list = relationshipDAO.findByItem(context, item); @@ -185,6 +189,7 @@ public class RelationshipServiceImpl implements RelationshipService { return list; } + @Override public List findAll(Context context) throws SQLException { return relationshipDAO.findAll(context, Relationship.class); } @@ -287,6 +292,7 @@ public class RelationshipServiceImpl implements RelationshipService { return listToReturn; } + @Override public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) @@ -301,6 +307,7 @@ public class RelationshipServiceImpl implements RelationshipService { return listToReturn; } + @Override public List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException { return relationshipDAO.findByRelationshipType(context, relationshipType); diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index e2d0a82141..7863fef898 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -35,7 +35,8 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { return relationshipTypeDAO.create(context, new RelationshipType()); } - public RelationshipType create(Context context, RelationshipType relationshipType) + @Override + public RelationshipType ecreate(Context context, RelationshipType relationshipType) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( @@ -44,19 +45,23 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { return relationshipTypeDAO.create(context, relationshipType); } + @Override public RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, String leftLabel,String rightLabel) throws SQLException { return relationshipTypeDAO.findbyTypesAndLabels(context, leftType, rightType, leftLabel, rightLabel); } + @Override public List findAll(Context context) throws SQLException { return relationshipTypeDAO.findAll(context, RelationshipType.class); } + @Override public List findByLeftOrRightLabel(Context context, String label) throws SQLException { return relationshipTypeDAO.findByLeftOrRightLabel(context, label); } + @Override public List findByEntityType(Context context, EntityType entityType) throws SQLException { return relationshipTypeDAO.findByEntityType(context, entityType); } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java index bcf2ba8183..5352e39680 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipDAO.java @@ -58,5 +58,15 @@ public interface RelationshipDAO extends GenericDAO { */ int findRightPlaceByRightItem(Context context,Item item) throws SQLException; + /** + * This method returns a list of Relationship objects for the given RelationshipType object. + * It will construct a list of all Relationship objects that have the given RelationshipType object + * as the relationshipType property + * @param context The relevant DSpace context + * @param relationshipType The RelationshipType object to be checked on + * @return A list of Relationship objects that have the given RelationshipType object as the + * relationshipType property + * @throws SQLException If something goes wrong + */ List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java index 9da26f76fe..f3193594df 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java @@ -38,6 +38,24 @@ public interface RelationshipTypeDAO extends GenericDAO { EntityType leftType,EntityType rightType,String leftLabel,String rightLabel) throws SQLException; + /** + * This method will return a list of RelationshipType objects for which the given label is equal to + * either the leftLabel or rightLabel. + * @param context The relevant DSpace context + * @param label The label that will be used to check on + * @return A list of RelationshipType objects that have the given label as either the leftLabel or rightLabel + * @throws SQLException If something goes wrong + */ List findByLeftOrRightLabel(Context context, String label) throws SQLException; + + /** + * This method will return a list of RelationshipType objects for which the given EntityType object is equal + * to the leftType or rightType + * @param context The relevant DSpace context + * @param entityType The EntityType object that will be used to check on + * @return The list of RelationshipType objects that have the given EntityType object + * as either a leftType or rightType + * @throws SQLException If something goes wrong + */ List findByEntityType(Context context, EntityType entityType) throws SQLException; } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java index b7fbb3710e..d6e79e7ff4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipDAOImpl.java @@ -23,6 +23,7 @@ import org.dspace.core.Context; public class RelationshipDAOImpl extends AbstractHibernateDAO implements RelationshipDAO { + @Override public List findByItem(Context context, Item item) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); @@ -34,6 +35,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl return list(context, criteriaQuery, true, Relationship.class, -1, -1); } + @Override public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); @@ -49,6 +51,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl } } + @Override public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); @@ -64,6 +67,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO impl } } + @Override public List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java index 79a5fa1ca6..7914040fa0 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java @@ -22,6 +22,7 @@ import org.dspace.core.Context; public class RelationshipTypeDAOImpl extends AbstractHibernateDAO implements RelationshipTypeDAO { + @Override public RelationshipType findbyTypesAndLabels(Context context, EntityType leftType, EntityType rightType, String leftLabel, String rightLabel) throws SQLException { @@ -38,6 +39,7 @@ public class RelationshipTypeDAOImpl extends AbstractHibernateDAO findByLeftOrRightLabel(Context context, String label) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class); @@ -52,6 +54,7 @@ public class RelationshipTypeDAOImpl extends AbstractHibernateDAO findByEntityType(Context context, EntityType entityType) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class); diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index feadaaaba3..81f6c32c5c 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -73,9 +73,28 @@ public interface RelationshipService extends DSpaceCRUDService { */ int findRightPlaceByRightItem(Context context, Item item) throws SQLException; + /** + * This method returns a list of Relationships for which the leftItem or rightItem is equal to the given + * Item object and for which the RelationshipType object is equal to the relationshipType property + * @param context The relevant DSpace context + * @param item The Item object to be matched on the leftItem or rightItem for the relationship + * @param relationshipType The RelationshipType object that will be used to check the Relationship on + * @return The list of Relationship objects that have the given Item object as leftItem or rightItem and + * for which the relationshipType property is equal to the given RelationshipType + * @throws SQLException If something goes wrong + */ public List findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType) throws SQLException; + /** + * This method returns a list of Relationship objets for which the relationshipType property is equal to the given + * RelationshipType object + * @param context The relevant DSpace context + * @param relationshipType The RelationshipType object that will be used to check the Relationship on + * @return The list of Relationship objects for which the given RelationshipType object is equal + * to the relationshipType property + * @throws SQLException If something goes wrong + */ List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException; } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java index f1abb734a8..fb199f39be 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java @@ -64,5 +64,14 @@ public interface RelationshipTypeService extends DSpaceCRUDService findByLeftOrRightLabel(Context context, String label) throws SQLException; + /** + * Returns a list of RelationshipType objects for which the given EntityType is equal to either the leftType + * or the rightType + * @param context The relevant DSpace context + * @param entityType The EntityType object used to check the leftType and rightType properties + * @return A list of RelationshipType objects for which the leftType or rightType property are equal to the + * given EntityType object + * @throws SQLException If something goes wrong + */ List findByEntityType(Context context, EntityType entityType) throws SQLException; } From 2f0fb32c8c23d25f9c7e92c49462253b8f8dd277 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 14 Dec 2018 13:27:29 +0100 Subject: [PATCH 050/188] Fixed typo --- .../java/org/dspace/content/RelationshipTypeServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index 7863fef898..401ade2d9e 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -36,7 +36,7 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { } @Override - public RelationshipType ecreate(Context context, RelationshipType relationshipType) + public RelationshipType create(Context context, RelationshipType relationshipType) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( From 240636e9783b431f807b31fdbd811731e75d9645 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 14 Dec 2018 14:53:11 +0100 Subject: [PATCH 051/188] Created new IT and fixed checkstyle --- .../config/entities/relationship-types.xml | 14 + .../app/rest/RelationshipRestController.java | 4 +- ...tionshipResourceWrapperHalLinkFactory.java | 6 +- ...shipTypeResourceWrapperHalLinkFactory.java | 3 +- .../hateoas/RelationshipResourceWrapper.java | 3 +- .../RelationshipTypeRestControllerIT.java | 268 ++++++++++++++++++ .../RelationshipTypeRestRepositoryIT.java | 7 +- 7 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java diff --git a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml index 23604d7c71..d3726994ff 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml @@ -109,4 +109,18 @@ 0 + + JournalIssue + Publication + isPublicationOfJournalIssue + isJournalIssueOfPublication + + 0 + 2147483647 + + + 0 + 1 + + \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index dc9439166c..310f0033ef 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -7,7 +7,6 @@ */ package org.dspace.app.rest; -import java.sql.SQLException; import java.util.LinkedList; import java.util.List; import java.util.UUID; @@ -88,7 +87,8 @@ public class RelationshipRestController { throw new ResourceNotFoundException("The request DSO with id: " + dsoId + " was not found"); } for (RelationshipType relationshipType : relationshipTypeList) { - relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType)); + relationships.addAll(relationshipService.findByItemAndRelationshipType(context, + item, relationshipType)); } } else { for (RelationshipType relationshipType : relationshipTypeList) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java index 8c05fdd1b0..4342e18d4b 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipResourceWrapperHalLinkFactory.java @@ -31,13 +31,15 @@ public class RelationshipResourceWrapperHalLinkFactory halResource.getContent().getRelationshipRestList().size()); halResource.setPageHeader(new EmbeddedPage(getSelfLink(halResource.getContent(), pageable), - page, halResource.getContent().getRelationshipRestList(), true, "relationships")); + page, halResource.getContent().getRelationshipRestList(), + true, "relationships")); } public String getSelfLink(RelationshipRestWrapper content, Pageable pageable) throws Exception { if (content != null) { UriComponentsBuilder uriBuilderSelfLink = uriBuilder(getMethodOn() - .retrieveByLabel(null, null, content.getLabel(), + .retrieveByLabel(null, null, + content.getLabel(), content.getDsoId(), pageable)); return uriBuilderSelfLink.build().toString(); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java index 88b98af27f..9da0a39f32 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/link/relation/RelationshipTypeResourceWrapperHalLinkFactory.java @@ -21,7 +21,8 @@ public class RelationshipTypeResourceWrapperHalLinkFactory extends HalLinkFactory { protected void addLinks(RelationshipTypeResourceWrapper halResource, Pageable pageable, LinkedList list) throws Exception { - list.add(buildLink(Link.REL_SELF, getMethodOn().retrieve(halResource.getContent().getEntityTypeId(), null, null))); + list.add(buildLink(Link.REL_SELF, getMethodOn() + .retrieve(halResource.getContent().getEntityTypeId(), null, null))); } protected Class getControllerClass() { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java index 0081638157..5851cbc65d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/RelationshipResourceWrapper.java @@ -30,7 +30,8 @@ public class RelationshipResourceWrapper extends HALResource list.size() ? list.size() : pageable.getOffset() + pageable.getPageSize(); + int end = (pageable.getOffset() + pageable.getPageSize()) > list.size() ? list.size() : + pageable.getOffset() + pageable.getPageSize(); list = list.subList(begin, end); embedResource("relationships", list); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java new file mode 100644 index 0000000000..f32f8bffc7 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java @@ -0,0 +1,268 @@ +/** + * 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.rest; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.builder.RelationshipBuilder; +import org.dspace.app.rest.matcher.EntityTypeMatcher; +import org.dspace.app.rest.matcher.PageMatcher; +import org.dspace.app.rest.matcher.RelationshipMatcher; +import org.dspace.app.rest.matcher.RelationshipTypeMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.EntityType; +import org.dspace.content.Item; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class RelationshipTypeRestControllerIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private RelationshipService relationshipService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + + } + + @After + public void destroy() throws Exception { + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); + + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); + relationshipTypeService.delete(context, relationshipType); + } + + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); + entityTypeService.delete(context, entityType); + } + + super.destroy(); + } + + @Test + public void findAllEntityTypes() throws Exception { + + context.turnOffAuthorisationSystem(); + + getClient().perform(get("/api/core/entitytypes")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7)))) + .andExpect(jsonPath("$._embedded.entitytypes", containsInAnyOrder( + EntityTypeMatcher.matchEntityTypeEntryForLabel("Publication"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("Person"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("Project"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("OrgUnit"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("Journal"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalVolume"), + EntityTypeMatcher.matchEntityTypeEntryForLabel("JournalIssue") + + ))) + ; + } + + @Test + public void findAllRelationshipTypesForPublications() throws Exception { + + context.turnOffAuthorisationSystem(); + EntityType publicationEntityType = entityTypeService.findByEntityType(context, "Publication"); + EntityType personEntityType = entityTypeService.findByEntityType(context, "Person"); + EntityType projectEntityType = entityTypeService.findByEntityType(context, "Project"); + EntityType orgunitEntityType = entityTypeService.findByEntityType(context, "OrgUnit"); + EntityType journalIssueEntityType = entityTypeService.findByEntityType(context, "journalIssue"); + + RelationshipType relationshipType1 = relationshipTypeService + .findbyTypesAndLabels(context, publicationEntityType, personEntityType, "isAuthorOfPublication", + "isPublicationOfAuthor"); + RelationshipType relationshipType2 = relationshipTypeService + .findbyTypesAndLabels(context, publicationEntityType, projectEntityType, "isProjectOfPublication", + "isPublicationOfProject"); + RelationshipType relationshipType3 = relationshipTypeService + .findbyTypesAndLabels(context, publicationEntityType, orgunitEntityType, "isOrgUnitOfPublication", + "isPublicationOfOrgUnit"); + RelationshipType relationshipType4 = relationshipTypeService + .findbyTypesAndLabels(context, journalIssueEntityType, publicationEntityType, "isPublicationOfJournalIssue", + "isJournalIssueOfPublication"); + RelationshipType relationshipType5 = relationshipTypeService + .findbyTypesAndLabels(context, publicationEntityType, orgunitEntityType, "isAuthorOfPublication", + "isPublicationOfAuthor"); + getClient().perform(get("/api/core/entitytypes/" + publicationEntityType.getID() + "/relationshiptypes")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType1), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType2), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType3), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType4), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipType5) + ))); + } + + @Test + public void createAndFindRelationships() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col2) + .withTitle("Author2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria") + .withRelationshipType("Person") + .build(); + + Item author3 = ItemBuilder.createItem(context, col2) + .withTitle("Author3") + .withIssueDate("2016-02-13") + .withAuthor("Maybe, Maybe") + .withRelationshipType("Person") + .build(); + + Item orgUnit1 = ItemBuilder.createItem(context, col3) + .withTitle("OrgUnit1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("OrgUnit") + .build(); + + Item project1 = ItemBuilder.createItem(context, col3) + .withTitle("Project1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Project") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + Item publication2 = ItemBuilder.createItem(context, col3) + .withTitle("Publication2") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isOrgUnitOfPersonRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Person"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isOrgUnitOfPerson", "isPersonOfOrgUnit"); + RelationshipType isOrgUnitOfProjectRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Project"), + entityTypeService.findByEntityType(context, "OrgUnit"), + "isOrgUnitOfProject", "isProjectOfOrgUnit"); + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + Relationship relationship1 = RelationshipBuilder + .createRelationshipBuilder(context, publication, author1, isAuthorOfPublicationRelationshipType).build(); + Relationship relationship2 = RelationshipBuilder + .createRelationshipBuilder(context, publication, author2, isAuthorOfPublicationRelationshipType).build(); + Relationship relationship3 = RelationshipBuilder + .createRelationshipBuilder(context, publication2, author2, isAuthorOfPublicationRelationshipType).build(); + Relationship relationship4 = RelationshipBuilder + .createRelationshipBuilder(context, publication2, author3, isAuthorOfPublicationRelationshipType).build(); + + getClient().perform(get("/api/core/relationships/isAuthorOfPublication")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1), + RelationshipMatcher.matchRelationship(relationship2), + RelationshipMatcher.matchRelationship(relationship3), + RelationshipMatcher.matchRelationship(relationship4) + ))); + + getClient().perform(get("/api/core/relationships/isAuthorOfPublication?dso=" + publication.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1), + RelationshipMatcher.matchRelationship(relationship2) + ))); + + getClient().perform(get("/api/core/relationships/isAuthorOfPublication?dso=" + publication2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship3), + RelationshipMatcher.matchRelationship(relationship4) + ))); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java index 3fafd8e1b9..e654ff6383 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java @@ -94,7 +94,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat @Test public void findAllRelationshipTypesTest() throws SQLException { - assertEquals(9, relationshipTypeService.findAll(context).size()); + assertEquals(10, relationshipTypeService.findAll(context).size()); } @Test @@ -194,7 +194,7 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat //We expect a 200 OK status .andExpect(status().isOk()) //The type has to be 'discover' - .andExpect(jsonPath("$.page.totalElements", is(9))) + .andExpect(jsonPath("$.page.totalElements", is(10))) //There needs to be a self link to this endpoint .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) //We have 4 facets in the default configuration, they need to all be present in the embedded section @@ -207,7 +207,8 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8))) + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) )); } From 4e51fd0c86c3e7a148ce828ba43a308172a947c5 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 14 Dec 2018 17:20:45 +0100 Subject: [PATCH 052/188] Added support for the leftItem and rightItem through the parameters --- .../content/DSpaceObjectServiceImpl.java | 3 ++- .../org/dspace/content/ItemServiceImpl.java | 8 +++---- .../content/RelationshipMetadataValue.java | 7 ++++++ .../dspace/content/service/ItemService.java | 1 - .../org/dspace/content/virtual/UUIDValue.java | 7 ++++++ .../app/rest/RestResourceController.java | 5 +++- .../RelationshipRestRepository.java | 24 +++++++++++-------- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 8e30936bfd..6caf09f2d0 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -561,7 +561,8 @@ public abstract class DSpaceObjectServiceImpl implements } for (MetadataValue metadataValue : metadataValues) { //Retrieve & store the place for each metadata value - if (StringUtils.startsWith(metadataValue.getAuthority(), "virtual::") && ((RelationshipMetadataValue) metadataValue).isUseForPlace()) { + if (StringUtils.startsWith(metadataValue.getAuthority(), "virtual::") && + ((RelationshipMetadataValue) metadataValue).isUseForPlace()) { int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); metadataValue.setPlace(mvPlace); String authority = metadataValue.getAuthority(); 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 093e88ee51..9789d457bf 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1371,10 +1371,7 @@ prevent the generation of resource policy entry values with null dspace_object a } private List handleRelationshipTypeMetadataMappping(Context context, Item item, - HashMap hashMaps, - Item otherItem, - String relationName, - Integer relationshipId) + HashMap hashMaps, Item otherItem, String relationName, Integer relationshipId) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); for (Map.Entry entry : hashMaps.entrySet()) { @@ -1439,7 +1436,8 @@ prevent the generation of resource policy entry values with null dspace_object a if (metadataField == null) { log.error( "A MetadataValue was attempted to construct with MetadataField for paremeters: metadataschema: " - + metadataSchema + ", metadataelement:" + metadataElement + ", metadataqualifier: " + metadataQualifier); + + metadataSchema + ", metadataelement:" + metadataElement + + ", metadataqualifier: " + metadataQualifier); return null; } metadataValue.setMetadataField(metadataField); diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index 700b0fc21f..c25aebb2b2 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.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.content; import org.hibernate.proxy.HibernateProxyHelper; 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 659d869f6f..e81faaeaa8 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 @@ -23,7 +23,6 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataField; -import org.dspace.content.MetadataValue; import org.dspace.content.RelationshipMetadataValue; import org.dspace.content.Thumbnail; import org.dspace.content.WorkspaceItem; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java index 4e512d3dfb..be4e247ca8 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.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.content.virtual; import java.sql.SQLException; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index 7af6544553..c9c5c86cda 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -990,7 +990,10 @@ public class RestResourceController implements InitializingBean { return putOneInternal(request, apiCategory, model, id, jsonNode); } - private DSpaceResource putOneInternal(HttpServletRequest request, String apiCategory, String model, ID id, JsonNode jsonNode) { + private DSpaceResource putOneInternal(HttpServletRequest request, + String apiCategory, + String model, ID id, + JsonNode jsonNode) { checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 4c0b3fa50d..37e30010fe 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -14,7 +14,6 @@ import javax.servlet.http.HttpServletRequest; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; import org.apache.log4j.Logger; import org.dspace.app.rest.converter.RelationshipConverter; import org.dspace.app.rest.converter.RelationshipTypeConverter; @@ -33,6 +32,7 @@ import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; +import org.dspace.util.UUIDUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -107,10 +107,11 @@ public class RelationshipRestRepository extends DSpaceRestRepository Date: Mon, 17 Dec 2018 13:45:04 +0100 Subject: [PATCH 053/188] Merging configurable_entities branch --- .../java/org/dspace/app/rest/RelationshipRestController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java index 310f0033ef..f9c34ebf62 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RelationshipRestController.java @@ -13,7 +13,8 @@ import java.util.UUID; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.Logger; import org.dspace.app.rest.converter.RelationshipConverter; import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RelationshipRest; From 1b0f00df187f86d8e09c817cbbc24b6ab1a1cf7e Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 18 Dec 2018 09:42:48 +0100 Subject: [PATCH 054/188] Comment on relationship.type --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 167c326553..0372c1fd14 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1291,6 +1291,8 @@ prevent the generation of resource policy entry values with null dspace_object a */ @Override public List getMetadata(Item item, String schema, String element, String qualifier, String lang) { + //Fields of the relationship schema are virtual metadata except for relationship.type which is the type of item in the model + //TODO: the "type" should be migrated to a constant if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName()) && !StringUtils.equals(element, "type")) { List relationMetadata = getRelationshipMetadata(item, false); From efd579f054abc59ecc0e525aff2694109d7199fd Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 18 Dec 2018 09:58:57 +0100 Subject: [PATCH 055/188] typing error --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 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 0372c1fd14..656cca3a5b 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1291,8 +1291,7 @@ prevent the generation of resource policy entry values with null dspace_object a */ @Override public List getMetadata(Item item, String schema, String element, String qualifier, String lang) { - //Fields of the relationship schema are virtual metadata except for relationship.type which is the type of item in the model - //TODO: the "type" should be migrated to a constant + //Fields of the relation schema are virtual metadata except for relation.type which is the type of item in the model if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName()) && !StringUtils.equals(element, "type")) { List relationMetadata = getRelationshipMetadata(item, false); From b050db1cae97f52641cc85eba1595d6030c00fd9 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 18 Dec 2018 10:17:12 +0100 Subject: [PATCH 056/188] JavaDoc updates --- .../org/dspace/content/ItemServiceImpl.java | 2 +- .../org/dspace/content/virtual/Collected.java | 13 +++++++ .../dspace/content/virtual/Concatenate.java | 10 ++++-- .../org/dspace/content/virtual/Related.java | 6 ++++ dspace/config/spring/api/core-services.xml | 35 ++++--------------- 5 files changed, 33 insertions(+), 33 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 49180a40f8..3f36095152 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1387,7 +1387,7 @@ prevent the generation of resource policy entry values with null dspace_object a } private MetadataValue getRelationMetadataFromOtherItem(Item otherItem, String relationName) { - MetadataValue metadataValue = constructMetadataValue("relation." + relationName); + MetadataValue metadataValue = constructMetadataValue(MetadataSchemaEnum.RELATION.getName() + "." + relationName); metadataValue.setAuthority("virtual"); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java index a1c9a57cd2..f2df5c4bd8 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -17,6 +17,12 @@ import org.dspace.content.service.ItemService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; +/** + * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + * The Collected bean will take all the values of each metadata field defined in the list and it'll + * create a list of virtual metadata fields defined by the map in which it's defined. + * All values from the metadata fields will returned as separate elements + */ public class Collected implements VirtualBean { @Autowired @@ -44,6 +50,13 @@ public class Collected implements VirtualBean { } + /** + * this method will retrieve the metadata values from the given item for all the metadata fields listed + * in the fields property and it'll return all those values as a list + * @param context The relevant DSpace context + * @param item The item that will be used to either retrieve metadata values from + * @return The String values for all of the retrieved metadatavalues + */ public List getValues(Context context, Item item) { List resultValues = new LinkedList<>(); List value = this.getFields(); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index c1c6547aa6..dc7db0658d 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -19,6 +19,10 @@ import org.springframework.beans.factory.annotation.Autowired; /** * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + * The Concatenate bean will take all the values of each metadata field configured in the list + * and it will join all of these together with the separator defined in this bean. This means that whichever + * entry this bean belongs to, that metadata field will have the value of the related item's metadata values + * joined together with this separator. Only one value will be returned */ public class Concatenate implements VirtualBean { @@ -30,7 +34,7 @@ public class Concatenate implements VirtualBean { */ private List fields; /** - * The seperator that will be used to concatenate the values retrieved from the above mentioned fields + * The separator that will be used to concatenate the values retrieved from the above mentioned fields */ private String separator; @@ -68,11 +72,11 @@ public class Concatenate implements VirtualBean { /** * this method will retrieve the metadata values from the given item for all the metadata fields listed - * in the fields property and it'll concatenate all those values together with the seperrator specified + * in the fields property and it'll concatenate all those values together with the separator specified * in this class * @param context The relevant DSpace context * @param item The item that will be used to either retrieve metadata values from - * @return The String value for all of the retrieved metadatavalues combined with the seperator + * @return The String value for all of the retrieved metadatavalues combined with the separator */ public List getValues(Context context, Item item) { diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index a5f5f3a8e0..22b57c3605 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -27,6 +27,12 @@ import org.springframework.beans.factory.annotation.Autowired; /** * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata * by traversing the path of relation specified in the config for this bean + * The Related bean will find the relationshiptype defined in the relationshipTypeString property on + * the current item and it'll use the related item from that relationship to pass it along to the virtualBean + * property which in turn refers to another VirtualBean instance and it continues the chain until it reaches + * either a Concatenate or Collected bean to retrieve the values. It will then return that value through the chain + * again and it'll fill the values into the virtual metadata fields that are defined in the map for the first + * Related bean. */ public class Related implements VirtualBean { diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 8b0b755a35..78fd545159 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -154,10 +154,7 @@ - @@ -604,4 +604,4 @@ - \ No newline at end of file + From 025c77ee703a44f228576737c0e5e4f6e75ea09f Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Wed, 23 Jan 2019 12:01:50 +0100 Subject: [PATCH 075/188] authorization for updating the place of both items --- .../main/java/org/dspace/content/RelationshipServiceImpl.java | 2 ++ .../dspace/app/rest/repository/RelationshipRestRepository.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 0631ab7f04..95ab1c1f46 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -79,6 +79,7 @@ public class RelationshipServiceImpl implements RelationshipService { relationship.getRelationshipType(), false); + context.turnOffAuthorisationSystem(); if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), true)) { if (!leftRelationships.isEmpty()) { leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); @@ -113,6 +114,7 @@ public class RelationshipServiceImpl implements RelationshipService { if (isCreation) { handleCreationPlaces(context, relationship); } + context.restoreAuthSystemState(); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index ef41b924ef..39c007dd29 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -120,8 +120,10 @@ public class RelationshipRestRepository extends DSpaceRestRepository Date: Thu, 24 Jan 2019 10:06:42 +0100 Subject: [PATCH 076/188] Implemented the additional getMetadata function with the boolean --- .../org/dspace/content/ItemServiceImpl.java | 62 +++++++++++-------- .../dspace/content/service/ItemService.java | 5 ++ .../org/dspace/content/virtual/Collected.java | 2 +- .../dspace/content/virtual/Concatenate.java | 2 +- 4 files changed, 42 insertions(+), 29 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 b0f4c80656..401765891c 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1292,33 +1292,7 @@ prevent the generation of resource policy entry values with null dspace_object a */ @Override public List getMetadata(Item item, String schema, String element, String qualifier, String lang) { - //Fields of the relation schema are virtual metadata - //except for relation.type which is the type of item in the model - if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName()) && !StringUtils.equals(element, "type")) { - - List relationMetadata = getRelationshipMetadata(item, false); - List listToReturn = new LinkedList<>(); - for (MetadataValue metadataValue : relationMetadata) { - if (StringUtils.equals(metadataValue.getMetadataField().getElement(), element)) { - listToReturn.add(metadataValue); - } - } - return listToReturn; - - } else { - List dbMetadataValues = super.getMetadata(item, schema, element, qualifier, lang); - - if (!(StringUtils.equals(schema, "*") && StringUtils.equals(element, "*") && - StringUtils.equals(qualifier, "*") && StringUtils.equals(lang, "*"))) { - return dbMetadataValues; - } - List fullMetadataValueList = new LinkedList<>(); - fullMetadataValueList.addAll(getRelationshipMetadata(item, true)); - fullMetadataValueList.addAll(dbMetadataValues); - - return fullMetadataValueList; - } - + return this.getMetadata(item, schema, element, qualifier, lang, true); } @Override @@ -1342,6 +1316,40 @@ prevent the generation of resource policy entry values with null dspace_object a return fullMetadataValueList; } + public List getMetadata(Item item, String schema, String element, String qualifier, String lang, + boolean enableVirtualMetadata) { + //Fields of the relation schema are virtual metadata + //except for relation.type which is the type of item in the model + if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName()) && !StringUtils.equals(element, "type")) { + + List relationMetadata = getRelationshipMetadata(item, false); + List listToReturn = new LinkedList<>(); + for (MetadataValue metadataValue : relationMetadata) { + if (StringUtils.equals(metadataValue.getMetadataField().getElement(), element)) { + listToReturn.add(metadataValue); + } + } + return listToReturn; + + } else { + List dbMetadataValues = super.getMetadata(item, schema, element, qualifier, lang); + + List fullMetadataValueList = new LinkedList<>(); + if (enableVirtualMetadata) { + fullMetadataValueList.addAll(getRelationshipMetadata(item, true)); + } + fullMetadataValueList.addAll(dbMetadataValues); + + List finalList = new LinkedList<>(); + for (MetadataValue metadataValue : fullMetadataValueList) { + if (match(schema, element, qualifier, lang, metadataValue)) { + finalList.add(metadataValue); + } + } + return finalList; + } + } + private List handleItemRelationship(Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata) 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 8f0324a39d..be91602a20 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 @@ -23,6 +23,7 @@ import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataValue; import org.dspace.content.RelationshipMetadataValue; import org.dspace.content.Thumbnail; import org.dspace.content.WorkspaceItem; @@ -653,4 +654,8 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega */ public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata); + + public List getMetadata(Item item, String schema, String element, String qualifier, + String lang, boolean enableVirtualMetadata); + } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java index 5989012385..37af8b4f4e 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -89,7 +89,7 @@ public class Collected implements VirtualBean { null, splittedString.length > 2 ? splittedString[2] : null, - Item.ANY); + Item.ANY, false); for (MetadataValue metadataValue : resultList) { if (StringUtils.isNotBlank(metadataValue.getValue())) { diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index eef5f9da61..dd12355b75 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -113,7 +113,7 @@ public class Concatenate implements VirtualBean { null, splittedString.length > 2 ? splittedString[2] : null, - Item.ANY); + Item.ANY, false); String resultString = ""; for (int i = 0; i < resultList.size(); i++) { From 51de4cd87ca6d53782df8fb3a8cd9f608298be82 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 24 Jan 2019 13:26:35 +0100 Subject: [PATCH 077/188] JavaDocs and boolean name update --- .../org/dspace/content/ItemServiceImpl.java | 4 +- .../dspace/content/service/ItemService.java | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 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 401765891c..03c9fe8f28 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1296,7 +1296,7 @@ prevent the generation of resource policy entry values with null dspace_object a } @Override - public List getRelationshipMetadata(Item item, boolean extra) { + public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata) { Context context = new Context(); List fullMetadataValueList = new LinkedList<>(); try { @@ -1306,7 +1306,7 @@ prevent the generation of resource policy entry values with null dspace_object a List relationships = relationshipService.findByItem(context, item); for (Relationship relationship : relationships) { fullMetadataValueList - .addAll(handleItemRelationship(context, item, entityType, relationship, extra)); + .addAll(handleItemRelationship(context, item, entityType, relationship, enableVirtualMetadata)); } } 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 be91602a20..970e614d68 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 @@ -655,6 +655,55 @@ public interface ItemService extends DSpaceObjectService, DSpaceObjectLega public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata); + + /** + * Get metadata for the DSpace Object in a chosen schema. + * See MetadataSchema for more information about schemas. + * Passing in a null value for qualifier + * or lang only matches metadata fields where that + * qualifier or languages is actually null. + * Passing in DSpaceObject.ANY + * retrieves all metadata fields with any value for the qualifier or + * language, including null + *

+ * Examples: + *

+ * Return values of the unqualified "title" field, in any language. + * Qualified title fields (e.g. "title.uniform") are NOT returned: + *

+ * dspaceobject.getMetadataByMetadataString("dc", "title", null, DSpaceObject.ANY ); + *

+ * Return all US English values of the "title" element, with any qualifier + * (including unqualified): + *

+ * dspaceobject.getMetadataByMetadataString("dc, "title", DSpaceObject.ANY, "en_US" ); + *

+ * The ordering of values of a particular element/qualifier/language + * combination is significant. When retrieving with wildcards, values of a + * particular element/qualifier/language combinations will be adjacent, but + * the overall ordering of the combinations is indeterminate. + * + * If enableVirtualMetadata is set to false, the virtual metadata will not be included + * + * @param item Item + * @param schema the schema for the metadata field. Must match + * the name of an existing metadata schema. + * @param element the element name. DSpaceObject.ANY matches any + * element. null doesn't really make sense as all + * metadata must have an element. + * @param qualifier the qualifier. null means unqualified, and + * DSpaceObject.ANY means any qualifier (including + * unqualified.) + * @param lang the ISO639 language code, optionally followed by an underscore + * and the ISO3166 country code. null means only + * values with no language are returned, and + * DSpaceObject.ANY means values with any country code or + * no country code are returned. + * @param enableVirtualMetadata + * Enables virtual metadata calculation and inclusion from the + * relationships. + * @return metadata fields that match the parameters + */ public List getMetadata(Item item, String schema, String element, String qualifier, String lang, boolean enableVirtualMetadata); From 391c5b4dc6ca4ecc2900e6f35e376c226463071d Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 24 Jan 2019 13:33:13 +0100 Subject: [PATCH 078/188] Sort metadata values part 1 --- .../content/MetadataValueComparator.java | 28 +++++++ .../rest/RelationshipRestRepositoryIT.java | 84 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java b/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java new file mode 100644 index 0000000000..ed914ee7af --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java @@ -0,0 +1,28 @@ +/** + * 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.Comparator; + +/** + * Compares two {@link MetadataValue}s. + * The comparator will sort by schema, element, qualifier, place (in that order) + */ +public class MetadataValueComparator + implements Comparator, Serializable { + @Override + public int compare(MetadataValue mv1, MetadataValue mv2) { + int compare = mv1.getMetadataField().getMetadataSchema().getID().compareTo(mv2.getMetadataField().getMetadataSchema().getID()); + if (compare != 0) + return compare; + compare = mv1.getMetadataField().getElement().compareTo(mv2.getMetadataField().getElement()); + //TODO: continue comparison + return compare; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index ba273b6c05..5e9e8f08c2 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -283,11 +283,17 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT List list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + assertEquals(2, list.size()); for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text")) { assertEquals(1, mdv.getPlace()); } } + MetadataValue author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + MetadataValue author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) @@ -310,10 +316,19 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT map = mapper.readValue(content, Map.class); String secondRelationshipIdString = String.valueOf(map.get("id")); + list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + assertEquals(3, list.size()); getClient(adminToken).perform(get("/api/core/relationships/" + secondRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); +// author0MD = list.get(0); +// assertEquals("Smith, Donald", author0MD.getValue()); +// author1MD = list.get(1); +// assertEquals("plain text", author1MD.getValue()); +// MetadataValue author2MD = list.get(2); +// assertEquals("Smith, Maria", author2MD.getValue()); + publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); // itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); @@ -323,12 +338,22 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT // itemService.update(context, publication); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + assertEquals(4, list.size()); for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text two")) { assertEquals(3, mdv.getPlace()); } } +// author0MD = list.get(0); +// assertEquals("Smith, Donald", author0MD.getValue()); +// author1MD = list.get(1); +// assertEquals("plain text", author1MD.getValue()); +// author2MD = list.get(2); +// assertEquals("Smith, Maria", author2MD.getValue()); +// MetadataValue author3MD = list.get(3); +// assertEquals("plain text two", author3MD.getValue()); + mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("leftItem", publication.getID().toString()) @@ -347,21 +372,80 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT map = mapper.readValue(content, Map.class); String thirdRelationshipIdString = String.valueOf(map.get("id")); + list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + assertEquals(5, list.size()); getClient(adminToken).perform(get("/api/core/relationships/" + thirdRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); +// author0MD = list.get(0); +// assertEquals("Smith, Donald", author0MD.getValue()); +// author1MD = list.get(1); +// assertEquals("plain text", author1MD.getValue()); +// author2MD = list.get(2); +// assertEquals("Smith, Maria", author2MD.getValue()); +// author3MD = list.get(3); +// assertEquals("plain text two", author3MD.getValue()); +// MetadataValue author4MD = list.get(4); +// assertEquals("Maybe, Maybe", author4MD.getValue()); + publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + assertEquals(6, list.size()); for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text three")) { assertEquals(5, mdv.getPlace()); } } + +// author0MD = list.get(0); +// assertEquals("Smith, Donald", author0MD.getValue()); +// author1MD = list.get(1); +// assertEquals("plain text", author1MD.getValue()); +// author2MD = list.get(2); +// assertEquals("Smith, Maria", author2MD.getValue()); +// author3MD = list.get(3); +// assertEquals("plain text two", author3MD.getValue()); +// author4MD = list.get(4); +// assertEquals("Maybe, Maybe", author4MD.getValue()); +// MetadataValue author5MD = list.get(5); +// assertEquals("plain text three", author5MD.getValue()); + + publication = itemService.find(context, publication.getID()); + itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text four"); + itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text five"); + itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text six"); + itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text seven"); + itemService.update(context, publication); + + list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + + assertEquals(10, list.size()); + for (MetadataValue mdv : list) { + if (StringUtils.equals(mdv.getValue(), "plain text four")) { + assertEquals(6, mdv.getPlace()); + } + if (StringUtils.equals(mdv.getValue(), "plain text five")) { + assertEquals(7, mdv.getPlace()); + } + if (StringUtils.equals(mdv.getValue(), "plain text six")) { + assertEquals(8, mdv.getPlace()); + } + if (StringUtils.equals(mdv.getValue(), "plain text seven")) { + assertEquals(9, mdv.getPlace()); + } + } + + list = itemService.getMetadata(publication, "dc", "contributor", Item.ANY, Item.ANY); + assertEquals(10, list.size()); //same size as authors + list = itemService.getMetadata(publication, "dc", Item.ANY, Item.ANY, Item.ANY); + assertEquals(16, list.size()); //also includes title, 4 date fields, uri + list = itemService.getMetadata(publication, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + assertEquals(20, list.size()); //also includes type and 3 relation.isAuthorOfPublication values } @Test From d7610ccf6ef2de46bc3257a2091e99e7154e0a68 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 24 Jan 2019 14:19:09 +0100 Subject: [PATCH 079/188] Resolving merge conflict --- .../org/dspace/content/ItemServiceImpl.java | 21 ------------------- 1 file changed, 21 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 d320c7b6dd..8ff9a80c3a 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1351,27 +1351,6 @@ prevent the generation of resource policy entry values with null dspace_object a } - @Override - public List getRelationshipMetadata(Item item, boolean enableVirtualMetadata) { - Context context = new Context(); - List fullMetadataValueList = new LinkedList<>(); - try { - List list = item.getMetadata(); - String entityType = getEntityTypeStringFromMetadata(list); - if (StringUtils.isNotBlank(entityType)) { - List relationships = relationshipService.findByItem(context, item); - for (Relationship relationship : relationships) { - fullMetadataValueList.addAll(handleItemRelationship(context, item, entityType, - relationship, enableVirtualMetadata)); - } - - } - } catch (SQLException e) { - log.error(e, e); - } - return fullMetadataValueList; - } - private List handleItemRelationship(Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata) From 54a626892a13240ec992dce81ebbc82108bd92d7 Mon Sep 17 00:00:00 2001 From: benbosman Date: Fri, 25 Jan 2019 09:10:19 +0100 Subject: [PATCH 080/188] indentation --- dspace/config/spring/api/discovery.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace/config/spring/api/discovery.xml b/dspace/config/spring/api/discovery.xml index 4c0deea893..174655a484 100644 --- a/dspace/config/spring/api/discovery.xml +++ b/dspace/config/spring/api/discovery.xml @@ -123,7 +123,7 @@ - + @@ -263,7 +263,7 @@ - + From 7d961db6ceebdea68cdefbf37e6e6c574c9f537f Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 28 Jan 2019 11:49:19 +0100 Subject: [PATCH 081/188] Applied feedback --- .../content/DSpaceObjectServiceImpl.java | 11 +++++---- .../org/dspace/content/ItemServiceImpl.java | 11 ++++----- .../content/RelationshipMetadataValue.java | 9 +++++++ .../content/RelationshipServiceImpl.java | 1 + .../content/service/RelationshipService.java | 10 ++++++++ .../org/dspace/content/virtual/UUIDValue.java | 4 ++++ .../main/java/org/dspace/core/Constants.java | 1 + .../app/rest/RestResourceController.java | 19 +++++++++++++++ .../rest/repository/DSpaceRestRepository.java | 24 +++++++++++++++++++ .../RelationshipRestRepository.java | 2 +- 10 files changed, 80 insertions(+), 12 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index fe4c5349d1..782a942cc1 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -246,7 +246,7 @@ public abstract class DSpaceObjectServiceImpl implements for (int i = 0; i < values.size(); i++) { if (authorities != null && authorities.size() >= i) { - if (StringUtils.startsWith(authorities.get(i), "virtual::")) { + if (StringUtils.startsWith(authorities.get(i), Constants.VIRTUAL_AUTHORITY_PREFIX)) { continue; } } @@ -561,7 +561,7 @@ public abstract class DSpaceObjectServiceImpl implements } for (MetadataValue metadataValue : metadataValues) { //Retrieve & store the place for each metadata value - if (StringUtils.startsWith(metadataValue.getAuthority(), "virtual::") && + if (StringUtils.startsWith(metadataValue.getAuthority(), Constants.VIRTUAL_AUTHORITY_PREFIX) && ((RelationshipMetadataValue) metadataValue).isUseForPlace()) { int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); metadataValue.setPlace(mvPlace); @@ -575,7 +575,8 @@ public abstract class DSpaceObjectServiceImpl implements } relationshipService.update(context, relationship); - } else if (!StringUtils.startsWith(metadataValue.getAuthority(), "virtual::")) { + } else if (!StringUtils.startsWith(metadataValue.getAuthority(), + Constants.VIRTUAL_AUTHORITY_PREFIX)) { int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue); metadataValue.setPlace(mvPlace); } @@ -588,14 +589,14 @@ public abstract class DSpaceObjectServiceImpl implements * * @param fieldToLastPlace the map containing the latest place of each metadata field * @param metadataValue the metadata value that needs to get a place - * @return The new place for the metadata valu + * @return The new place for the metadata value */ protected int getMetadataValuePlace(Map fieldToLastPlace, MetadataValue metadataValue) { MetadataField metadataField = metadataValue.getMetadataField(); if (fieldToLastPlace.containsKey(metadataField)) { fieldToLastPlace.put(metadataField, fieldToLastPlace.get(metadataField) + 1); } else { - // The metadata value place starts at 0q + // The metadata value place starts at 0 fieldToLastPlace.put(metadataField, 0); } return fieldToLastPlace.get(metadataField); 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 836a922113..19ce31c0d5 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1398,7 +1398,7 @@ prevent the generation of resource policy entry values with null dspace_object a RelationshipMetadataValue metadataValue = constructMetadataValue(context, MetadataSchemaEnum.RELATION .getName() + "." + relationName); - metadataValue.setAuthority("virtual::" + relationshipId); + metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId); metadataValue.setValue(otherItem.getID().toString()); return metadataValue; } @@ -1421,7 +1421,7 @@ prevent the generation of resource policy entry values with null dspace_object a RelationshipMetadataValue metadataValue, int relationshipId) { metadataValue.setValue(value); - metadataValue.setAuthority("virtual::" + relationshipId); + metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId); metadataValue.setConfidence(-1); metadataValue.setDSpaceObject(item); return metadataValue; @@ -1437,10 +1437,9 @@ prevent the generation of resource policy entry values with null dspace_object a MetadataField metadataField = metadataFieldService .findByElement(context, metadataSchema, metadataElement, metadataQualifier); if (metadataField == null) { - log.error( - "A MetadataValue was attempted to construct with MetadataField for paremeters: metadataschema: " - + metadataSchema + ", metadataelement:" + metadataElement + - ", metadataqualifier: " + metadataQualifier); + log.error("A MetadataValue was attempted to construct with MetadataField for parameters: " + + "metadataschema: {}, metadataelement: {}, metadataqualifier: {}", + metadataSchema, metadataElement, metadataQualifier); return null; } metadataValue.setMetadataField(metadataField); diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index c25aebb2b2..fb46431801 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -9,8 +9,17 @@ package org.dspace.content; import org.hibernate.proxy.HibernateProxyHelper; +/** + * This class is used as a representation of MetadataValues for the MetadataValues that are derived from the + * Relationships that the item has. This includes the useForPlace property which we'll have to use to determine + * whether these Values should be counted for place calculation on both the native MetadataValues and the + * Relationship's place attributes. + */ public class RelationshipMetadataValue extends MetadataValue { + /** + * This property determines whether this RelationshipMetadataValue should be used in place calculation or not + */ private boolean useForPlace; public boolean isUseForPlace() { diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index b6e3f32714..ad8f90c778 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -66,6 +66,7 @@ public class RelationshipServiceImpl implements RelationshipService { } } + @Override public void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException { List leftRelationships = findByItemAndRelationshipType(context, relationship.getLeftItem(), diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index 21c4888e4d..7cc5bd43c9 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -88,6 +88,16 @@ public interface RelationshipService extends DSpaceCRUDService { RelationshipType relationshipType) throws SQLException; + /** + * This method will update the place for the Relationship and all other relationships found by the items and + * relationship type of the given Relatonship. It will give this Relationship the last place in both the + * left and right place determined by querying for the list of leftRelationships and rightRelationships + * by the leftItem, rightItem and relationshipType of the given Relationship. + * @param context The relevant DSpace context + * @param relationship The Relationship object that will have it's place updated and that will be used + * to retrieve the other relationships whose place might need to be updated + * @throws SQLException If something goes wrong + */ public void updatePlaceInRelationship(Context context, Relationship relationship) throws SQLException; } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java index 52b83e47f3..4d7c23f594 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java @@ -14,6 +14,10 @@ import java.util.List; import org.dspace.content.Item; import org.dspace.core.Context; +/** + * This class is used by the VirtualMetadataPopulator. It will simply take the ID of the item that's passed along + * to this and return that as it's value + */ public class UUIDValue implements VirtualBean { private boolean useForPlace; diff --git a/dspace-api/src/main/java/org/dspace/core/Constants.java b/dspace-api/src/main/java/org/dspace/core/Constants.java index 8f5073f731..ad5e5aadff 100644 --- a/dspace-api/src/main/java/org/dspace/core/Constants.java +++ b/dspace-api/src/main/java/org/dspace/core/Constants.java @@ -224,6 +224,7 @@ public class Constants { public static final String DEFAULT_ENCODING = "UTF-8"; + public static final String VIRTUAL_AUTHORITY_PREFIX = "virtual::"; /** * Default constructor */ diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index 19c9d69613..e4717dbf5e 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -986,6 +986,25 @@ public class RestResourceController implements InitializingBean { return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT); } + /** + * Execute a PUT request for an entity with id of type Integer; + * + * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}/{id} + * + * Example: + *

+     * {@code
+     *      curl -X PUT http:///dspace-spring-rest/api/core/metadatafield/1
+     * }
+     * 
+ * + * @param request the http request + * @param apiCategory the API category e.g. "api" + * @param model the DSpace model e.g. "collection" + * @param id the ID of the target REST object + * @param jsonNode the part of the request body representing the updated rest object + * @return the relevant REST resource + */ @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT) public DSpaceResource put(HttpServletRequest request, @PathVariable String apiCategory, @PathVariable String model, diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index c0faa41879..6ca6416064 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -408,6 +408,16 @@ public abstract class DSpaceRestRepository Date: Mon, 28 Jan 2019 13:24:35 +0100 Subject: [PATCH 082/188] [Task 59343] sorted the list of metadatavalues and forced the itemconverter to use the itemservice --- .../org/dspace/content/ItemServiceImpl.java | 21 +++++++++++++++++++ .../app/rest/converter/ItemConverter.java | 3 +-- 2 files changed, 22 insertions(+), 2 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 8ff9a80c3a..6382941476 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -11,6 +11,7 @@ import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -18,6 +19,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -1329,6 +1332,8 @@ prevent the generation of resource policy entry values with null dspace_object a listToReturn.add(metadataValue); } } + listToReturn = sortMetadataValueList(listToReturn); + return listToReturn; } else { @@ -1346,11 +1351,27 @@ prevent the generation of resource policy entry values with null dspace_object a finalList.add(metadataValue); } } + finalList = sortMetadataValueList(finalList); return finalList; } } + private List sortMetadataValueList(List listToReturn) { + Comparator comparator = Comparator.comparing( + metadataValue -> metadataValue.getMetadataField().getMetadataSchema().getName()); + comparator = comparator.thenComparing(Comparator.comparing( + metadataValue -> metadataValue.getMetadataField().getElement())); + comparator = comparator.thenComparing(Comparator.comparing( + metadataValue -> metadataValue.getMetadataField().getQualifier())); + comparator = comparator.thenComparing(Comparator.comparing( + metadataValue -> metadataValue.getPlace())); + + Stream metadataValueStream = listToReturn.stream().sorted(comparator); + listToReturn = metadataValueStream.collect(Collectors.toList()); + return listToReturn; + } + private List handleItemRelationship(Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index ae7c3a602e..06a3beab15 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -95,8 +95,7 @@ public class ItemConverter extends DSpaceObjectConverter fullList = new LinkedList<>(); - fullList.addAll(obj.getMetadata()); - fullList.addAll(itemService.getRelationshipMetadata(obj, true)); + fullList = itemService.getMetadata(obj, Item.ANY, Item.ANY, Item.ANY, Item.ANY, true); List metadata = super.convertMetadataToRest(fullList); item.setMetadata(metadata); From a62a66ec412fb0d2ebb6b4dfdcd6dd5478f3860d Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 28 Jan 2019 14:10:36 +0100 Subject: [PATCH 083/188] removed the ItemService from the DspaceObjectService --- .../java/org/dspace/content/DSpaceObjectServiceImpl.java | 5 +---- .../java/org/dspace/content/MetadataValueComparator.java | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 1b87ca69f8..3cdd8c8e1a 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -27,7 +27,6 @@ import org.dspace.content.authority.Choices; import org.dspace.content.authority.service.ChoiceAuthorityService; import org.dspace.content.authority.service.MetadataAuthorityService; import org.dspace.content.service.DSpaceObjectService; -import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataValueService; import org.dspace.content.service.RelationshipService; @@ -65,8 +64,6 @@ public abstract class DSpaceObjectServiceImpl implements @Autowired(required = true) protected MetadataAuthorityService metadataAuthorityService; @Autowired(required = true) - protected ItemService itemService; - @Autowired(required = true) protected RelationshipService relationshipService; public DSpaceObjectServiceImpl() { @@ -559,7 +556,7 @@ public abstract class DSpaceObjectServiceImpl implements Map fieldToLastPlace = new HashMap<>(); List metadataValues = new LinkedList<>(); if (dso.getType() == Constants.ITEM) { - metadataValues = itemService.getMetadata((Item) dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY); + metadataValues = getMetadata(dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY); } else { metadataValues = dso.getMetadata(); } diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java b/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java index ed914ee7af..ea7abb9e42 100644 --- a/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java +++ b/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java @@ -18,9 +18,11 @@ public class MetadataValueComparator implements Comparator, Serializable { @Override public int compare(MetadataValue mv1, MetadataValue mv2) { - int compare = mv1.getMetadataField().getMetadataSchema().getID().compareTo(mv2.getMetadataField().getMetadataSchema().getID()); - if (compare != 0) + int compare = mv1.getMetadataField().getMetadataSchema().getID() + .compareTo(mv2.getMetadataField().getMetadataSchema().getID()); + if (compare != 0) { return compare; + } compare = mv1.getMetadataField().getElement().compareTo(mv2.getMetadataField().getElement()); //TODO: continue comparison return compare; From 7dc59a03a2cefa80a419afc3940f113772228860 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 28 Jan 2019 15:35:56 +0100 Subject: [PATCH 084/188] Fixed nullpointer issue in th comparator --- .../java/org/dspace/content/ItemServiceImpl.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 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 6382941476..07f2ddeeaf 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1359,13 +1359,14 @@ prevent the generation of resource policy entry values with null dspace_object a private List sortMetadataValueList(List listToReturn) { Comparator comparator = Comparator.comparing( - metadataValue -> metadataValue.getMetadataField().getMetadataSchema().getName()); - comparator = comparator.thenComparing(Comparator.comparing( - metadataValue -> metadataValue.getMetadataField().getElement())); - comparator = comparator.thenComparing(Comparator.comparing( - metadataValue -> metadataValue.getMetadataField().getQualifier())); - comparator = comparator.thenComparing(Comparator.comparing( - metadataValue -> metadataValue.getPlace())); + metadataValue -> metadataValue.getMetadataField().getMetadataSchema().getName(), + Comparator.nullsFirst(Comparator.naturalOrder())); + comparator = comparator.thenComparing(metadataValue -> metadataValue.getMetadataField().getElement(), + Comparator.nullsFirst(Comparator.naturalOrder())); + comparator = comparator.thenComparing(metadataValue -> metadataValue.getMetadataField().getQualifier(), + Comparator.nullsFirst(Comparator.naturalOrder())); + comparator = comparator.thenComparing(metadataValue -> metadataValue.getPlace(), + Comparator.nullsFirst(Comparator.naturalOrder())); Stream metadataValueStream = listToReturn.stream().sorted(comparator); listToReturn = metadataValueStream.collect(Collectors.toList()); From f8497ff392b5f4376e82a8610b2e1faeebf4182d Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 29 Jan 2019 10:26:25 +0100 Subject: [PATCH 085/188] JavaDoc --- .../content/MetadataValueComparator.java | 30 ------------------- .../content/RelationshipServiceImpl.java | 7 +++-- .../content/service/RelationshipService.java | 13 +++++++- .../rest/repository/DSpaceRestRepository.java | 11 ++++++- 4 files changed, 26 insertions(+), 35 deletions(-) delete mode 100644 dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java b/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java deleted file mode 100644 index ea7abb9e42..0000000000 --- a/dspace-api/src/main/java/org/dspace/content/MetadataValueComparator.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * 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.Comparator; - -/** - * Compares two {@link MetadataValue}s. - * The comparator will sort by schema, element, qualifier, place (in that order) - */ -public class MetadataValueComparator - implements Comparator, Serializable { - @Override - public int compare(MetadataValue mv1, MetadataValue mv2) { - int compare = mv1.getMetadataField().getMetadataSchema().getID() - .compareTo(mv2.getMetadataField().getMetadataSchema().getID()); - if (compare != 0) { - return compare; - } - compare = mv1.getMetadataField().getElement().compareTo(mv2.getMetadataField().getElement()); - //TODO: continue comparison - return compare; - } -} diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 6afef340ac..a97c084329 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -121,10 +121,11 @@ public class RelationshipServiceImpl implements RelationshipService { } - public void updateItem(Context context, Item leftItem) + @Override + public void updateItem(Context context, Item relatedItem) throws SQLException, AuthorizeException { - leftItem.setMetadataModified(); - itemService.update(context, leftItem); + relatedItem.setMetadataModified(); + itemService.update(context, relatedItem); } diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index e17a0f9f9a..8b13cd570f 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -91,6 +91,17 @@ public interface RelationshipService extends DSpaceCRUDService { public void updatePlaceInRelationship(Context context, Relationship relationship, boolean isCreation) throws SQLException, AuthorizeException; - public void updateItem(Context context, Item leftItem) throws SQLException, AuthorizeException; + /** + * This method will update the given item's metadata order. + * If the relationships for the item have been modified and will calculate the place based on a + * metadata field, this function will ensure the place is calculated. + * @param context The relevant DSpace context + * @param relatedItem The Item for which the list of Relationship location is calculated + * based on a metadata field + * @throws SQLException If something goes wrong + * @throws AuthorizeException + * If the user is not authorized to update the item + */ + public void updateItem(Context context, Item relatedItem) throws SQLException, AuthorizeException; } \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index c0faa41879..e00088e4bc 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -407,7 +407,16 @@ public abstract class DSpaceRestRepository Date: Tue, 29 Jan 2019 10:39:55 +0100 Subject: [PATCH 086/188] Verify order of virtual and real metadata --- .../rest/RelationshipRestRepositoryIT.java | 94 ++++++++++++------- 1 file changed, 58 insertions(+), 36 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 0c50dd1e2f..b820f48300 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -532,12 +532,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); -// author0MD = list.get(0); -// assertEquals("Smith, Donald", author0MD.getValue()); -// author1MD = list.get(1); -// assertEquals("plain text", author1MD.getValue()); -// MetadataValue author2MD = list.get(2); -// assertEquals("Smith, Maria", author2MD.getValue()); + author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + MetadataValue author2MD = list.get(2); + assertEquals("Smith, Maria", author2MD.getValue()); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); @@ -555,14 +555,14 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } } -// author0MD = list.get(0); -// assertEquals("Smith, Donald", author0MD.getValue()); -// author1MD = list.get(1); -// assertEquals("plain text", author1MD.getValue()); -// author2MD = list.get(2); -// assertEquals("Smith, Maria", author2MD.getValue()); -// MetadataValue author3MD = list.get(3); -// assertEquals("plain text two", author3MD.getValue()); + author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + author2MD = list.get(2); + assertEquals("Smith, Maria", author2MD.getValue()); + MetadataValue author3MD = list.get(3); + assertEquals("plain text two", author3MD.getValue()); mvcResult = getClient(adminToken).perform(post("/api/core/relationships") @@ -588,16 +588,16 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); -// author0MD = list.get(0); -// assertEquals("Smith, Donald", author0MD.getValue()); -// author1MD = list.get(1); -// assertEquals("plain text", author1MD.getValue()); -// author2MD = list.get(2); -// assertEquals("Smith, Maria", author2MD.getValue()); -// author3MD = list.get(3); -// assertEquals("plain text two", author3MD.getValue()); -// MetadataValue author4MD = list.get(4); -// assertEquals("Maybe, Maybe", author4MD.getValue()); + author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + author2MD = list.get(2); + assertEquals("Smith, Maria", author2MD.getValue()); + author3MD = list.get(3); + assertEquals("plain text two", author3MD.getValue()); + MetadataValue author4MD = list.get(4); + assertEquals("Maybe, Maybe", author4MD.getValue()); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); @@ -612,18 +612,18 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } } -// author0MD = list.get(0); -// assertEquals("Smith, Donald", author0MD.getValue()); -// author1MD = list.get(1); -// assertEquals("plain text", author1MD.getValue()); -// author2MD = list.get(2); -// assertEquals("Smith, Maria", author2MD.getValue()); -// author3MD = list.get(3); -// assertEquals("plain text two", author3MD.getValue()); -// author4MD = list.get(4); -// assertEquals("Maybe, Maybe", author4MD.getValue()); -// MetadataValue author5MD = list.get(5); -// assertEquals("plain text three", author5MD.getValue()); + author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + author2MD = list.get(2); + assertEquals("Smith, Maria", author2MD.getValue()); + author3MD = list.get(3); + assertEquals("plain text two", author3MD.getValue()); + author4MD = list.get(4); + assertEquals("Maybe, Maybe", author4MD.getValue()); + MetadataValue author5MD = list.get(5); + assertEquals("plain text three", author5MD.getValue()); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text four"); @@ -650,6 +650,28 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } } + + author0MD = list.get(0); + assertEquals("Smith, Donald", author0MD.getValue()); + author1MD = list.get(1); + assertEquals("plain text", author1MD.getValue()); + author2MD = list.get(2); + assertEquals("Smith, Maria", author2MD.getValue()); + author3MD = list.get(3); + assertEquals("plain text two", author3MD.getValue()); + author4MD = list.get(4); + assertEquals("Maybe, Maybe", author4MD.getValue()); + author5MD = list.get(5); + assertEquals("plain text three", author5MD.getValue()); + MetadataValue author6MD = list.get(6); + assertEquals("plain text four", author6MD.getValue()); + MetadataValue author7MD = list.get(7); + assertEquals("plain text five", author7MD.getValue()); + MetadataValue author8MD = list.get(8); + assertEquals("plain text six", author8MD.getValue()); + MetadataValue author9MD = list.get(9); + assertEquals("plain text seven", author9MD.getValue()); + list = itemService.getMetadata(publication, "dc", "contributor", Item.ANY, Item.ANY); assertEquals(10, list.size()); //same size as authors list = itemService.getMetadata(publication, "dc", Item.ANY, Item.ANY, Item.ANY); From 2dc03adc58723dea87983164dcd77b87a6c9dca4 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 29 Jan 2019 11:11:48 +0100 Subject: [PATCH 087/188] better readable code --- .../org/dspace/content/RelationshipServiceImpl.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 5e945f606b..6f8a87cd74 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -9,6 +9,7 @@ package org.dspace.content; import java.sql.SQLException; import java.util.Collections; +import java.util.Comparator; import java.util.LinkedList; import java.util.List; @@ -86,11 +87,11 @@ public class RelationshipServiceImpl implements RelationshipService { context.turnOffAuthorisationSystem(); if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), true)) { if (!leftRelationships.isEmpty()) { - leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); + leftRelationships.sort(Comparator.comparingInt(Relationship::getLeftPlace)); for (int i = 0; i < leftRelationships.size(); i++) { - leftRelationships.get(leftRelationships.size() - 1 - i).setLeftPlace(i); + leftRelationships.get(i).setLeftPlace(i); } - relationship.setLeftPlace(leftRelationships.get(0).getLeftPlace() + 1); + relationship.setLeftPlace(leftRelationships.size()); } else { relationship.setLeftPlace(0); } @@ -101,11 +102,11 @@ public class RelationshipServiceImpl implements RelationshipService { if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), false)) { if (!rightRelationships.isEmpty()) { - rightRelationships.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace()); + rightRelationships.sort(Comparator.comparingInt(Relationship::getRightPlace)); for (int i = 0; i < rightRelationships.size(); i++) { - rightRelationships.get(rightRelationships.size() - 1 - i).setRightPlace(i); + rightRelationships.get(i).setRightPlace(i); } - relationship.setRightPlace(rightRelationships.get(0).getRightPlace() + 1); + relationship.setRightPlace(rightRelationships.size()); } else { relationship.setRightPlace(0); } From 887a0999bd26190feee3915f7522921d1c57ecdd Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 29 Jan 2019 12:20:49 +0100 Subject: [PATCH 088/188] wording --- .../org/dspace/app/rest/repository/DSpaceRestRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 6ca6416064..c3db8fa91d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -409,7 +409,7 @@ public abstract class DSpaceRestRepository Date: Tue, 29 Jan 2019 13:07:49 +0100 Subject: [PATCH 089/188] wording --- .../org/dspace/app/rest/repository/DSpaceRestRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index c3db8fa91d..504a301edb 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -430,7 +430,7 @@ public abstract class DSpaceRestRepository Date: Tue, 29 Jan 2019 16:22:26 +0100 Subject: [PATCH 090/188] getValues should not return null values --- .../src/main/java/org/dspace/content/virtual/Related.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 06d7c8ac3a..6285d7d48f 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -137,7 +137,7 @@ public class Related implements VirtualBean { * @param item The item that will be used to find the related item through its relationships * @return The String value of the metadata fields concatened with a seperator as defined * in the deepest Concatened bean in the chain - * Will return null if no relationships are found + * Will return an empty list if no relationships are found * @throws SQLException If something goes wrong */ public List getValues(Context context, Item item) throws SQLException { @@ -172,7 +172,8 @@ public class Related implements VirtualBean { } } - return null; + //Return an empty list if no relationships were found + return new LinkedList<>(); } } From 864f6f12376461bde9f1df12292cb23b720c6e4b Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Wed, 6 Feb 2019 14:19:12 +0100 Subject: [PATCH 091/188] Support relationnships using a uri-list --- .../app/rest/RestResourceController.java | 168 +++++++++++++++--- .../rest/repository/DSpaceRestRepository.java | 90 +++++++++- .../RelationshipRestRepository.java | 94 ++++------ .../java/org/dspace/app/rest/utils/Utils.java | 73 ++++++++ .../app/rest/EPersonRestRepositoryIT.java | 1 - .../rest/RelationshipRestRepositoryIT.java | 112 +++++++++--- .../rest/WorkspaceItemRestRepositoryIT.java | 12 +- 7 files changed, 442 insertions(+), 108 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index e4717dbf5e..1e8de95d61 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -51,6 +51,7 @@ import org.dspace.app.rest.repository.LinkRestRepository; import org.dspace.app.rest.utils.RestRepositoryUtils; import org.dspace.app.rest.utils.Utils; import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -378,38 +379,64 @@ public class RestResourceController implements InitializingBean { /** * Execute a POST request; * - * curl -X POST http:///dspace-spring-rest/api/{apiCategory}/{model} + * curl -X POST -H "Content-Type:application/json" http:///dspace-spring-rest/api/{apiCategory}/{model} * * Example: *
      * {@code
-     *      curl -X POST http:///dspace-spring-rest/api/submission/workspaceitems
+     *      curl -X POST -H "Content-Type:application/json" http:///dspace-spring-rest/api/submission/workspaceitems
      * }
      * 
* - * @param request - * @param apiCategory - * @param model - * @return - * @throws HttpRequestMethodNotSupportedException + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @return The relevant ResponseEntity for this request + * @throws HttpRequestMethodNotSupportedException If something goes wrong */ - @RequestMapping(method = RequestMethod.POST) + @RequestMapping(method = RequestMethod.POST, consumes = {"application/json", "application/hal+json"}) public ResponseEntity post(HttpServletRequest request, @PathVariable String apiCategory, @PathVariable String model) throws HttpRequestMethodNotSupportedException { - return postInternal(request, apiCategory, model); + return postJsonInternal(request, apiCategory, model); } /** - * Internal method to execute POST; + * Execute a POST request; * - * @param request - * @param apiCategory - * @param model - * @return - * @throws HttpRequestMethodNotSupportedException + * curl -X POST -H "Content-Type:text/uri-list" http:///dspace-spring-rest/api/{apiCategory}/{model} + * + * Example: + *
+     * {@code
+     *      curl -X POST -H "Content-Type:text/uri-list" http:///dspace-spring-rest/api/submission/workspaceitems
+     * }
+     * 
+ * + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @return The relevant ResponseEntity for this request + * @throws HttpRequestMethodNotSupportedException If something goes wrong */ - public ResponseEntity postInternal(HttpServletRequest request, + @RequestMapping(method = RequestMethod.POST, consumes = {"text/uri-list"}) + public ResponseEntity postWithUriListContentType(HttpServletRequest request, + @PathVariable String apiCategory, + @PathVariable String model) + throws HttpRequestMethodNotSupportedException { + return postUriListInternal(request, apiCategory, model); + } + + /** + * Internal method to execute POST with application/json MediaType; + * + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @return The relevant ResponseEntity for this request + * @throws HttpRequestMethodNotSupportedException If something goes wrong + */ + public ResponseEntity postJsonInternal(HttpServletRequest request, String apiCategory, String model) throws HttpRequestMethodNotSupportedException { @@ -431,6 +458,39 @@ public class RestResourceController implements InitializingBean { return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); } + /** + * Internal method to execute POST with text/uri-list MediaType; + * + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @return The relevant ResponseEntity for this request + * @throws HttpRequestMethodNotSupportedException If something goes wrong + */ + public ResponseEntity postUriListInternal(HttpServletRequest request, + String apiCategory, + String model) + throws HttpRequestMethodNotSupportedException { + checkModelPluralForm(apiCategory, model); + DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); + RestAddressableModel modelObject = null; + try { + List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); + modelObject = repository.createAndReturn(dSpaceObjectList); + } catch (ClassCastException | IOException e) { + log.error(e.getMessage(), e); + return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR); + } + if (modelObject == null) { + throw new HttpRequestMethodNotSupportedException(RequestMethod.POST.toString()); + } + DSpaceResource result = repository.wrapResource(modelObject); + linkService.addLinks(result); + //TODO manage HTTPHeader + return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); + } + + /** * Called in POST, multipart, upload to a specific rest resource the file passed as "file" request parameter * @@ -989,12 +1049,12 @@ public class RestResourceController implements InitializingBean { /** * Execute a PUT request for an entity with id of type Integer; * - * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}/{id} + * curl -X PUT -H "Content-Type:application/json" http:///dspace-spring-rest/api/{apiCategory}/{model}/{id} * * Example: *
      * {@code
-     *      curl -X PUT http:///dspace-spring-rest/api/core/metadatafield/1
+     *      curl -X PUT -H "Content-Type:application/json" http:///dspace-spring-rest/api/core/metadatafield/1
      * }
      * 
* @@ -1005,18 +1065,53 @@ public class RestResourceController implements InitializingBean { * @param jsonNode the part of the request body representing the updated rest object * @return the relevant REST resource */ - @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT) + @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT, + consumes = {"application/json", "application/hal+json"}) public DSpaceResource put(HttpServletRequest request, @PathVariable String apiCategory, @PathVariable String model, @PathVariable Integer id, @RequestBody(required = true) JsonNode jsonNode) { - return putOneInternal(request, apiCategory, model, id, jsonNode); + return putOneJsonInternal(request, apiCategory, model, id, jsonNode); } - private DSpaceResource putOneInternal(HttpServletRequest request, - String apiCategory, - String model, ID id, - JsonNode jsonNode) { + /** + * Execute a PUT request for an entity with id of type Integer; + * + * curl -X PUT -H "Content-Type:text/uri-list" http:///dspace-spring-rest/api/{apiCategory}/{model}/{id} + * + * Example: + *
+     * {@code
+     *      curl -X PUT -H "Content-Type:text/uri-list" http:///dspace-spring-rest/api/core/metadatafield/1
+     * }
+     * 
+ * + * @param request the http request + * @param apiCategory the API category e.g. "api" + * @param model the DSpace model e.g. "collection" + * @param id the ID of the target REST object + * @return the relevant REST resource + */ + @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT, + consumes = {"text/uri-list"}) + public DSpaceResource put(HttpServletRequest request, + @PathVariable String apiCategory, @PathVariable String model, + @PathVariable Integer id) throws IOException { + return putOneUriListInternal(request, apiCategory, model, id); + } + + /** + * Internal method to execute PUT with application/json MediaType; + * + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @param id The ID for the resource to be altered by the PUT + * @param jsonNode The relevant JsonNode to be used by the PUT + * @return The relevant DSpaceResource for this request + */ + private DSpaceResource putOneJsonInternal( + HttpServletRequest request, String apiCategory, String model, ID id, JsonNode jsonNode) { checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; @@ -1029,4 +1124,29 @@ public class RestResourceController implements InitializingBean { return result; } + /** + * Internal method to execute PUT with text/uri-list MediaType; + * + * @param request The relevant request + * @param apiCategory The apiCategory to be used + * @param model The model to be used + * @param id The ID for the resource to be altered by the PUT + * @return The relevant DSpaceResource for this request + * @throws IOException If something goes wrong + */ + private DSpaceResource putOneUriListInternal( + HttpServletRequest request, String apiCategory, String model, ID id) throws IOException { + checkModelPluralForm(apiCategory, model); + DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); + RestAddressableModel modelObject = null; + List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); + modelObject = repository.put(request, apiCategory, model, id, dSpaceObjectList); + if (modelObject == null) { + throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); + } + DSpaceResource result = repository.wrapResource(modelObject); + linkService.addLinks(result); + return result; + + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 6ca6416064..eff8579727 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -11,6 +11,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.Serializable; import java.sql.SQLException; +import java.util.List; import javax.servlet.http.HttpServletRequest; @@ -25,6 +26,7 @@ import org.dspace.app.rest.model.hateoas.DSpaceResource; import org.dspace.app.rest.model.patch.Patch; import org.dspace.app.util.DCInputsReaderException; import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -254,9 +256,30 @@ public abstract class DSpaceRestRepository wrapResource(T model, String... rels); + /** + * Create and return a new instance. Data is recovered from the thread bound HTTP request and the list + * of DSpaceObjects provided in the parameter + * + * @param list The list of DSpaceObjects to be used in the createAndReturn method + * @return The created REST object + */ + public T createAndReturn(List list) { + Context context = null; + try { + context = obtainContext(); + T entity = thisRepository.createAndReturn(context, list); + context.commit(); + return entity; + } catch (AuthorizeException e) { + throw new RESTAuthorizationException(e); + } catch (SQLException ex) { + throw new RuntimeException(ex.getMessage(), ex); + } + } + /** * Create and return a new instance. Data are usually retrieved from the thread bound http request - * + * * @return the created REST object */ public T createAndReturn() { @@ -276,7 +299,26 @@ public abstract class DSpaceRestRepository list) + throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { + throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); + } + + /** + * Method to implement to support the creation of a new instance. Usually require to retrieve the http request from + * the thread bound attribute + * * @param context * the dspace context * @return the created REST object @@ -286,7 +328,7 @@ public abstract class DSpaceRestRepository dSpaceObjects) { + Context context = obtainContext(); + try { + thisRepository.put(context, request, apiCategory, model, id, dSpaceObjects); + context.commit(); + } catch (SQLException | AuthorizeException e) { + throw new RuntimeException(e.getMessage(), e); + } + return findOne(id); + } + /** * Implement this method in the subclass to support updating a DSpace instance. * @@ -449,4 +513,24 @@ public abstract class DSpaceRestRepository dSpaceObjects) + throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException { + throw new RepositoryMethodNotImplementedException(apiCategory, model); + } + } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index bd9677dfc0..0c64ebc098 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -7,13 +7,10 @@ */ package org.dspace.app.rest.repository; -import java.io.IOException; import java.sql.SQLException; import java.util.List; import javax.servlet.http.HttpServletRequest; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.log4j.Logger; import org.dspace.app.rest.converter.RelationshipConverter; import org.dspace.app.rest.converter.RelationshipTypeConverter; @@ -24,6 +21,7 @@ import org.dspace.app.rest.model.hateoas.DSpaceResource; import org.dspace.app.rest.model.hateoas.RelationshipResource; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.service.AuthorizeService; +import org.dspace.content.DSpaceObject; import org.dspace.content.Item; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; @@ -33,7 +31,6 @@ import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.dspace.util.UUIDUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -95,82 +92,67 @@ public class RelationshipRestRepository extends DSpaceRestRepository list) throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest(); - ObjectMapper mapper = new ObjectMapper(); - RelationshipRest relationshipRest = null; - try { - relationshipRest = mapper.readValue(req.getInputStream(), RelationshipRest.class); - } catch (IOException e1) { - throw new UnprocessableEntityException("error parsing the body"); - } Relationship relationship = new Relationship(); - Item leftItem = itemService.find(context, UUIDUtils.fromString(req.getParameter("leftItem"))); - Item rightItem = itemService.find(context, UUIDUtils.fromString(req.getParameter("rightItem"))); - RelationshipType relationshipType = relationshipTypeService - .find(context, Integer.parseInt(req.getParameter("relationshipType"))); + if (list.size() == 2 && list.get(0).getType() == Constants.ITEM && list.get(1).getType() == Constants.ITEM) { + Item leftItem = (Item) list.get(0); + Item rightItem = (Item) list.get(1); + RelationshipType relationshipType = relationshipTypeService + .find(context, Integer.parseInt(req.getParameter("relationshipType"))); - EPerson ePerson = context.getCurrentUser(); - if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) || - authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { - relationship.setLeftItem(leftItem); - relationship.setRightItem(rightItem); - relationship.setRelationshipType(relationshipType); - relationship = relationshipService.create(context, relationship); - return relationshipConverter.fromModel(relationship); + EPerson ePerson = context.getCurrentUser(); + if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) || + authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + relationship.setRelationshipType(relationshipType); + relationship = relationshipService.create(context, relationship); + return relationshipConverter.fromModel(relationship); + } else { + throw new AccessDeniedException("You do not have write rights on this relationship's items"); + } } else { - throw new AccessDeniedException("You do not have write rights on this relationship's items"); + throw new UnprocessableEntityException("The given items in the request were not valid items"); } + } @Override protected RelationshipRest put(Context context, HttpServletRequest request, String apiCategory, String model, - Integer id, - JsonNode jsonNode) + Integer id, List dSpaceObjects) throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException { - HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest(); - ObjectMapper mapper = new ObjectMapper(); - RelationshipRest relationshipRest = null; - try { - relationshipRest = mapper.readValue(jsonNode.toString(), RelationshipRest.class); - } catch (IOException e) { - throw new UnprocessableEntityException("error parsing the body"); - } Relationship relationship = relationshipService.find(context, id); if (relationship == null) { throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); } - Item leftItem = itemService.find(context, UUIDUtils.fromString(req.getParameter("leftItem"))); - Item rightItem = itemService.find(context, UUIDUtils.fromString(req.getParameter("rightItem"))); - RelationshipType relationshipType = relationshipTypeService - .find(context, Integer.parseInt(req.getParameter("relationshipType"))); - if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) || - authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { - relationship.setId(relationshipRest.getId()); - relationship.setLeftItem(leftItem); - relationship.setRightItem(rightItem); + if (dSpaceObjects.size() == 2 && dSpaceObjects.get(0).getType() == Constants.ITEM + && dSpaceObjects.get(1).getType() == Constants.ITEM) { + Item leftItem = (Item) dSpaceObjects.get(0); + Item rightItem = (Item) dSpaceObjects.get(1); - relationship.setRelationshipType(relationshipType); - if (relationshipRest.getLeftPlace() != -1) { - relationship.setLeftPlace(relationshipRest.getLeftPlace()); + if (authorizeService.authorizeActionBoolean(context, leftItem, Constants.WRITE) || + authorizeService.authorizeActionBoolean(context, rightItem, Constants.WRITE)) { + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + + relationshipService.updatePlaceInRelationship(context, relationship); + relationshipService.update(context, relationship); + + return relationshipConverter.fromModel(relationship); + } else { + throw new AccessDeniedException("You do not have write rights on this relationship's items"); } - if (relationshipRest.getRightPlace() != -1) { - relationship.setRightPlace(relationshipRest.getRightPlace()); - } - - relationshipService.updatePlaceInRelationship(context, relationship); - relationshipService.update(context, relationship); - - return relationshipConverter.fromModel(relationship); } else { - throw new AccessDeniedException("You do not have write rights on this relationship's items"); + throw new UnprocessableEntityException("The given items in the request were not valid"); } + } @Override diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java index afbc3d243a..3677066519 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java @@ -16,9 +16,15 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import java.util.Scanner; + +import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; +import org.apache.log4j.Logger; import org.dspace.app.rest.exception.PaginationException; import org.dspace.app.rest.exception.RepositoryNotFoundException; import org.dspace.app.rest.model.AuthorityRest; @@ -30,7 +36,11 @@ import org.dspace.app.rest.model.RestAddressableModel; import org.dspace.app.rest.model.hateoas.DSpaceResource; import org.dspace.app.rest.repository.DSpaceRestRepository; import org.dspace.app.rest.repository.LinkRestRepository; +import org.dspace.content.DSpaceObject; +import org.dspace.content.service.DSpaceObjectService; import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.util.UUIDUtils; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -48,9 +58,16 @@ import org.springframework.web.multipart.MultipartFile; */ @Component public class Utils { + + private static final Logger log = Logger.getLogger(Utils.class); + @Autowired ApplicationContext applicationContext; + @Autowired(required = true) + private List> dSpaceObjectServices; + + public Page getPage(List fullContents, Pageable pageable) { int total = fullContents.size(); List pageContent = null; @@ -219,4 +236,60 @@ public class Utils { return multipartFile.getName(); } } + + private List constructDSpaceObjectList(Context context, + HttpServletRequest request) throws IOException { + List list = readFromRequest(request); + + List dSpaceObjects = new LinkedList<>(); + for (String string : list) { + String uuid = string.substring(string.lastIndexOf('/') + 1); + try { + for (DSpaceObjectService dSpaceObjectService : dSpaceObjectServices) { + DSpaceObject dSpaceObject = dSpaceObjectService.find(context, UUIDUtils.fromString(uuid)); + if (dSpaceObject != null) { + dSpaceObjects.add(dSpaceObject); + break; + } + } + } catch (SQLException e) { + log.error(e.getMessage(), e); + } + + } + return dSpaceObjects; + } + + private List readFromRequest(HttpServletRequest request) throws IOException { + List list = new LinkedList<>(); + Scanner scanner = new Scanner(request.getInputStream()); + + try { + + while (scanner.hasNextLine()) { + + String line = scanner.nextLine(); + if (org.springframework.util.StringUtils.hasText(line)) { + list.add(line); + } + } + + } finally { + scanner.close(); + } + return list; + } + + + /** + * This method will retrieve a list of DSpaceObjects from the Request by reading in the Request's InputStream + * with a Scanner and searching the InputStream for UUIDs which will then be resolved to a DSpaceObject. + * These will all be added to a list and returned by this method. + * @param request The request of which the InputStream will be used + * @return The list of DSpaceObjects that we could find in the InputStream + * @throws IOException If something goes wrong + */ + public List getdSpaceObjectsFromRequest(HttpServletRequest request) throws IOException { + return constructDSpaceObjectList(ContextUtil.obtainContext(request), request); + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java index 677fdab754..ff8043b14b 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EPersonRestRepositoryIT.java @@ -69,7 +69,6 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest { .content(mapper.writeValueAsBytes(data)) .contentType(contentType)) .andExpect(status().isCreated()) - .andExpect(content().contentType(contentType)) .andExpect(jsonPath("$", Matchers.allOf( hasJsonPath("$.uuid", not(empty())), // is it what you expect? EPerson.getName() returns the email... diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 52073e0dd1..335c83254a 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -11,13 +11,16 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.io.File; import java.util.Iterator; import java.util.List; +import java.util.Map; +import com.fasterxml.jackson.databind.ObjectMapper; import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; import org.dspace.app.rest.builder.ItemBuilder; @@ -257,15 +260,13 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") - .param("leftItem", publication.getID().toString()) - .param("rightItem", author1.getID().toString()) .param("relationshipType", - isAuthorOfPublicationRelationshipType.getID() - .toString()) - .contentType(MediaType.APPLICATION_JSON).content( - "{\"id\":530,\"leftId\":\"77877343-3f75-4c33-9492" + - "-6ed7c98ed84e\",\"relationshipTypeId\":0,\"rightId\":\"423d0eda-b808-4b87-97ae-b85fe9d59418\"," + - "\"leftPlace\":1,\"rightPlace\":1}")) + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -323,15 +324,13 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") - .param("leftItem", publication.getID().toString()) - .param("rightItem", author1.getID().toString()) .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.APPLICATION_JSON).content( - "{\"id\":530,\"leftId\":\"77877343-3f75-4c33-9492" + - "-6ed7c98ed84e\",\"relationshipTypeId\":0,\"rightId\":\"423d0eda-b808-4b87-97ae-b85fe9d59418\"," + - "\"leftPlace\":1,\"rightPlace\":1}")) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -388,17 +387,90 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") - .param("leftItem", publication.getID().toString()) - .param("rightItem", author1.getID().toString()) .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.APPLICATION_JSON).content( - "{\"id\":530,\"leftId\":\"77877343-3f75-4c33-9492" + - "-6ed7c98ed84e\",\"relationshipTypeId\":0,\"rightId\":\"423d0eda-b808-4b87-97ae-b85fe9d59418\"," + - "\"leftPlace\":1,\"rightPlace\":1}")) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isForbidden()) .andReturn(); } + + @Test + public void putRelationshipAccess() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + String token = getAuthToken(admin.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.rightId", is(author2.getID().toString()))); + + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java index 885ad2d123..c1b5b6eef1 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -444,19 +444,22 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration // create a workspaceitem explicitly in the col1 getClient(authToken).perform(post("/api/submission/workspaceitems") - .param("collection", col1.getID().toString())) + .param("collection", col1.getID().toString()) + .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); // create a workspaceitem explicitly in the col2 getClient(authToken).perform(post("/api/submission/workspaceitems") - .param("collection", col2.getID().toString())) + .param("collection", col2.getID().toString()) + .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col2.getID().toString()))); // create a workspaceitem without an explicit collection, this will go in the first valid collection for the // user: the col1 - getClient(authToken).perform(post("/api/submission/workspaceitems")) + getClient(authToken).perform(post("/api/submission/workspaceitems") + .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); @@ -629,7 +632,8 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration // create an empty workspaceitem explicitly in the col1, check validation on creation getClient(authToken).perform(post("/api/submission/workspaceitems") - .param("collection", col1.getID().toString())) + .param("collection", col1.getID().toString()) + .contentType(org.springframework.http.MediaType.APPLICATION_JSON)) .andExpect(status().isCreated()) .andExpect(jsonPath("$.status", is(false))) // title and author are required in the first panel From f2b3f7027cb80ed7c2565cce1c7de473c09df5bb Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Wed, 6 Feb 2019 16:12:47 +0100 Subject: [PATCH 092/188] Support relationships using a uri-list: merge --- .../RelationshipRestRepository.java | 4 +- .../rest/RelationshipRestRepositoryIT.java | 150 +++++++----------- 2 files changed, 62 insertions(+), 92 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 3d30102dd3..87c44203f7 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -146,8 +146,8 @@ public class RelationshipRestRepository extends DSpaceRestRepository Date: Thu, 7 Feb 2019 12:55:02 +0100 Subject: [PATCH 093/188] Check for null values Use typed Maps --- .../org/dspace/content/ItemServiceImpl.java | 39 ++++++++++++------- .../virtual/VirtualMetadataPopulator.java | 14 +++---- 2 files changed, 30 insertions(+), 23 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 5b37a1ae60..31fecd2620 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1379,22 +1379,23 @@ prevent the generation of resource policy entry values with null dspace_object a throws SQLException { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); - HashMap hashMaps = new HashMap<>(); + HashMap hashMaps; String relationName = ""; Item otherItem = null; int place = 0; if (StringUtils.equals(relationshipType.getLeftType().getLabel(), entityType)) { - hashMaps = (HashMap) virtualMetadataPopulator - .getMap().get(relationshipType.getLeftLabel()); + hashMaps = virtualMetadataPopulator.getMap().get(relationshipType.getLeftLabel()); otherItem = relationship.getRightItem(); relationName = relationship.getRelationshipType().getLeftLabel(); place = relationship.getLeftPlace(); } else if (StringUtils.equals(relationshipType.getRightType().getLabel(), entityType)) { - hashMaps = (HashMap) virtualMetadataPopulator - .getMap().get(relationshipType.getRightLabel()); + hashMaps = virtualMetadataPopulator.getMap().get(relationshipType.getRightLabel()); otherItem = relationship.getLeftItem(); relationName = relationship.getRelationshipType().getRightLabel(); place = relationship.getRightPlace(); + } else { + //No virtual metadata can be created + return resultingMetadataValueList; } if (hashMaps != null && enableVirtualMetadata) { @@ -1402,8 +1403,11 @@ prevent the generation of resource policy entry values with null dspace_object a otherItem, relationName, relationship.getID(), place)); } - resultingMetadataValueList - .add(getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID())); + RelationshipMetadataValue relationMetadataFromOtherItem = + getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID()); + if (relationMetadataFromOtherItem != null) { + resultingMetadataValueList.add(relationMetadataFromOtherItem); + } return resultingMetadataValueList; } @@ -1420,11 +1424,13 @@ prevent the generation of resource policy entry values with null dspace_object a for (String value : virtualBean.getValues(context, otherItem)) { RelationshipMetadataValue metadataValue = constructMetadataValue(context, key); - metadataValue = constructResultingMetadataValue(item, value, metadataValue, relationshipId); - metadataValue.setUseForPlace(virtualBean.getUseForPlace()); - metadataValue.setPlace(place); - if (StringUtils.isNotBlank(metadataValue.getValue())) { - resultingMetadataValueList.add(metadataValue); + if (metadataValue != null) { + metadataValue = constructResultingMetadataValue(item, value, metadataValue, relationshipId); + metadataValue.setUseForPlace(virtualBean.getUseForPlace()); + metadataValue.setPlace(place); + if (StringUtils.isNotBlank(metadataValue.getValue())) { + resultingMetadataValueList.add(metadataValue); + } } } } @@ -1437,9 +1443,12 @@ prevent the generation of resource policy entry values with null dspace_object a RelationshipMetadataValue metadataValue = constructMetadataValue(context, MetadataSchemaEnum.RELATION .getName() + "." + relationName); - metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId); - metadataValue.setValue(otherItem.getID().toString()); - return metadataValue; + if (metadataValue != null) { + metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId); + metadataValue.setValue(otherItem.getID().toString()); + return metadataValue; + } + return null; } private String getEntityTypeStringFromMetadata(List list) { diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java index 78ee7b0b41..64663f3574 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java @@ -22,13 +22,13 @@ public class VirtualMetadataPopulator { /** * The map that holds this representation */ - private Map map; + private Map> map; /** * Standard setter for the map * @param map The map to be used in the VirtualMetadataPopulator */ - public void setMap(Map map) { + public void setMap(Map> map) { this.map = map; } @@ -36,18 +36,16 @@ public class VirtualMetadataPopulator { * Standard getter for the map * @return The map that is used in the VirtualMetadataPopulator */ - public Map getMap() { + public Map> getMap() { return map; } public boolean isUseForPlaceTrueForRelationshipType(RelationshipType relationshipType, boolean isLeft) { - HashMap hashMaps = new HashMap<>(); + HashMap hashMaps; if (isLeft) { - hashMaps = (HashMap) this - .getMap().get(relationshipType.getLeftLabel()); + hashMaps = this.getMap().get(relationshipType.getLeftLabel()); } else { - hashMaps = (HashMap) this - .getMap().get(relationshipType.getRightLabel()); + hashMaps = this.getMap().get(relationshipType.getRightLabel()); } if (hashMaps != null) { for (Map.Entry entry : hashMaps.entrySet()) { From 37c3ab9e17aa5804357cd1283c23be6218285f1b Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 18 Feb 2019 09:23:39 +0100 Subject: [PATCH 094/188] Applied feedback --- .../org/dspace/content/ItemServiceImpl.java | 36 ++++++++++--------- .../content/RelationshipMetadataValue.java | 11 ++++++ .../content/RelationshipServiceImpl.java | 16 ++++----- .../org/dspace/content/virtual/Collected.java | 10 +++++- .../app/rest/RestResourceController.java | 7 ++-- .../RelationshipRestRepository.java | 21 +++++------ .../java/org/dspace/app/rest/utils/Utils.java | 33 ++++++++++++++--- 7 files changed, 88 insertions(+), 46 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 19ce31c0d5..1a5f7954d0 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1428,26 +1428,28 @@ prevent the generation of resource policy entry values with null dspace_object a } private RelationshipMetadataValue constructMetadataValue(Context context, String key) { + String[] splittedKey = key.split("\\."); + RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); + String metadataSchema = splittedKey.length > 0 ? splittedKey[0] : null; + String metadataElement = splittedKey.length > 1 ? splittedKey[1] : null; + String metadataQualifier = splittedKey.length > 2 ? splittedKey[2] : null; + MetadataField metadataField = null; try { - String[] splittedKey = key.split("\\."); - RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); - String metadataSchema = splittedKey.length > 0 ? splittedKey[0] : null; - String metadataElement = splittedKey.length > 1 ? splittedKey[1] : null; - String metadataQualifier = splittedKey.length > 2 ? splittedKey[2] : null; - MetadataField metadataField = metadataFieldService + metadataField = metadataFieldService .findByElement(context, metadataSchema, metadataElement, metadataQualifier); - if (metadataField == null) { - log.error("A MetadataValue was attempted to construct with MetadataField for parameters: " + - "metadataschema: {}, metadataelement: {}, metadataqualifier: {}", - metadataSchema, metadataElement, metadataQualifier); - return null; - } - metadataValue.setMetadataField(metadataField); - metadataValue.setLanguage(Item.ANY); - return metadataValue; } catch (SQLException e) { - log.error(e.getMessage(), e); + log.error("Could not find element with MetadataSchema: " + metadataSchema + + ", MetadataElement: " + metadataElement + " and MetadataQualifier: " + metadataQualifier, e); + return null; } - return null; + if (metadataField == null) { + log.error("A MetadataValue was attempted to construct with MetadataField for parameters: " + + "metadataschema: {}, metadataelement: {}, metadataqualifier: {}", + metadataSchema, metadataElement, metadataQualifier); + return null; + } + metadataValue.setMetadataField(metadataField); + metadataValue.setLanguage(Item.ANY); + return metadataValue; } } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index fb46431801..fc62b86da6 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -22,6 +22,17 @@ public class RelationshipMetadataValue extends MetadataValue { */ private boolean useForPlace; + /** + * This property determines whether this RelationshipMetadataValue should be used in place calculation or not. + * This is retrieved from Spring configuration when constructing RelationshipMetadataValues. This Spring + * configuration is located in the core-services.xml configuration file. + * Putting this property on true will imply that we're now mixing plain-text metadatavalues with the + * metadatavalues that are constructed through Relationships with regards to the place attribute. + * For example, currently the RelationshipMetadataValue dc.contributor.author that is constructed through a + * Relationship for a Publication will have its useForPlace set to true. This means that the place + * calculation will take both these RelationshipMetadataValues into account together with the normal + * plain text metadatavalues. + */ public boolean isUseForPlace() { return useForPlace; } diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 88239bf933..a12c92f0a1 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -212,15 +212,14 @@ public class RelationshipServiceImpl implements RelationshipService { public void update(Context context, List relationships) throws SQLException, AuthorizeException { if (CollectionUtils.isNotEmpty(relationships)) { - // Check authorisation - only administrators can change formats - if (!authorizeService.isAdmin(context)) { - throw new AuthorizeException( - "Only administrators can modify relationship"); - } - for (Relationship relationship : relationships) { - if (isRelationshipValidToCreate(context, relationship)) { - relationshipDAO.save(context, relationship); + if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) || + authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) { + if (isRelationshipValidToCreate(context, relationship)) { + relationshipDAO.save(context, relationship); + } + } else { + throw new AuthorizeException("You do not have write rights on this relationship's items"); } } } @@ -228,6 +227,7 @@ public class RelationshipServiceImpl implements RelationshipService { public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException { if (isRelationshipValidToDelete(context, relationship)) { + // To delete a relationship, a user must have WRITE permissions on one of the related Items if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) || authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) { relationshipDAO.delete(context, relationship); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java index e064924acf..d913fa4e9d 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -29,7 +29,15 @@ public class Collected implements VirtualBean { private ItemService itemService; /** - * The boolean value indicating whether this field should be used for place or not + * This property determines whether this RelationshipMetadataValue should be used in place calculation or not. + * This is retrieved from Spring configuration when constructing RelationshipMetadataValues. This Spring + * configuration is located in the core-services.xml configuration file. + * Putting this property on true will imply that we're now mixing plain-text metadatavalues with the + * metadatavalues that are constructed through Relationships with regards to the place attribute. + * For example, currently the RelationshipMetadataValue dc.contributor.author that is constructed through a + * Relationship for a Publication will have its useForPlace set to true. This means that the place + * calculation will take both these RelationshipMetadataValues into account together with the normal + * plain text metadatavalues. */ private boolean useForPlace; /** diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index 1e8de95d61..91b679737d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -474,11 +474,12 @@ public class RestResourceController implements InitializingBean { checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; + List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); try { - List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); modelObject = repository.createAndReturn(dSpaceObjectList); - } catch (ClassCastException | IOException e) { - log.error(e.getMessage(), e); + } catch (ClassCastException e) { + log.error("Something went wrong whilst creating the object for apiCategory: " + apiCategory + + " and model: " + model, e); return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR); } if (modelObject == null) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 0c64ebc098..997e5abfc9 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -30,7 +30,6 @@ import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.dspace.eperson.EPerson; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -92,6 +91,7 @@ public class RelationshipRestRepository extends DSpaceRestRepository list) throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { @@ -104,17 +104,15 @@ public class RelationshipRestRepository extends DSpaceRestRepository constructDSpaceObjectList(Context context, - HttpServletRequest request) throws IOException { - List list = readFromRequest(request); + /** + * This method will construct a List of DSpaceObjects by executing the method + * {@link Utils#readFromRequest(HttpServletRequest)} and fetching the List of Strings from the request. + * The method will iterate over this list of Strings and parse the String to retrieve the UUID from it. + * It will then look through all the DSpaceObjectServices to try and match this UUID to a DSpaceObject. + * If one is found, this DSpaceObject is added to the List of DSpaceObjects that we will return. + * @param context The relevant DSpace context + * @param request The request out of which we'll create the List of DSpaceObjects + * @return The resulting list of DSpaceObjects that we parsed out of the request + */ + private List constructDSpaceObjectList(Context context, HttpServletRequest request) { + List list = null; + try { + list = readFromRequest(request); + } catch (IOException e) { + log.error("Something went wrong with reading in the inputstream from the request", e); + } List dSpaceObjects = new LinkedList<>(); for (String string : list) { + if (string.endsWith("/")) { + string = string.substring(0, string.length() - 1); + } String uuid = string.substring(string.lastIndexOf('/') + 1); try { for (DSpaceObjectService dSpaceObjectService : dSpaceObjectServices) { @@ -253,13 +270,19 @@ public class Utils { } } } catch (SQLException e) { - log.error(e.getMessage(), e); + log.error("Could not find DSpaceObject for UUID: " + uuid, e); } } return dSpaceObjects; } + /** + * This method reads lines from the request's InputStream and will add this to a list of Strings. + * @param request The request from which the InputStream will be fetched + * @return A list of String constructed from the request's InputStream + * @throws IOException If something goes wrong + */ private List readFromRequest(HttpServletRequest request) throws IOException { List list = new LinkedList<>(); Scanner scanner = new Scanner(request.getInputStream()); @@ -289,7 +312,7 @@ public class Utils { * @return The list of DSpaceObjects that we could find in the InputStream * @throws IOException If something goes wrong */ - public List getdSpaceObjectsFromRequest(HttpServletRequest request) throws IOException { + public List getdSpaceObjectsFromRequest(HttpServletRequest request) { return constructDSpaceObjectList(ContextUtil.obtainContext(request), request); } } From 7f194dfa955b64f0758d0a73ab451e68a5377218 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 20 Feb 2019 11:28:34 +0100 Subject: [PATCH 095/188] Applied feedback --- .../content/DSpaceObjectServiceImpl.java | 6 +- .../org/dspace/content/ItemServiceImpl.java | 33 ++- .../content/RelationshipServiceImpl.java | 6 + .../virtual/VirtualMetadataPopulator.java | 7 + .../RelationshipRestRepository.java | 19 +- .../rest/RelationshipRestRepositoryIT.java | 276 +++++++++++++----- 6 files changed, 250 insertions(+), 97 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java index 56670ed9a4..c88661df9b 100644 --- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java @@ -249,7 +249,7 @@ public abstract class DSpaceObjectServiceImpl implements } } MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField); - // TODO Set place to list length + //Set place to list length metadataValue.setPlace(this.getMetadata(dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY).size()); metadataValue.setLanguage(lang == null ? null : lang.trim()); @@ -560,6 +560,10 @@ public abstract class DSpaceObjectServiceImpl implements } else { metadataValues = dso.getMetadata(); } + //This inline sort function will sort the MetadataValues based on their place in ascending order + //If two places are the same then the MetadataValue instance will be placed before the + //RelationshipMetadataValue instance. + //This is done to ensure that the order is correct. metadataValues.sort(new Comparator() { public int compare(MetadataValue o1, MetadataValue o2) { int compare = o1.getPlace() - o2.getPlace(); 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 332e92741a..df2969de0a 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1314,7 +1314,7 @@ prevent the generation of resource policy entry values with null dspace_object a } } catch (SQLException e) { - log.error(e, e); + log.error("Lookup for Relationships for item with uuid: " + item.getID() + " caused DSpace to crash", e); } return fullMetadataValueList; } @@ -1357,6 +1357,12 @@ prevent the generation of resource policy entry values with null dspace_object a } + /** + * This method will sort the List of MetadataValue objects based on the MetadataSchema, MetadataField Element, + * MetadataField Qualifier and MetadataField Place in that order. + * @param listToReturn The list to be sorted + * @return The list sorted on those criteria + */ private List sortMetadataValueList(List listToReturn) { Comparator comparator = Comparator.comparing( metadataValue -> metadataValue.getMetadataField().getMetadataSchema().getName(), @@ -1373,6 +1379,8 @@ prevent the generation of resource policy entry values with null dspace_object a return listToReturn; } + //This method processes the Relationship of an Item and will return a list of RelationshipMetadataValue objects + //that are generated for this specfic relationship for the item through the config in VirtualMetadataPopulator private List handleItemRelationship(Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata) @@ -1399,23 +1407,26 @@ prevent the generation of resource policy entry values with null dspace_object a } if (hashMaps != null && enableVirtualMetadata) { - resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMappping(context, item, hashMaps, - otherItem, relationName, - relationship.getID(), place)); + resultingMetadataValueList.addAll(handleRelationshipTypeMetadataMapping(context, item, hashMaps, + otherItem, relationName, + relationship.getID(), place)); } RelationshipMetadataValue relationMetadataFromOtherItem = - getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID()); + getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID()); if (relationMetadataFromOtherItem != null) { resultingMetadataValueList.add(relationMetadataFromOtherItem); } return resultingMetadataValueList; } - private List handleRelationshipTypeMetadataMappping(Context context, Item item, - HashMap - hashMaps, - Item otherItem, String relationName, - Integer relationshipId, int place) + //This method will retrieve a list of RelationshipMetadataValue objects based on the config passed along in the + //hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects + //and the keys of the hashmap will be used to construct the RelationshipMetadataValue object. + private List handleRelationshipTypeMetadataMapping(Context context, Item item, + HashMap + hashMaps, + Item otherItem, String relationName, + Integer relationshipId, int place) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); for (Map.Entry entry : hashMaps.entrySet()) { @@ -1475,6 +1486,8 @@ prevent the generation of resource policy entry values with null dspace_object a return metadataValue; } + //This method will construct a RelationshipMetadataValue object with proper schema, element and qualifier based + //on the key String parameter passed along to it private RelationshipMetadataValue constructMetadataValue(Context context, String key) { String[] splittedKey = key.split("\\."); RelationshipMetadataValue metadataValue = new RelationshipMetadataValue(); diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 6d8d3a285d..84d4891364 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -86,6 +86,8 @@ public class RelationshipServiceImpl implements RelationshipService { false); context.turnOffAuthorisationSystem(); + //If useForPlace for the leftlabel is false for the relationshipType, + // we need to sort the relationships here based on leftplace. if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), true)) { if (!leftRelationships.isEmpty()) { leftRelationships.sort(Comparator.comparingInt(Relationship::getLeftPlace)); @@ -101,6 +103,8 @@ public class RelationshipServiceImpl implements RelationshipService { } + //If useForPlace for the rightLabel is false for the relationshipType, + // we need to sort the relationships here based on the rightplace. if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), false)) { if (!rightRelationships.isEmpty()) { rightRelationships.sort(Comparator.comparingInt(Relationship::getRightPlace)); @@ -132,6 +136,8 @@ public class RelationshipServiceImpl implements RelationshipService { } + //Sets the places for the Relationship properly if the updatePlaceInRelationship was called for a new creation + //of this Relationship private void handleCreationPlaces(Context context, Relationship relationship) throws SQLException { List leftRelationships; List rightRelationships; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java index 64663f3574..72bf89c002 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java @@ -40,6 +40,13 @@ public class VirtualMetadataPopulator { return map; } + /** + * This method will return a boolean indicating whether the useForPlace is true or false for the given + * RelationshipType for the left or right label as indicated by the second parameter. + * @param relationshipType The relationshipType for which this should be checked + * @param isLeft The boolean indicating whether to check the left or the right label + * @return A boolean indicating whether the useForPlace is true or not for the given parameters + */ public boolean isUseForPlaceTrueForRelationshipType(RelationshipType relationshipType, boolean isLeft) { HashMap hashMaps; if (isLeft) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 8de72ee0a3..e76279eac2 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -30,6 +30,7 @@ import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -104,15 +105,21 @@ public class RelationshipRestRepository extends DSpaceRestRepository map = mapper.readValue(content, Map.class); String firstRelationshipIdString = String.valueOf(map.get("id")); + // Here we call the relationship and verify that the relationship's leftplace is 0 getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + // Make sure we grab the latest instance of the Item from the database publication = itemService.find(context, publication.getID()); + // Add a plain text dc.contributor.author value itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text"); itemService.update(context, publication); List list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + // Ensure that the list of dc.contributor.author values now holds two values ("Smith, Donald" and "plain text") assertEquals(2, list.size()); for (MetadataValue mdv : list) { + // Here we want to ensure that the "plain text" metadatavalue has place 1 because it was added later than + // the Relationship, so the "Smith, Donald" should have place 0 and "plain text" should have place 1 if (StringUtils.equals(mdv.getValue(), "plain text")) { assertEquals(1, mdv.getPlace()); } } + // Testing what was describe above MetadataValue author0MD = list.get(0); assertEquals("Smith, Donald", author0MD.getValue()); MetadataValue author1MD = list.get(1); assertEquals("plain text", author1MD.getValue()); + // Verfiy the leftPlace of our relationship is still 0. getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + // Create another Relationship for the Publication, thus creating a third dc.contributor.author mdv mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) .andExpect(status().isCreated()) .andReturn(); content = mvcResult.getResponse().getContentAsString(); map = mapper.readValue(content, Map.class); + // Grab the ID for the second relationship for future calling in the rest String secondRelationshipIdString = String.valueOf(map.get("id")); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + // Ensure that we now have three dc.contributor.author mdv ("Smith, Donald", "plain text", "Smith, Maria" + // In that order which will be checked below the rest call assertEquals(3, list.size()); + // Perform the REST call to the relationship to ensure its leftPlace is 2 even though it's only the second + // Relationship. Note that leftPlace 1 was skipped due to the dc.contributor.author plain text value and + // This is expected behaviour and should be tested getClient(adminToken).perform(get("/api/core/relationships/" + secondRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); @@ -530,15 +568,16 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT MetadataValue author2MD = list.get(2); assertEquals("Smith, Maria", author2MD.getValue()); + // Ensure we have the latest instance of the Item from the database publication = itemService.find(context, publication.getID()); + // Add a fourth dc.contributor.author mdv itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); -// itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); -// itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text four"); -// itemService.update(context, publication); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + // Assert that the list of dc.contributor.author mdv is now of size 4 in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two" assertEquals(4, list.size()); for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text two")) { @@ -556,27 +595,37 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT assertEquals("plain text two", author3MD.getValue()); + // Create the third Relationship thus adding a fifth dc.contributor.author mdv mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) .andExpect(status().isCreated()) .andReturn(); content = mvcResult.getResponse().getContentAsString(); map = mapper.readValue(content, Map.class); + // Save the third Relationship's ID for future calling String thirdRelationshipIdString = String.valueOf(map.get("id")); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); + // Assert that our dc.contributor.author mdv list is now of size 5 assertEquals(5, list.size()); + // Assert that the third Relationship has leftPlace 4, even though 3 relationships were created. + // This is because the plain text values 'occupy' place 1 and 3. getClient(adminToken).perform(get("/api/core/relationships/" + thirdRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); + // Assert that the list is of size 5 and in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe" + // Thus the order they were added in author0MD = list.get(0); assertEquals("Smith, Donald", author0MD.getValue()); author1MD = list.get(1); @@ -588,6 +637,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT MetadataValue author4MD = list.get(4); assertEquals("Maybe, Maybe", author4MD.getValue()); + // The following additions of Metadata will perform the same sequence of logic and tests as described above publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); @@ -669,6 +719,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT assertEquals(20, list.size()); //also includes type and 3 relation.isAuthorOfPublication values } + /** + * This method will test the deletion of a plain-text metadatavalue to then + * verify that the place property is still being handled correctly. + * @throws Exception + */ @Test public void deleteMetadataValueAndValidatePlace() throws Exception { @@ -720,15 +775,18 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); + // First create the structure of 5 metadatavalues just like the additions test. MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); ObjectMapper mapper = new ObjectMapper(); @@ -762,10 +820,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -779,11 +839,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); -// itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); -// itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text four"); -// itemService.update(context, publication); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -797,10 +854,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -824,6 +883,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } } + // Now we will have a dc.contributor.author metadatavalue list of size 5 in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe" List authors = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); List listToRemove = new LinkedList<>(); for (MetadataValue metadataValue : authors) { @@ -831,6 +892,9 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT listToRemove.add(metadataValue); } } + + // Remove the "plain text two" metadatavalue. Ensure that all mdvs prior to that in the list are unchanged + // And ensure that the ones coming after this mdv have its place lowered by one. itemService.removeMetadataValues(context, publication, listToRemove); itemService.update(context, publication); @@ -861,6 +925,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * This method will test the deletion of a Relationship to then + * verify that the place property is still being handled correctly. + * @throws Exception + */ @Test public void deleteRelationshipsAndValidatePlace() throws Exception { @@ -912,15 +981,18 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); + // First create the structure of 5 metadatavalues just like the additions test. MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); ObjectMapper mapper = new ObjectMapper(); @@ -954,10 +1026,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -986,10 +1060,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author3.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -1014,6 +1090,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + // Now we will have a dc.contributor.author metadatavalue list of size 5 in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe" + + // Now we delete the second relationship, the one that made "Smith, Maria" metadatavalue + // Ensure that all metadatavalues before this one in the list still hold the same place + // Ensure that all the metadatavalues after this one have their place lowered by one getClient(adminToken).perform(delete("/api/core/relationships/" + secondRelationshipIdString)); getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) @@ -1052,6 +1134,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * This test will simply add Relationships between Items with a useForPlace attribute set to false for the + * RelationshipType. We want to test that the Relationships that are created will still have their place + * attributes handled in a correct way + * @throws Exception + */ @Test public void addRelationshipsNotUseForPlace() throws Exception { @@ -1101,14 +1189,18 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); + // This is essentially a sequence of adding Relationships by POST and then checking with GET to see + // if the place is being set properly. MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); ObjectMapper mapper = new ObjectMapper(); @@ -1124,10 +1216,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID().toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); mapper = new ObjectMapper(); @@ -1143,10 +1237,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID().toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + author3.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + author3.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); mapper = new ObjectMapper(); @@ -1160,6 +1256,13 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(jsonPath("rightPlace", is(2))); } + /** + * This test will simply add Relationships between Items with a useForPlace attribute set to false for the + * RelationshipType. We want to test that the Relationships that are created will still have their place + * attributes handled in a correct way. It will then delete a Relationship and once again ensure that the place + * attributes are being handled correctly. + * @throws Exception + */ @Test public void addAndDeleteRelationshipsNotUseForPlace() throws Exception { @@ -1209,14 +1312,18 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); + // This is essentially a sequence of adding Relationships by POST and then checking with GET to see + // if the place is being set properly. MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); ObjectMapper mapper = new ObjectMapper(); @@ -1232,10 +1339,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID().toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); mapper = new ObjectMapper(); @@ -1251,10 +1360,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isOrgUnitOfPersonRelationshipType.getID().toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + author3.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + author3.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + orgUnit1.getID())) .andExpect(status().isCreated()) .andReturn(); mapper = new ObjectMapper(); @@ -1267,6 +1378,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("rightPlace", is(2))); + // Here we will delete the secondRelationship and then verify that the others have their place handled properly getClient(adminToken).perform(delete("/api/core/relationships/" + secondRelationshipIdString)); getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) @@ -1328,10 +1440,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -1341,12 +1455,14 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String id = String.valueOf(map.get("id")); MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) - .andExpect(status().isOk()) - .andReturn(); + .contentType(MediaType.parseMediaType + (org.springframework.data.rest.webmvc.RestMediaTypes + .TEXT_URI_LIST_VALUE)) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isOk()) + .andReturn(); getClient(token).perform(get("/api/core/relationships/" + id)) .andExpect(status().isOk()) From a0ebd616f23309af201263819db5089633cf3a2b Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 20 Feb 2019 13:11:39 +0100 Subject: [PATCH 096/188] Processed feedback --- .../RelationshipRestRepository.java | 22 +- .../rest/RelationshipRestRepositoryIT.java | 451 +++++++++++++++++- 2 files changed, 470 insertions(+), 3 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 997e5abfc9..0363c94944 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -135,8 +135,7 @@ public class RelationshipRestRepository extends DSpaceRestRepository map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.rightId", is(author2.getID().toString()))); + + } + + @Test + public void putRelationshipNewRightItemWriteAccess() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("uiytirthery@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, author1, Constants.WRITE, user); + authorizeService.addPolicy(context, author2, Constants.WRITE, user); + + String token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.rightId", is(author2.getID().toString()))); + + } + + + @Test + public void putRelationshipLeftItemWriteAccess() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("tturturu@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, publication, Constants.WRITE, user); + + String token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.rightId", is(author2.getID().toString()))); + + } + + @Test + public void putRelationshipNewLeftItemWriteAccess() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + Item publication2 = ItemBuilder.createItem(context, col3) + .withTitle("Publication2") + .withAuthor("Testy, TEstzea") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("tryhrtureery@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, author1, Constants.WRITE, user); + authorizeService.addPolicy(context, publication2, Constants.WRITE, user); + + String token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult = getClient(getAuthToken(admin.getEmail(), password)) + .perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication2.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftId", is(publication2.getID().toString()))); + + } + + + @Test + public void putRelationshipNoAccess() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("ytureye@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + + String token = getAuthToken(admin.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isForbidden()) + .andReturn(); + + } } From 91caed0cf63cf6a608182003f4c81dc1523bf498 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 20 Feb 2019 14:39:32 +0100 Subject: [PATCH 097/188] Refactored tests --- .../rest/RelationshipRestRepositoryIT.java | 378 +++++++++++++----- 1 file changed, 281 insertions(+), 97 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 3dd835885d..18cbd3f851 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -475,7 +475,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } @Test - public void putRelationshipRightItemWriteAccess() throws Exception { + public void putRelationshipWriteAccessOnAuthors() throws Exception { context.turnOffAuthorisationSystem(); @@ -564,7 +564,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } @Test - public void putRelationshipNewRightItemWriteAccess() throws Exception { + public void putRelationshipWriteAccessOnPublication() throws Exception { context.turnOffAuthorisationSystem(); @@ -617,96 +617,6 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT ePersonService.update(context, user); context.setCurrentUser(user); - authorizeService.addPolicy(context, author1, Constants.WRITE, user); - authorizeService.addPolicy(context, author2, Constants.WRITE, user); - - String token = getAuthToken(user.getEmail(), password); - - MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") - .param("relationshipType", - isAuthorOfPublicationRelationshipType.getID() - .toString()) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) - .andExpect(status().isCreated()) - .andReturn(); - - ObjectMapper mapper = new ObjectMapper(); - String content = mvcResult.getResponse().getContentAsString(); - Map map = mapper.readValue(content, Map.class); - String id = String.valueOf(map.get("id")); - - MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) - .contentType(MediaType.parseMediaType("text/uri-list")) - .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + - "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) - .andExpect(status().isOk()) - .andReturn(); - - getClient(token).perform(get("/api/core/relationships/" + id)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.rightId", is(author2.getID().toString()))); - - } - - - @Test - public void putRelationshipLeftItemWriteAccess() 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(); - Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); - Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); - - Item author1 = ItemBuilder.createItem(context, col1) - .withTitle("Author1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald") - .withRelationshipType("Person") - .build(); - - Item author2 = ItemBuilder.createItem(context, col1) - .withTitle("Author2") - .withIssueDate("2017-10-12") - .withAuthor("Smith, Donalaze") - .withRelationshipType("Person") - .build(); - - Item publication = ItemBuilder.createItem(context, col3) - .withTitle("Publication1") - .withAuthor("Testy, TEst") - .withIssueDate("2015-01-01") - .withRelationshipType("Publication") - .build(); - - RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService - .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), - entityTypeService.findByEntityType(context, "Person"), - "isAuthorOfPublication", "isPublicationOfAuthor"); - - - - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("tturturu@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); - context.setCurrentUser(user); - authorizeService.addPolicy(context, publication, Constants.WRITE, user); String token = getAuthToken(user.getEmail(), password); @@ -741,8 +651,9 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + @Test - public void putRelationshipNewLeftItemWriteAccess() throws Exception { + public void putRelationshipWriteAccessOnPublications() throws Exception { context.turnOffAuthorisationSystem(); @@ -770,7 +681,102 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .withRelationshipType("Person") .build(); - Item publication = ItemBuilder.createItem(context, col3) + Item publication1 = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + Item publication2 = ItemBuilder.createItem(context, col3) + .withTitle("Publication2") + .withAuthor("Testy, TEstzeaze") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("tturturu@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, publication1, Constants.WRITE, user); + authorizeService.addPolicy(context, publication2, Constants.WRITE, user); + + String token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication1.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication2.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isOk()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftId", is(publication2.getID().toString()))); + + } + + @Test + public void putRelationshipWriteAccessOnAuthor() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication1 = ItemBuilder.createItem(context, col3) .withTitle("Publication1") .withAuthor("Testy, TEst") .withIssueDate("2015-01-01") @@ -803,7 +809,6 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); - authorizeService.addPolicy(context, publication2, Constants.WRITE, user); String token = getAuthToken(user.getEmail(), password); @@ -814,7 +819,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .toString()) .contentType(MediaType.parseMediaType("text/uri-list")) .content( - "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + publication1.getID() + "\n" + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) .andExpect(status().isCreated()) .andReturn(); @@ -885,7 +890,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT EPerson user = ePersonService.create(context); user.setFirstName(context, "first"); user.setLastName(context, "last"); - user.setEmail("ytureye@email.com"); + user.setEmail("erertertgrdgf@email.com"); user.setCanLogIn(true); user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); ePersonService.setPassword(user, password); @@ -922,4 +927,183 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andReturn(); } + + @Test + public void putRelationshipOnlyAccessOnOneAuthor() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("tjyhrgefdg@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, author1, Constants.WRITE, user); + + String token = getAuthToken(admin.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author2.getID())) + .andExpect(status().isForbidden()) + .andReturn(); + + } + + @Test + public void putRelationshipOnlyAccessOnOnePublication() 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + Collection col3 = CollectionBuilder.createCollection(context, child1).withName("OrgUnits").build(); + + Item author1 = ItemBuilder.createItem(context, col1) + .withTitle("Author1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald") + .withRelationshipType("Person") + .build(); + + Item author2 = ItemBuilder.createItem(context, col1) + .withTitle("Author2") + .withIssueDate("2017-10-12") + .withAuthor("Smith, Donalaze") + .withRelationshipType("Person") + .build(); + + Item publication1 = ItemBuilder.createItem(context, col3) + .withTitle("Publication1") + .withAuthor("Testy, TEst") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + Item publication2 = ItemBuilder.createItem(context, col3) + .withTitle("Publication2") + .withAuthor("Testy, TEstzeaze") + .withIssueDate("2015-01-01") + .withRelationshipType("Publication") + .build(); + + RelationshipType isAuthorOfPublicationRelationshipType = relationshipTypeService + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), + "isAuthorOfPublication", "isPublicationOfAuthor"); + + + + EPerson user = ePersonService.create(context); + user.setFirstName(context, "first"); + user.setLastName(context, "last"); + user.setEmail("tyerzergt@email.com"); + user.setCanLogIn(true); + user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); + ePersonService.setPassword(user, password); + // actually save the eperson to unit testing DB + ePersonService.update(context, user); + context.setCurrentUser(user); + + authorizeService.addPolicy(context, publication1, Constants.WRITE, user); + + String token = getAuthToken(user.getEmail(), password); + + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") + .param("relationshipType", + isAuthorOfPublicationRelationshipType.getID() + .toString()) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication1.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isCreated()) + .andReturn(); + + ObjectMapper mapper = new ObjectMapper(); + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String id = String.valueOf(map.get("id")); + + MvcResult mvcResult2 = getClient(token).perform(put("/api/core/relationships/" + id) + .contentType(MediaType.parseMediaType("text/uri-list")) + .content( + "https://localhost:8080/spring-rest/api/core/items/" + publication2.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + author1.getID())) + .andExpect(status().isForbidden()) + .andReturn(); + + getClient(token).perform(get("/api/core/relationships/" + id)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftId", is(publication1.getID().toString()))); + + } } From 1989cd9ff4741aa9da9e093e2ac336cdadf292bb Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Wed, 20 Feb 2019 17:26:43 +0100 Subject: [PATCH 098/188] JavaDoc --- .../rest/RelationshipRestRepositoryIT.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 18cbd3f851..d0028c6fdf 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -474,6 +474,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 1 and author 2 + * Verify this is possible for a user with WRITE permissions on author 1 and author 2 + */ @Test public void putRelationshipWriteAccessOnAuthors() throws Exception { @@ -563,6 +568,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 1 and author 2 + * Verify this is possible for a user with WRITE permissions on publication 1 + */ @Test public void putRelationshipWriteAccessOnPublication() throws Exception { @@ -652,6 +662,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 2 and author 1 + * Verify this is possible for a user with WRITE permissions on publication 1 and publication 2 + */ @Test public void putRelationshipWriteAccessOnPublications() throws Exception { @@ -747,6 +762,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 2 and author 1 + * Verify this is possible for a user with WRITE permissions on author 1 + */ @Test public void putRelationshipWriteAccessOnAuthor() throws Exception { @@ -844,6 +865,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 1 and author 2 + * Verify this is NOT possible for a user without WRITE permissions + */ @Test public void putRelationshipNoAccess() throws Exception { @@ -928,6 +954,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 1 and author 2 + * Verify this is NOT possible for a user with WRITE permissions on author 1 + */ @Test public void putRelationshipOnlyAccessOnOneAuthor() throws Exception { @@ -1013,6 +1044,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } + /** + * Create a relationship between publication 1 and author 1 + * Change it to a relationship between publication 2 and author 1 + * Verify this is NOT possible for a user with WRITE permissions on publication 1 + */ @Test public void putRelationshipOnlyAccessOnOnePublication() throws Exception { From 65a94cdda7ed64b92d9d2c15dff224e8cff9c4b9 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 21 Feb 2019 09:21:11 +0100 Subject: [PATCH 099/188] Implemented an IT for the text/uri-list parsing --- .../org/dspace/app/rest/UriListParsingIT.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java new file mode 100644 index 0000000000..6e51b61ccd --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java @@ -0,0 +1,86 @@ +/** + * 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.rest; + +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.ItemBuilder; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.utils.Utils; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.core.Constants; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mock.web.MockHttpServletRequest; + +/** + * This test class will test the UriList parsing method in the Utils class + */ +public class UriListParsingIT extends AbstractControllerIntegrationTest { + + @Autowired + protected Utils utils; + + @Test + public void mockRequestTextUriParsingTest() throws Exception { + + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + 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(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. Three public items that are readable by Anonymous with different subjects + Item publicItem1 = ItemBuilder.createItem(context, col1) + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + Item publicItem2 = ItemBuilder.createItem(context, col2) + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); + + context.restoreAuthSystemState(); + + + MockHttpServletRequest mockRequest = new MockHttpServletRequest(); + String uriListString = "https://localhost:8080/spring-rest/api/core/items/" + publicItem1.getID() + "\n" + + "https://localhost:8080/spring-rest/api/core/items/" + publicItem2.getID(); + mockRequest.setContentType("text/uri-list"); + mockRequest.setContent(uriListString.getBytes()); + List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(mockRequest); + assertThat("DSpaceObject List is of size 2" ,dSpaceObjectList.size(), equalTo(2)); + assertThat("DSpaceObject 1 is an item", dSpaceObjectList.get(0).getType(), equalTo(Constants.ITEM)); + assertThat("DSpaceObject 2 is an item", dSpaceObjectList.get(1).getType(), equalTo(Constants.ITEM)); + assertTrue(dSpaceObjectList.get(0).equals(publicItem1)); + assertTrue(dSpaceObjectList.get(1).equals(publicItem2)); + + + } +} From 033790e1b2abb6af73d791690be949f3c0ceddaf Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 5 Mar 2019 14:17:08 +0100 Subject: [PATCH 100/188] Added missing context.restoreAuthSystemState --- .../app/rest/RelationshipRestRepositoryIT.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index d0028c6fdf..c947bc4191 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -442,6 +442,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT + context.restoreAuthSystemState(); + String token = getAuthToken(admin.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") @@ -536,6 +538,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT authorizeService.addPolicy(context, author1, Constants.WRITE, user); authorizeService.addPolicy(context, author2, Constants.WRITE, user); + context.restoreAuthSystemState(); + String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") @@ -629,6 +633,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT authorizeService.addPolicy(context, publication, Constants.WRITE, user); + context.restoreAuthSystemState(); + String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") @@ -730,6 +736,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT authorizeService.addPolicy(context, publication1, Constants.WRITE, user); authorizeService.addPolicy(context, publication2, Constants.WRITE, user); + context.restoreAuthSystemState(); + String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") @@ -831,6 +839,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT authorizeService.addPolicy(context, author1, Constants.WRITE, user); + context.restoreAuthSystemState(); + String token = getAuthToken(user.getEmail(), password); MvcResult mvcResult = getClient(getAuthToken(admin.getEmail(), password)) @@ -924,6 +934,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT ePersonService.update(context, user); context.setCurrentUser(user); + context.restoreAuthSystemState(); String token = getAuthToken(admin.getEmail(), password); @@ -1015,6 +1026,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT authorizeService.addPolicy(context, author1, Constants.WRITE, user); + context.restoreAuthSystemState(); + String token = getAuthToken(admin.getEmail(), password); MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") @@ -1113,6 +1126,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String token = getAuthToken(user.getEmail(), password); + context.restoreAuthSystemState(); + MvcResult mvcResult = getClient(token).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() From 6056bf94e0848e2eda382abede1d694ca86fc541 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 6 Mar 2019 14:54:01 +0100 Subject: [PATCH 101/188] Added the comment to the context.turnOffAuthorizationSystem --- .../app/rest/repository/RelationshipRestRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 90ee634b13..0980fe84ae 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -112,6 +112,11 @@ public class RelationshipRestRepository extends DSpaceRestRepository Date: Wed, 13 Mar 2019 13:10:49 +0100 Subject: [PATCH 102/188] Applied feedback; implemented context authorisation logic in tests --- .../rest/RelationshipRestRepositoryIT.java | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index c4babab990..74861a3c9b 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -476,6 +476,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); + context.restoreAuthSystemState(); // Here we create our first Relationship to the Publication to give it a dc.contributor.author virtual // metadata field. MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") @@ -501,6 +502,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + context.turnOffAuthorisationSystem(); // Make sure we grab the latest instance of the Item from the database publication = itemService.find(context, publication.getID()); @@ -526,6 +528,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT assertEquals("plain text", author1MD.getValue()); + context.restoreAuthSystemState(); // Verfiy the leftPlace of our relationship is still 0. getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) @@ -568,12 +571,14 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT MetadataValue author2MD = list.get(2); assertEquals("Smith, Maria", author2MD.getValue()); + context.turnOffAuthorisationSystem(); // Ensure we have the latest instance of the Item from the database publication = itemService.find(context, publication.getID()); // Add a fourth dc.contributor.author mdv itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); itemService.update(context, publication); + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); // Assert that the list of dc.contributor.author mdv is now of size 4 in the following order: @@ -637,11 +642,14 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT MetadataValue author4MD = list.get(4); assertEquals("Maybe, Maybe", author4MD.getValue()); + context.turnOffAuthorisationSystem(); // The following additions of Metadata will perform the same sequence of logic and tests as described above publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); + context.restoreAuthSystemState(); + list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); assertEquals(6, list.size()); @@ -664,6 +672,8 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT MetadataValue author5MD = list.get(5); assertEquals("plain text three", author5MD.getValue()); + context.turnOffAuthorisationSystem(); + publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text four"); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text five"); @@ -671,6 +681,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text seven"); itemService.update(context, publication); + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); assertEquals(10, list.size()); @@ -776,7 +787,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT String adminToken = getAuthToken(admin.getEmail(), password); // First create the structure of 5 metadatavalues just like the additions test. - + context.restoreAuthSystemState(); MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -800,10 +811,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(jsonPath("leftPlace", is(0))); + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text"); itemService.update(context, publication); - + context.restoreAuthSystemState(); List list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -836,11 +848,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT getClient(adminToken).perform(get("/api/core/relationships/" + secondRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); - + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); itemService.update(context, publication); - + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -871,10 +883,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); - + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -893,11 +906,13 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT } } + context.turnOffAuthorisationSystem(); // Remove the "plain text two" metadatavalue. Ensure that all mdvs prior to that in the list are unchanged // And ensure that the ones coming after this mdv have its place lowered by one. itemService.removeMetadataValues(context, publication, listToRemove); itemService.update(context, publication); + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -979,6 +994,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", "isPublicationOfAuthor"); + context.restoreAuthSystemState(); String adminToken = getAuthToken(admin.getEmail(), password); // First create the structure of 5 metadatavalues just like the additions test. @@ -1005,11 +1021,12 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); - + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text"); itemService.update(context, publication); + context.restoreAuthSystemState(); List list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -1043,10 +1060,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); itemService.update(context, publication); - + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -1077,10 +1095,11 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); + context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); - + context.restoreAuthSystemState(); list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { @@ -1186,7 +1205,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Person"), entityTypeService.findByEntityType(context, "OrgUnit"), "isOrgUnitOfPerson", "isPersonOfOrgUnit"); - + context.restoreAuthSystemState(); String adminToken = getAuthToken(admin.getEmail(), password); // This is essentially a sequence of adding Relationships by POST and then checking with GET to see @@ -1309,7 +1328,7 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Person"), entityTypeService.findByEntityType(context, "OrgUnit"), "isOrgUnitOfPerson", "isPersonOfOrgUnit"); - + context.restoreAuthSystemState(); String adminToken = getAuthToken(admin.getEmail(), password); // This is essentially a sequence of adding Relationships by POST and then checking with GET to see From 00a486317852708af9dbc15b8efaca3e43e15234 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 15 Mar 2019 14:34:29 +0100 Subject: [PATCH 103/188] Removed the jsonIgnore from place attribute in MetadataValueRest and fixed IT --- .../app/rest/model/MetadataValueRest.java | 15 -------- .../app/rest/test/metadata-patch-suite.json | 36 +++++++++---------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataValueRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataValueRest.java index 013e235847..aeffb6c04d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataValueRest.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataValueRest.java @@ -7,10 +7,6 @@ */ package org.dspace.app.rest.model; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import org.dspace.app.rest.converter.MetadataConverter; /** * An embeddable representation of the Metadata to use in with DSpace REST @@ -28,17 +24,6 @@ public class MetadataValueRest { int confidence; - /** - * The order of this metadata value with respect to others in the same DSO with the same key. - * - * In the REST representation, all values of the same key are given as a json array that expresses - * their relative order, so there is no need to expose the exact numeric value publicly. The numeric - * value is only used at this level to ensure the intended order is respected when converting to/from json. - * - * @see MetadataConverter#convert(List) - * @see MetadataRest#put(String, MetadataValueRest...) - */ - @JsonIgnore int place = -1; public MetadataValueRest() { diff --git a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json index cff452fe91..a09ecf1ba9 100644 --- a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json +++ b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json @@ -23,7 +23,7 @@ ], "expect": { "dc.title": [ - { "value": "title 1", "language": null, "authority": null, "confidence": -1 } + { "value": "title 1", "language": null, "authority": null, "confidence": -1, "place": 0} ] } }, @@ -38,8 +38,8 @@ ], "expect": { "dc.title": [ - { "value": "title 1", "language": null, "authority": null, "confidence": -1 }, - { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 } + { "value": "title 1", "language": null, "authority": null, "confidence": -1,"place": 0 }, + { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 ,"place": 1} ] } }, @@ -56,9 +56,9 @@ ], "expect": { "dc.title": [ - { "value": "title 0", "language": null, "authority": null, "confidence": -1 }, - { "value": "title 1", "language": null, "authority": null, "confidence": -1 }, - { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 } + { "value": "title 0", "language": null, "authority": null, "confidence": -1 ,"place": 0 }, + { "value": "title 1", "language": null, "authority": null, "confidence": -1 ,"place": 1 }, + { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 ,"place": 2 } ] } }, @@ -73,9 +73,9 @@ ], "expect": { "dc.title": [ - { "value": "title 0", "language": null, "authority": null, "confidence": -1 }, - { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 }, - { "value": "title 1", "language": null, "authority": null, "confidence": -1 } + { "value": "title 0", "language": null, "authority": null, "confidence": -1 ,"place": 0 }, + { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 ,"place": 1 }, + { "value": "title 1", "language": null, "authority": null, "confidence": -1 ,"place": 2 } ] } }, @@ -95,9 +95,9 @@ ], "expect": { "dc.title": [ - { "value": "title 0", "language": null, "authority": null, "confidence": -1 }, - { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 }, - { "value": "title 1", "language": null, "authority": null, "confidence": -1 } + { "value": "title 0", "language": null, "authority": null, "confidence": -1 ,"place": 0 }, + { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 ,"place": 1 }, + { "value": "title 1", "language": null, "authority": null, "confidence": -1 ,"place": 2 } ] } }, @@ -112,10 +112,10 @@ ], "expect": { "dc.title": [ - { "value": "title 0", "language": null, "authority": null, "confidence": -1 }, - { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 }, - { "value": "title 1", "language": null, "authority": null, "confidence": -1 }, - { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 } + { "value": "title 0", "language": null, "authority": null, "confidence": -1 ,"place": 0 }, + { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 ,"place": 1 }, + { "value": "title 1", "language": null, "authority": null, "confidence": -1 ,"place": 2 }, + { "value": "title A", "language": "en_US", "authority": null, "confidence": -1 ,"place": 3 } ] } }, @@ -133,8 +133,8 @@ ], "expect": { "dc.title": [ - { "value": "title 0", "language": null, "authority": null, "confidence": -1 }, - { "value": "title 1", "language": null, "authority": null, "confidence": -1 } + { "value": "title 0", "language": null, "authority": null, "confidence": -1 ,"place": 0 }, + { "value": "title 1", "language": null, "authority": null, "confidence": -1 ,"place": 1 } ] } }, From b828e56bb85d78c2c146811df8085b1ddb1c968d Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 25 Mar 2019 14:10:28 +0100 Subject: [PATCH 104/188] Squashed feedback on PR-2376 --- .../dspace/app/bulkedit/MetadataImport.java | 20 +++++----- .../dspace/app/util/InitializeEntities.java | 29 +++++++------- .../java/org/dspace/content/Relationship.java | 6 +++ .../content/RelationshipMetadataValue.java | 5 +-- .../content/RelationshipServiceImpl.java | 39 +++++++++++++------ .../org/dspace/content/RelationshipType.java | 31 +++++++++------ .../content/RelationshipTypeServiceImpl.java | 19 +++++++++ .../factory/ContentServiceFactoryImpl.java | 1 + .../content/service/RelationshipService.java | 16 ++++++++ .../service/RelationshipTypeService.java | 20 ++++++++++ .../h2/V7.0_2018.04.16__dspace-entities.sql | 5 ++- .../V7.0_2018.04.16__dspace-entities.sql | 5 ++- .../V7.0_2018.04.16__dspace-entities.sql | 5 ++- .../converter/RelationshipTypeConverter.java | 13 +------ .../app/rest/model/RelationshipTypeRest.java | 24 ++++++------ .../RelationshipRestRepository.java | 7 +--- .../app/rest/EPersonRestRepositoryIT.java | 5 ++- .../RelationshipTypeRestRepositoryIT.java | 26 +++++++------ .../app/rest/builder/RelationshipBuilder.java | 6 +-- .../org/dspace/app/rest/csv/CsvImportIT.java | 4 +- .../rest/matcher/RelationshipTypeMatcher.java | 9 +++-- 21 files changed, 185 insertions(+), 110 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 90c8df864c..037f2c7902 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 @@ -756,19 +756,21 @@ public class MetadataImport { private void buildRelationObject(Context c, Item item, String value, boolean left, List acceptableRelationshipTypes) throws SQLException, AuthorizeException { - Relationship relationship = new Relationship(); + Item leftItem = null; + Item rightItem = null; RelationshipType acceptedRelationshipType = acceptableRelationshipTypes.get(0); if (left) { - relationship.setLeftItem(item); - relationship.setRightItem(itemService.findByIdOrLegacyId(c, value)); + leftItem = item; + rightItem = itemService.findByIdOrLegacyId(c, value); } else { - relationship.setRightItem(item); - relationship.setLeftItem(itemService.findByIdOrLegacyId(c, value)); + rightItem = item; + leftItem = itemService.findByIdOrLegacyId(c, value); } - relationship.setRelationshipType(acceptedRelationshipType); - relationship.setLeftPlace(relationshipService.findLeftPlaceByLeftItem(c, relationship.getLeftItem()) + 1); - relationship.setRightPlace(relationshipService.findRightPlaceByRightItem(c, relationship.getRightItem()) + 1); - Relationship persistedRelationship = relationshipService.create(c, relationship); + RelationshipType relationshipType = acceptedRelationshipType; + int leftPlace = relationshipService.findLeftPlaceByLeftItem(c, leftItem) + 1; + int rightPlace = relationshipService.findRightPlaceByRightItem(c, rightItem) + 1; + Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem, + relationshipType, leftPlace, rightPlace); relationshipService.update(c, persistedRelationship); } diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index 6d90826e32..b43e67ad02 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -204,7 +204,6 @@ public class InitializeEntities { String leftCardinalityMax,String rightCardinalityMin, String rightCardinalityMax) throws SQLException, AuthorizeException { - RelationshipType relationshipType = new RelationshipType(); EntityType leftEntityType = entityTypeService.findByEntityType(context,leftType); if (leftEntityType == null) { @@ -214,30 +213,32 @@ public class InitializeEntities { if (rightEntityType == null) { rightEntityType = entityTypeService.create(context, rightType); } - relationshipType.setLeftType(leftEntityType); - relationshipType.setRightType(rightEntityType); - relationshipType.setLeftLabel(leftLabel); - relationshipType.setRightLabel(rightLabel); + Integer leftCardinalityMinInteger; + Integer leftCardinalityMaxInteger; + Integer rightCardinalityMinInteger; + Integer rightCardinalityMaxInteger; if (StringUtils.isNotBlank(leftCardinalityMin)) { - relationshipType.setLeftMinCardinality(Integer.parseInt(leftCardinalityMin)); + leftCardinalityMinInteger = Integer.parseInt(leftCardinalityMin); } else { - relationshipType.setLeftMinCardinality(Integer.MIN_VALUE); + leftCardinalityMinInteger = null; } if (StringUtils.isNotBlank(leftCardinalityMax)) { - relationshipType.setLeftMaxCardinality(Integer.parseInt(leftCardinalityMax)); + leftCardinalityMaxInteger = Integer.parseInt(leftCardinalityMax); } else { - relationshipType.setLeftMaxCardinality(Integer.MAX_VALUE); + leftCardinalityMaxInteger = null; } if (StringUtils.isNotBlank(rightCardinalityMin)) { - relationshipType.setRightMinCardinality(Integer.parseInt(rightCardinalityMin)); + rightCardinalityMinInteger = Integer.parseInt(rightCardinalityMin); } else { - relationshipType.setRightMinCardinality(Integer.MIN_VALUE); + rightCardinalityMinInteger = null; } if (StringUtils.isNotBlank(rightCardinalityMax)) { - relationshipType.setRightMaxCardinality(Integer.parseInt(rightCardinalityMax)); + rightCardinalityMaxInteger = Integer.parseInt(rightCardinalityMax); } else { - relationshipType.setRightMaxCardinality(Integer.MAX_VALUE); + rightCardinalityMaxInteger = null; } - return relationshipType; + return relationshipTypeService.create(context, leftEntityType, rightEntityType, leftLabel, rightLabel, + leftCardinalityMinInteger, leftCardinalityMaxInteger, + rightCardinalityMinInteger, rightCardinalityMaxInteger); } } diff --git a/dspace-api/src/main/java/org/dspace/content/Relationship.java b/dspace-api/src/main/java/org/dspace/content/Relationship.java index c998e43fa1..9c0e07bbcb 100644 --- a/dspace-api/src/main/java/org/dspace/content/Relationship.java +++ b/dspace-api/src/main/java/org/dspace/content/Relationship.java @@ -18,6 +18,7 @@ import javax.persistence.ManyToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; +import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; /** @@ -76,6 +77,11 @@ public class Relationship implements ReloadableEntity { @Column(name = "right_place") private int rightPlace; + /** + * Protected constructor, create object using: + * {@link org.dspace.content.service.RelationshipService#create(Context)} } + */ + protected Relationship() {} /** * Standard setter for the ID field * @param id The ID to be set diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index fc62b86da6..51b206c4dc 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -7,8 +7,6 @@ */ package org.dspace.content; -import org.hibernate.proxy.HibernateProxyHelper; - /** * This class is used as a representation of MetadataValues for the MetadataValues that are derived from the * Relationships that the item has. This includes the useForPlace property which we'll have to use to determine @@ -46,8 +44,7 @@ public class RelationshipMetadataValue extends MetadataValue { if (obj == null) { return false; } - Class objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(obj); - if (getClass() != objClass) { + if (getClass() != RelationshipMetadataValue.class) { return false; } final RelationshipMetadataValue other = (RelationshipMetadataValue) obj; diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 84d4891364..0239740d09 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -55,6 +55,18 @@ public class RelationshipServiceImpl implements RelationshipService { return relationshipDAO.create(context, new Relationship()); } + @Override + public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType, + int leftPlace, int rightPlace) throws AuthorizeException, SQLException { + Relationship relationship = new Relationship(); + relationship.setLeftItem(leftItem); + relationship.setRightItem(rightItem); + relationship.setRelationshipType(relationshipType); + relationship.setLeftPlace(leftPlace); + relationship.setRightPlace(rightPlace); + return create(c, relationship); + } + @Override public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException { if (isRelationshipValidToCreate(context, relationship)) { @@ -180,33 +192,33 @@ public class RelationshipServiceImpl implements RelationshipService { if (!verifyEntityTypes(relationship.getLeftItem(), relationshipType.getLeftType())) { log.warn("The relationship has been deemed invalid since the leftItem" + " and leftType do no match on entityType"); - logRelationshipTypeDetails(relationshipType); + logRelationshipTypeDetailsForError(relationshipType); return false; } if (!verifyEntityTypes(relationship.getRightItem(), relationshipType.getRightType())) { log.warn("The relationship has been deemed invalid since the rightItem" + " and rightType do no match on entityType"); - logRelationshipTypeDetails(relationshipType); + logRelationshipTypeDetailsForError(relationshipType); return false; } if (!verifyMaxCardinality(context, relationship.getLeftItem(), relationshipType.getLeftMaxCardinality(), relationshipType)) { log.warn("The relationship has been deemed invalid since the left item has more" + " relationships than the left max cardinality allows after we'd store this relationship"); - logRelationshipTypeDetails(relationshipType); + logRelationshipTypeDetailsForError(relationshipType); return false; } if (!verifyMaxCardinality(context, relationship.getRightItem(), relationshipType.getRightMaxCardinality(), relationshipType)) { log.warn("The relationship has been deemed invalid since the right item has more" + " relationships than the right max cardinality allows after we'd store this relationship"); - logRelationshipTypeDetails(relationshipType); + logRelationshipTypeDetailsForError(relationshipType); return false; } return true; } - private void logRelationshipTypeDetails(RelationshipType relationshipType) { + private void logRelationshipTypeDetailsForError(RelationshipType relationshipType) { log.warn("The relationshipType's ID is: " + relationshipType.getID()); log.warn("The relationshipType's left label is: " + relationshipType.getLeftLabel()); log.warn("The relationshipType's right label is: " + relationshipType.getRightLabel()); @@ -219,10 +231,11 @@ public class RelationshipServiceImpl implements RelationshipService { } private boolean verifyMaxCardinality(Context context, Item itemToProcess, - int maxCardinality, RelationshipType relationshipType) throws SQLException { + Integer maxCardinality, + RelationshipType relationshipType) throws SQLException { List rightRelationships = findByItemAndRelationshipType(context, itemToProcess, relationshipType, false); - if (rightRelationships.size() >= maxCardinality && maxCardinality != 0) { + if (maxCardinality != null && rightRelationships.size() >= maxCardinality) { return false; } return true; @@ -321,14 +334,14 @@ public class RelationshipServiceImpl implements RelationshipService { if (this.find(context, relationship.getID()) == null) { log.warn("The relationship has been deemed invalid since the relationship" + " is not present in the DB with the current ID"); - logRelationshipTypeDetails(relationship.getRelationshipType()); + logRelationshipTypeDetailsForError(relationship.getRelationshipType()); return false; } if (!checkMinCardinality(context, relationship.getLeftItem(), relationship, relationship.getRelationshipType().getLeftMinCardinality(), true)) { log.warn("The relationship has been deemed invalid since the leftMinCardinality" + " constraint would be violated upon deletion"); - logRelationshipTypeDetails(relationship.getRelationshipType()); + logRelationshipTypeDetailsForError(relationship.getRelationshipType()); return false; } @@ -336,7 +349,7 @@ public class RelationshipServiceImpl implements RelationshipService { relationship, relationship.getRelationshipType().getRightMinCardinality(), false)) { log.warn("The relationship has been deemed invalid since the rightMinCardinality" + " constraint would be violated upon deletion"); - logRelationshipTypeDetails(relationship.getRelationshipType()); + logRelationshipTypeDetailsForError(relationship.getRelationshipType()); return false; } return true; @@ -344,10 +357,10 @@ public class RelationshipServiceImpl implements RelationshipService { private boolean checkMinCardinality(Context context, Item item, Relationship relationship, - int minCardinality, boolean isLeft) throws SQLException { + Integer minCardinality, boolean isLeft) throws SQLException { List list = this .findByItemAndRelationshipType(context, item, relationship.getRelationshipType(), isLeft); - if (!(list.size() > minCardinality)) { + if (minCardinality != null && !(list.size() > minCardinality)) { return false; } return true; @@ -395,4 +408,6 @@ public class RelationshipServiceImpl implements RelationshipService { throws SQLException { return relationshipDAO.findByRelationshipType(context, relationshipType); } + + } diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipType.java b/dspace-api/src/main/java/org/dspace/content/RelationshipType.java index 99499fc323..76314478fb 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipType.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipType.java @@ -19,6 +19,7 @@ import javax.persistence.ManyToOne; import javax.persistence.SequenceGenerator; import javax.persistence.Table; +import org.dspace.core.Context; import org.dspace.core.ReloadableEntity; /** @@ -80,26 +81,32 @@ public class RelationshipType implements ReloadableEntity { * This is stored as an Integer */ @Column(name = "left_min_cardinality") - private int leftMinCardinality; + private Integer leftMinCardinality; /** * The maximum amount of relations for the leftItem that can to be present at all times * This is stored as an Integer */ @Column(name = "left_max_cardinality") - private int leftMaxCardinality; + private Integer leftMaxCardinality; /** * The minimum amount of relations for the rightItem that need to be present at all times */ @Column(name = "right_min_cardinality") - private int rightMinCardinality; + private Integer rightMinCardinality; /** * Tha maximum amount of relations for the rightItem that can be present at all times */ @Column(name = "right_max_cardinality") - private int rightMaxCardinality; + private Integer rightMaxCardinality; + + /** + * Protected constructor, create object using: + * {@link org.dspace.content.service.RelationshipTypeService#create(Context)} } + */ + protected RelationshipType() {} /** * Standard getter for the ID of this RelationshipType @@ -177,7 +184,7 @@ public class RelationshipType implements ReloadableEntity { * Standard getter for the leftMinCardinality Integer for this RelationshipType * @return the leftMinCardinality Integer of this RelationshipType */ - public int getLeftMinCardinality() { + public Integer getLeftMinCardinality() { return leftMinCardinality; } @@ -185,7 +192,7 @@ public class RelationshipType implements ReloadableEntity { * Standard setter for the leftMinCardinality Integer for this RelationshipType * @param leftMinCardinality The leftMinCardinality Integer that this RelationshipType should recieve */ - public void setLeftMinCardinality(int leftMinCardinality) { + public void setLeftMinCardinality(Integer leftMinCardinality) { this.leftMinCardinality = leftMinCardinality; } @@ -193,7 +200,7 @@ public class RelationshipType implements ReloadableEntity { * Standard getter for the leftMaxCardinality Integer for this RelationshipType * @return the leftMaxCardinality Integer of this RelationshipType */ - public int getLeftMaxCardinality() { + public Integer getLeftMaxCardinality() { return leftMaxCardinality; } @@ -201,7 +208,7 @@ public class RelationshipType implements ReloadableEntity { * Standard setter for the leftMaxCardinality Integer for this RelationshipType * @param leftMaxCardinality The leftMaxCardinality Integer that this RelationshipType should recieve */ - public void setLeftMaxCardinality(int leftMaxCardinality) { + public void setLeftMaxCardinality(Integer leftMaxCardinality) { this.leftMaxCardinality = leftMaxCardinality; } @@ -209,7 +216,7 @@ public class RelationshipType implements ReloadableEntity { * Standard getter for the rightMinCardinality Integer for this RelationshipType * @return the rightMinCardinality Integer of this RelationshipType */ - public int getRightMinCardinality() { + public Integer getRightMinCardinality() { return rightMinCardinality; } @@ -217,7 +224,7 @@ public class RelationshipType implements ReloadableEntity { * Standard setter for the rightMinCardinality Integer for this RelationshipType * @param rightMinCardinality The rightMinCardinality Integer that this RelationshipType should recieve */ - public void setRightMinCardinality(int rightMinCardinality) { + public void setRightMinCardinality(Integer rightMinCardinality) { this.rightMinCardinality = rightMinCardinality; } @@ -225,7 +232,7 @@ public class RelationshipType implements ReloadableEntity { * Standard getter for the rightMaxCardinality Integer for this RelationshipType * @return the rightMaxCardinality Integer of this RelationshipType */ - public int getRightMaxCardinality() { + public Integer getRightMaxCardinality() { return rightMaxCardinality; } @@ -233,7 +240,7 @@ public class RelationshipType implements ReloadableEntity { * Standard setter for the rightMaxCardinality Integer for this RelationshipType * @param rightMaxCardinality The rightMaxCardinality Integer that this RelationshipType should recieve */ - public void setRightMaxCardinality(int rightMaxCardinality) { + public void setRightMaxCardinality(Integer rightMaxCardinality) { this.rightMaxCardinality = rightMaxCardinality; } diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index 401ade2d9e..f26df2a223 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -66,6 +66,25 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { return relationshipTypeDAO.findByEntityType(context, entityType); } + @Override + public RelationshipType create(Context context, EntityType leftEntityType, EntityType rightEntityType, + String leftLabel, String rightLabel, Integer leftCardinalityMinInteger, + Integer leftCardinalityMaxInteger, Integer rightCardinalityMinInteger, + Integer rightCardinalityMaxInteger) + throws SQLException, AuthorizeException { + RelationshipType relationshipType = new RelationshipType(); + relationshipType.setLeftType(leftEntityType); + relationshipType.setRightType(rightEntityType); + relationshipType.setLeftLabel(leftLabel); + relationshipType.setRightLabel(rightLabel); + relationshipType.setLeftMinCardinality(leftCardinalityMinInteger); + relationshipType.setLeftMaxCardinality(leftCardinalityMaxInteger); + relationshipType.setRightMinCardinality(rightCardinalityMinInteger); + relationshipType.setRightMaxCardinality(rightCardinalityMaxInteger); + return create(context, relationshipType); + } + + public RelationshipType find(Context context,int id) throws SQLException { return relationshipTypeDAO.findByID(context, RelationshipType.class, id); } diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java index 8e36660c0e..2b097ae358 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactoryImpl.java @@ -171,6 +171,7 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory { return entityTypeService; } + @Override public EntityService getEntityService() { return entityService; } diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java index f42e7cbb36..6b07c316a1 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipService.java @@ -125,4 +125,20 @@ public interface RelationshipService extends DSpaceCRUDService { * @throws SQLException If something goes wrong */ List findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException; + + /** + * This method is used to construct a Relationship object with all it's variables + * @param c The relevant DSpace context + * @param leftItem The leftItem Item object for the relationship + * @param rightItem The rightItem Item object for the relationship + * @param relationshipType The RelationshipType object for the relationship + * @param leftPlace The leftPlace integer for the relationship + * @param rightPlace The rightPlace integer for the relationship + * @return The created Relationship object with the given properties + * @throws AuthorizeException If something goes wrong + * @throws SQLException If something goes wrong + */ + Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType, + int leftPlace, int rightPlace) + throws AuthorizeException, SQLException; } \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java index fb199f39be..0a5a51d4aa 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/RelationshipTypeService.java @@ -74,4 +74,24 @@ public interface RelationshipTypeService extends DSpaceCRUDService findByEntityType(Context context, EntityType entityType) throws SQLException; + + /** + * This method will support the creation of a RelationshipType object with the given parameters + * @param context The relevant DSpace context + * @param leftEntityType The leftEntityType EntityType object for this relationshipType + * @param rightEntityType The rightEntityType EntityType object for this relationshipType + * @param leftLabel The leftLabel String object for this relationshipType + * @param rightLabel The rightLabel String object for this relationshipType + * @param leftCardinalityMinInteger The leftCardinalityMinInteger Integer object for this relationshipType + * @param leftCardinalityMaxInteger The leftCardinalityMaxInteger Integer object for this relationshipType + * @param rightCardinalityMinInteger The rightCardinalityMinInteger Integer object for this relationshipType + * @param rightCardinalityMaxInteger The rightCardinalityMaxInteger Integer object for this relationshipType + * @return The created RelationshipType object for these properties + * @throws SQLException If something goes wrong + * @throws AuthorizeException If something goes wrong + */ + RelationshipType create(Context context, EntityType leftEntityType, EntityType rightEntityType, String leftLabel, + String rightLabel, Integer leftCardinalityMinInteger, Integer leftCardinalityMaxInteger, + Integer rightCardinalityMinInteger, Integer rightCardinalityMaxInteger) + throws SQLException, AuthorizeException; } diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql index 52e290b923..60bc9dc984 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql @@ -55,8 +55,9 @@ CREATE TABLE relationship ); CREATE INDEX entity_type_label_idx ON entity_type(label); -CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); -CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); +CREATE INDEX relationship_by_left_id_idx ON relationship(left_id); +CREATE INDEX relationship_by_right_id_idx ON relationship(right_id); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql index f06e64e6f8..c4b84d8623 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql @@ -55,8 +55,9 @@ CREATE TABLE relationship ); CREATE INDEX entity_type_label_idx ON entity_type(label); -CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); -CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); +CREATE INDEX relationship_by_left_id_idx ON relationship(left_id); +CREATE INDEX relationship_by_right_id_idx ON relationship(right_id); \ No newline at end of file diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql index f06e64e6f8..c4b84d8623 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql @@ -55,8 +55,9 @@ CREATE TABLE relationship ); CREATE INDEX entity_type_label_idx ON entity_type(label); -CREATE INDEX relationship_type_by_types_and_labels_idx ON relationship_type(left_type, right_type, left_label, right_label); CREATE INDEX relationship_type_by_left_type_idx ON relationship_type(left_type); CREATE INDEX relationship_type_by_right_type_idx ON relationship_type(right_type); CREATE INDEX relationship_type_by_left_label_idx ON relationship_type(left_label); -CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); \ No newline at end of file +CREATE INDEX relationship_type_by_right_label_idx ON relationship_type(right_label); +CREATE INDEX relationship_by_left_id_idx ON relationship(left_id); +CREATE INDEX relationship_by_right_id_idx ON relationship(right_id); \ No newline at end of file diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java index 5fdf20b618..ce0065c608 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/RelationshipTypeConverter.java @@ -51,18 +51,7 @@ public class RelationshipTypeConverter extends DSpaceConverter { private String leftLabel; private String rightLabel; - private int leftMinCardinality; - private int leftMaxCardinality; - private int rightMinCardinality; - private int rightMaxCardinality; + private Integer leftMinCardinality; + private Integer leftMaxCardinality; + private Integer rightMinCardinality; + private Integer rightMaxCardinality; private EntityTypeRest leftType; private EntityTypeRest rightType; @@ -57,35 +57,35 @@ public class RelationshipTypeRest extends BaseObjectRest { this.rightLabel = rightLabel; } - public int getLeftMinCardinality() { + public Integer getLeftMinCardinality() { return leftMinCardinality; } - public void setLeftMinCardinality(int leftMinCardinality) { + public void setLeftMinCardinality(Integer leftMinCardinality) { this.leftMinCardinality = leftMinCardinality; } - public int getLeftMaxCardinality() { + public Integer getLeftMaxCardinality() { return leftMaxCardinality; } - public void setLeftMaxCardinality(int leftMaxCardinality) { + public void setLeftMaxCardinality(Integer leftMaxCardinality) { this.leftMaxCardinality = leftMaxCardinality; } - public int getRightMinCardinality() { + public Integer getRightMinCardinality() { return rightMinCardinality; } - public void setRightMinCardinality(int rightMinCardinality) { + public void setRightMinCardinality(Integer rightMinCardinality) { this.rightMinCardinality = rightMinCardinality; } - public int getRightMaxCardinality() { + public Integer getRightMaxCardinality() { return rightMaxCardinality; } - public void setRightMaxCardinality(int rightMaxCardinality) { + public void setRightMaxCardinality(Integer rightMaxCardinality) { this.rightMaxCardinality = rightMaxCardinality; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index 0980fe84ae..ed367bcfb4 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -98,7 +98,6 @@ public class RelationshipRestRepository extends DSpaceRestRepository relationshipsForArticle = relationshipService .findByItemAndRelationshipType(context, article, relationshipTypeService - .findByLeftOrRightLabel(context,"isPublicationOfAuthor").get(0)); + .findbyTypesAndLabels(context, entityTypeService.findByEntityType(context, "Publication"), + entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", + "isPublicationOfAuthor")); assertThat(relationshipsForArticle.size(), is(3)); List expectedRelationshipsItemsForArticle = new ArrayList<>(); expectedRelationshipsItemsForArticle.add(itemC); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java index 748f67f4e5..55fd089113 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/RelationshipTypeMatcher.java @@ -49,8 +49,9 @@ public class RelationshipTypeMatcher { } private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityType(int id, - String leftLabel, String rightLabel, int leftMinCardinality, int leftMaxCardinality, - int rightMinCardinality, int rightMaxCardinality, EntityType leftEntityType, EntityType rightEntityType) { + String leftLabel, String rightLabel, Integer leftMinCardinality, Integer leftMaxCardinality, + Integer rightMinCardinality, Integer rightMaxCardinality, + EntityType leftEntityType, EntityType rightEntityType) { return matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(id, leftLabel, rightLabel, leftMinCardinality, leftMaxCardinality, rightMinCardinality, @@ -62,8 +63,8 @@ public class RelationshipTypeMatcher { } private static Matcher matchExplicitRelationshipTypeValuesAndExplicitEntityTypeValues(int id, - String leftLabel, String rightLabel, int leftMinCardinality, int leftMaxCardinality, - int rightMinCardinality, int rightMaxCardinality, int leftEntityTypeId, String leftEntityTypeLabel, + String leftLabel, String rightLabel, Integer leftMinCardinality, Integer leftMaxCardinality, + Integer rightMinCardinality, Integer rightMaxCardinality, int leftEntityTypeId, String leftEntityTypeLabel, int rightEntityTypeId, String rightEntityTypeLabel) { return allOf( hasJsonPath("$.id", is(id)), From 13ce03c8c71da35e8f25866d9216df315c7192e9 Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Wed, 27 Mar 2019 13:19:28 +0100 Subject: [PATCH 105/188] Refactor Entity ITs to not use the xml file but builders --- .../app/rest/EntityTypeRestRepositoryIT.java | 65 +---------- .../rest/RelationshipRestRepositoryIT.java | 61 +--------- .../RelationshipTypeRestControllerIT.java | 60 +--------- .../RelationshipTypeRestRepositoryIT.java | 61 +--------- .../app/rest/builder/AbstractBuilder.java | 9 ++ .../app/rest/builder/EntityTypeBuilder.java | 87 ++++++++++++++ .../rest/builder/MetadataFieldBuilder.java | 3 +- .../rest/builder/MetadataSchemaBuilder.java | 2 +- .../rest/builder/RelationshipTypeBuilder.java | 109 ++++++++++++++++++ .../org/dspace/app/rest/csv/CsvImportIT.java | 63 +--------- .../test/AbstractEntityIntegrationTest.java | 105 +++++++++++++++++ .../org/dspace/core/HibernateTestUtil.java | 32 +++++ 12 files changed, 355 insertions(+), 302 deletions(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipTypeBuilder.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractEntityIntegrationTest.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/core/HibernateTestUtil.java diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java index 0c70470f5f..8b5f19d158 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java @@ -16,82 +16,21 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.io.File; import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; import org.dspace.app.rest.matcher.EntityTypeMatcher; -import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.content.EntityType; -import org.dspace.content.Relationship; -import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; -import org.dspace.content.service.RelationshipService; -import org.dspace.content.service.RelationshipTypeService; -import org.dspace.services.ConfigurationService; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; -@Ignore -public class EntityTypeRestRepositoryIT extends AbstractControllerIntegrationTest { +public class EntityTypeRestRepositoryIT extends AbstractEntityIntegrationTest { - @Autowired - private RelationshipTypeService relationshipTypeService; @Autowired private EntityTypeService entityTypeService; - @Autowired - private ConfigurationService configurationService; - - @Autowired - private RelationshipService relationshipService; - - @Before - public void setup() throws Exception { - - //Set up the database for the next test - String pathToFile = configurationService.getProperty("dspace.dir") + - File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; - runDSpaceScript("initialize-entities", "-f", pathToFile); - } - - @After - public void destroy() throws Exception { - //Clean up the database for the next test - context.turnOffAuthorisationSystem(); - List relationshipTypeList = relationshipTypeService.findAll(context); - List entityTypeList = entityTypeService.findAll(context); - List relationships = relationshipService.findAll(context); - - Iterator relationshipIterator = relationships.iterator(); - while (relationshipIterator.hasNext()) { - Relationship relationship = relationshipIterator.next(); - relationshipIterator.remove(); - relationshipService.delete(context, relationship); - } - - Iterator relationshipTypeIterator = relationshipTypeList.iterator(); - while (relationshipTypeIterator.hasNext()) { - RelationshipType relationshipType = relationshipTypeIterator.next(); - relationshipTypeIterator.remove(); - relationshipTypeService.delete(context, relationshipType); - } - - Iterator entityTypeIterator = entityTypeList.iterator(); - while (entityTypeIterator.hasNext()) { - EntityType entityType = entityTypeIterator.next(); - entityTypeIterator.remove(); - entityTypeService.delete(context, entityType); - } - - super.destroy(); - } - @Test public void findAllEntityTypesSizeTest() throws SQLException { assertEquals(7, entityTypeService.findAll(context).size()); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 74861a3c9b..0837f4a86c 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -17,8 +17,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.io.File; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -31,34 +29,27 @@ import org.dspace.app.rest.builder.ItemBuilder; import org.dspace.app.rest.builder.RelationshipBuilder; import org.dspace.app.rest.matcher.PageMatcher; import org.dspace.app.rest.matcher.RelationshipMatcher; -import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Collection; import org.dspace.content.Community; -import org.dspace.content.EntityType; import org.dspace.content.Item; import org.dspace.content.MetadataValue; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.ItemService; -import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.I18nUtil; import org.dspace.eperson.EPerson; import org.dspace.eperson.service.EPersonService; -import org.dspace.services.ConfigurationService; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MvcResult; -@Ignore -public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationTest { +public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest { @Autowired private RelationshipTypeService relationshipTypeService; @@ -66,12 +57,6 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT @Autowired private EntityTypeService entityTypeService; - @Autowired - private RelationshipService relationshipService; - - @Autowired - private ConfigurationService configurationService; - @Autowired private EPersonService ePersonService; @@ -81,48 +66,6 @@ public class RelationshipRestRepositoryIT extends AbstractControllerIntegrationT @Autowired private ItemService itemService; - @Before - public void setup() throws Exception { - - //Set up the database for the next test - String pathToFile = configurationService.getProperty("dspace.dir") + - File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; - runDSpaceScript("initialize-entities", "-f", pathToFile); - - - } - - @After - public void destroy() throws Exception { - //Clean up the database for the next test - context.turnOffAuthorisationSystem(); - List relationshipTypeList = relationshipTypeService.findAll(context); - List entityTypeList = entityTypeService.findAll(context); - List relationships = relationshipService.findAll(context); - - Iterator relationshipIterator = relationships.iterator(); - while (relationshipIterator.hasNext()) { - Relationship relationship = relationshipIterator.next(); - relationshipIterator.remove(); - relationshipService.delete(context, relationship); - } - - Iterator relationshipTypeIterator = relationshipTypeList.iterator(); - while (relationshipTypeIterator.hasNext()) { - RelationshipType relationshipType = relationshipTypeIterator.next(); - relationshipTypeIterator.remove(); - relationshipTypeService.delete(context, relationshipType); - } - - Iterator entityTypeIterator = entityTypeList.iterator(); - while (entityTypeIterator.hasNext()) { - EntityType entityType = entityTypeIterator.next(); - entityTypeIterator.remove(); - entityTypeService.delete(context, entityType); - } - - super.destroy(); - } @Test public void findAllRelationshipTest() throws Exception { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java index f32f8bffc7..c8d2322d29 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java @@ -13,10 +13,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.io.File; -import java.util.Iterator; -import java.util.List; - import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; import org.dspace.app.rest.builder.ItemBuilder; @@ -25,7 +21,7 @@ import org.dspace.app.rest.matcher.EntityTypeMatcher; import org.dspace.app.rest.matcher.PageMatcher; import org.dspace.app.rest.matcher.RelationshipMatcher; import org.dspace.app.rest.matcher.RelationshipTypeMatcher; -import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.EntityType; @@ -33,15 +29,11 @@ import org.dspace.content.Item; import org.dspace.content.Relationship; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; -import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; -import org.dspace.services.ConfigurationService; -import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; -public class RelationshipTypeRestControllerIT extends AbstractControllerIntegrationTest { +public class RelationshipTypeRestControllerIT extends AbstractEntityIntegrationTest { @Autowired private RelationshipTypeService relationshipTypeService; @@ -49,54 +41,6 @@ public class RelationshipTypeRestControllerIT extends AbstractControllerIntegrat @Autowired private EntityTypeService entityTypeService; - @Autowired - private RelationshipService relationshipService; - - @Autowired - private ConfigurationService configurationService; - - @Before - public void setup() throws Exception { - - //Set up the database for the next test - String pathToFile = configurationService.getProperty("dspace.dir") + - File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; - runDSpaceScript("initialize-entities", "-f", pathToFile); - - } - - @After - public void destroy() throws Exception { - //Clean up the database for the next test - context.turnOffAuthorisationSystem(); - List relationshipTypeList = relationshipTypeService.findAll(context); - List entityTypeList = entityTypeService.findAll(context); - List relationships = relationshipService.findAll(context); - - Iterator relationshipIterator = relationships.iterator(); - while (relationshipIterator.hasNext()) { - Relationship relationship = relationshipIterator.next(); - relationshipIterator.remove(); - relationshipService.delete(context, relationship); - } - - Iterator relationshipTypeIterator = relationshipTypeList.iterator(); - while (relationshipTypeIterator.hasNext()) { - RelationshipType relationshipType = relationshipTypeIterator.next(); - relationshipTypeIterator.remove(); - relationshipTypeService.delete(context, relationshipType); - } - - Iterator entityTypeIterator = entityTypeList.iterator(); - while (entityTypeIterator.hasNext()) { - EntityType entityType = entityTypeIterator.next(); - entityTypeIterator.remove(); - entityTypeService.delete(context, entityType); - } - - super.destroy(); - } - @Test public void findAllEntityTypes() throws Exception { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java index bd8f7d82c6..6539451aef 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestRepositoryIT.java @@ -19,30 +19,20 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.io.File; import java.sql.SQLException; -import java.util.Iterator; import java.util.List; import org.dspace.app.rest.matcher.EntityTypeMatcher; import org.dspace.app.rest.matcher.RelationshipTypeMatcher; -import org.dspace.app.rest.test.AbstractControllerIntegrationTest; -import org.dspace.content.EntityType; -import org.dspace.content.Relationship; +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; -import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; -import org.dspace.services.ConfigurationService; import org.h2.util.StringUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; -@Ignore -public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrationTest { +public class RelationshipTypeRestRepositoryIT extends AbstractEntityIntegrationTest { @Autowired private RelationshipTypeService relationshipTypeService; @@ -50,53 +40,6 @@ public class RelationshipTypeRestRepositoryIT extends AbstractControllerIntegrat @Autowired private EntityTypeService entityTypeService; - @Autowired - private RelationshipService relationshipService; - - @Autowired - private ConfigurationService configurationService; - - @Before - public void setup() throws Exception { - - //Set up the database for the next test - String pathToFile = configurationService.getProperty("dspace.dir") + - File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; - runDSpaceScript("initialize-entities", "-f", pathToFile); - } - - @After - public void destroy() throws Exception { - //Clean up the database for the next test - context.turnOffAuthorisationSystem(); - List relationshipTypeList = relationshipTypeService.findAll(context); - List entityTypeList = entityTypeService.findAll(context); - List relationships = relationshipService.findAll(context); - - Iterator relationshipIterator = relationships.iterator(); - while (relationshipIterator.hasNext()) { - Relationship relationship = relationshipIterator.next(); - relationshipIterator.remove(); - relationshipService.delete(context, relationship); - } - - Iterator relationshipTypeIterator = relationshipTypeList.iterator(); - while (relationshipTypeIterator.hasNext()) { - RelationshipType relationshipType = relationshipTypeIterator.next(); - relationshipTypeIterator.remove(); - relationshipTypeService.delete(context, relationshipType); - } - - Iterator entityTypeIterator = entityTypeList.iterator(); - while (entityTypeIterator.hasNext()) { - EntityType entityType = entityTypeIterator.next(); - entityTypeIterator.remove(); - entityTypeService.delete(context, entityType); - } - - super.destroy(); - } - @Test public void findAllRelationshipTypesTest() throws SQLException { assertEquals(10, relationshipTypeService.findAll(context).size()); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java index ad86acb2be..67478e5e71 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java @@ -23,11 +23,13 @@ import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BundleService; import org.dspace.content.service.CollectionService; import org.dspace.content.service.CommunityService; +import org.dspace.content.service.EntityTypeService; 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.SiteService; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; @@ -74,6 +76,8 @@ public abstract class AbstractBuilder { static MetadataSchemaService metadataSchemaService; static SiteService siteService; static RelationshipService relationshipService; + static RelationshipTypeService relationshipTypeService; + static EntityTypeService entityTypeService; protected Context context; @@ -110,6 +114,8 @@ public abstract class AbstractBuilder { metadataSchemaService = ContentServiceFactory.getInstance().getMetadataSchemaService(); siteService = ContentServiceFactory.getInstance().getSiteService(); relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); + relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService(); + entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService(); // Temporarily disabled // TODO find a way to be able to test the XML and "default" workflow at the same time @@ -143,6 +149,9 @@ public abstract class AbstractBuilder { metadataFieldService = null; metadataSchemaService = null; siteService = null; + relationshipService = null; + relationshipTypeService = null; + entityTypeService = null; } public static void cleanupObjects() throws Exception { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java new file mode 100644 index 0000000000..f11cdb090d --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java @@ -0,0 +1,87 @@ +/** + * 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.rest.builder; + +import java.sql.SQLException; + +import org.apache.log4j.Logger; +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.EntityType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.core.Context; +import org.dspace.discovery.SearchServiceException; + +public class EntityTypeBuilder extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(EntityTypeBuilder.class); + + private EntityType entityType; + + protected EntityTypeBuilder(Context context) { + super(context); + } + + @Override + protected EntityTypeService getService() { + return entityTypeService; + } + + protected void cleanup() throws Exception { + delete(entityType); + } + + public EntityType build() { + try { + + entityTypeService.update(context, entityType); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException | SQLException | AuthorizeException e) { + log.error(e); + } + return entityType; + } + + public void delete(EntityType entityType) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + EntityType attachedEntityType = c.reloadEntity(entityType); + if (attachedEntityType != null) { + getService().delete(c, attachedEntityType); + } + c.complete(); + } + + indexingService.commit(); + } + + public static EntityTypeBuilder createEntityTypeBuilder(Context context, String entityType) { + EntityTypeBuilder entityTypeBuilder = new EntityTypeBuilder(context); + return entityTypeBuilder.create(context, entityType); + } + + private EntityTypeBuilder create(Context context, String entityType) { + try { + + this.context = context; + this.entityType = entityTypeService.create(context, entityType); + + } catch (SQLException | AuthorizeException e) { + e.printStackTrace(); + } + + return this; + } + + @Override + protected int getPriority() { + return -1 ; + } +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java index 061e5f7c0d..9a8c6bd3a4 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java @@ -28,9 +28,10 @@ public class MetadataFieldBuilder extends AbstractBuilder { + + /* Log4j logger*/ + private static final Logger log = Logger.getLogger(RelationshipTypeBuilder.class); + + private RelationshipType relationshipType; + + protected RelationshipTypeBuilder(Context context) { + super(context); + } + + @Override + protected RelationshipTypeService getService() { + return relationshipTypeService; + } + + protected void cleanup() throws Exception { + context.turnOffAuthorisationSystem(); + List byRelationshipType = relationshipService.findByRelationshipType(context, relationshipType); + for (Relationship relationship : byRelationshipType) { + relationshipService.delete(context, relationship); + } + context.restoreAuthSystemState(); + + delete(relationshipType); + } + + public RelationshipType build() { + try { + + relationshipTypeService.update(context, relationshipType); + context.dispatchEvents(); + + indexingService.commit(); + } catch (SearchServiceException | SQLException | AuthorizeException e) { + log.error(e); + } + return relationshipType; + } + + public void delete(RelationshipType relationshipType) throws Exception { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + RelationshipType attachedRelationShipType = c.reloadEntity(relationshipType); + if (attachedRelationShipType != null) { + getService().delete(c, attachedRelationShipType); + } + c.complete(); + } + + indexingService.commit(); + } + + public static RelationshipTypeBuilder createRelationshipTypeBuilder(Context context, EntityType leftType, + EntityType rightType, String leftLabel, + String rightLabel, Integer leftCardinalityMin, + Integer leftCardinalityMax, Integer rightCardinalityMin, + Integer rightCardinalityMax) { + RelationshipTypeBuilder relationshipBuilder = new RelationshipTypeBuilder(context); + return relationshipBuilder.create(context, leftType, + rightType, leftLabel, + rightLabel, leftCardinalityMin, + leftCardinalityMax, rightCardinalityMin, + rightCardinalityMax); + } + + private RelationshipTypeBuilder create(Context context, EntityType leftEntityType, EntityType rightEntityType, + String leftLabel, String rightLabel, Integer leftCardinalityMin, + Integer leftCardinalityMax, Integer rightCardinalityMin, Integer rightCardinalityMax) { + try { + + this.context = context; + this.relationshipType = relationshipTypeService + .create(context, leftEntityType, rightEntityType, leftLabel, rightLabel, leftCardinalityMin, + leftCardinalityMax, rightCardinalityMin, rightCardinalityMax); + + } catch (SQLException | AuthorizeException e) { + e.printStackTrace(); + } + + return this; + } + + @Override + protected int getPriority() { + return -2 ; + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java index 8e41528337..0438595f31 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/csv/CsvImportIT.java @@ -15,7 +15,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.io.BufferedWriter; -import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.sql.SQLException; @@ -27,27 +26,20 @@ import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; import org.dspace.app.rest.builder.ItemBuilder; import org.dspace.app.rest.matcher.RelationshipMatcher; -import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.content.Collection; import org.dspace.content.Community; -import org.dspace.content.EntityType; import org.dspace.content.Item; import org.dspace.content.Relationship; -import org.dspace.content.RelationshipType; import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.ItemService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.RelationshipTypeService; -import org.dspace.services.ConfigurationService; import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; -@Ignore -public class CsvImportIT extends AbstractControllerIntegrationTest { +public class CsvImportIT extends AbstractEntityIntegrationTest { @Autowired private RelationshipTypeService relationshipTypeService; @@ -61,57 +53,6 @@ public class CsvImportIT extends AbstractControllerIntegrationTest { @Autowired private ItemService itemService; - @Autowired - private ConfigurationService configurationService; - - @Before - public void setup() throws Exception { - - //Set up the database for the next test - String pathToFile = configurationService.getProperty("dspace.dir") + - File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; - runDSpaceScript("initialize-entities", "-f", pathToFile); - } - - @After - public void destroy() throws Exception { - //Clean up the database for the next test - context.turnOffAuthorisationSystem(); - List relationshipTypeList = relationshipTypeService.findAll(context); - List entityTypeList = entityTypeService.findAll(context); - List relationships = relationshipService.findAll(context); - Iterator itemIterator = itemService.findAll(context); - - Iterator relationshipIterator = relationships.iterator(); - while (relationshipIterator.hasNext()) { - Relationship relationship = relationshipIterator.next(); - relationshipIterator.remove(); - relationshipService.delete(context, relationship); - } - - Iterator relationshipTypeIterator = relationshipTypeList.iterator(); - while (relationshipTypeIterator.hasNext()) { - RelationshipType relationshipType = relationshipTypeIterator.next(); - relationshipTypeIterator.remove(); - relationshipTypeService.delete(context, relationshipType); - } - - Iterator entityTypeIterator = entityTypeList.iterator(); - while (entityTypeIterator.hasNext()) { - EntityType entityType = entityTypeIterator.next(); - entityTypeIterator.remove(); - entityTypeService.delete(context, entityType); - } - - while (itemIterator.hasNext()) { - Item item = itemIterator.next(); - itemIterator.remove(); - itemService.delete(context, item); - } - - super.destroy(); - } - @Test public void createRelationshipsWithCsvImportTest() throws Exception { context.turnOffAuthorisationSystem(); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractEntityIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractEntityIntegrationTest.java new file mode 100644 index 0000000000..5308551aaf --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractEntityIntegrationTest.java @@ -0,0 +1,105 @@ +/** + * 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.rest.test; + +import org.dspace.app.rest.builder.EntityTypeBuilder; +import org.dspace.app.rest.builder.RelationshipTypeBuilder; +import org.dspace.content.EntityType; +import org.dspace.content.service.EntityTypeService; +import org.junit.Before; +import org.springframework.beans.factory.annotation.Autowired; + +public class AbstractEntityIntegrationTest extends AbstractControllerIntegrationTest { + + @Autowired + private EntityTypeService entityTypeService; + + /** + * This method will call the setUp method from AbstractControllerIntegrationTest. + * Afterwards it will setUp the entity relation structure as defined in + * dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml + * + * This method will first build the following EntityTypes: + * - Publication + * - Person + * - Project + * - OrgUnit + * - Journal + * - JournalVolume + * - JournalIssue + * + * After the EntityTypes are created, RelationshipTypes are set up between the different EntityTypes as indicated + * in relationship-types.xml + */ + @Before + public void setUp() throws Exception { + super.setUp(); + + if (entityTypeService.findAll(context).size() > 0) { + //Don't initialize the setup more than once + return; + } + + context.turnOffAuthorisationSystem(); + + EntityType publication = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build(); + EntityType person = EntityTypeBuilder.createEntityTypeBuilder(context, "Person").build(); + EntityType project = EntityTypeBuilder.createEntityTypeBuilder(context, "Project").build(); + EntityType orgUnit = EntityTypeBuilder.createEntityTypeBuilder(context, "OrgUnit").build(); + EntityType journal = EntityTypeBuilder.createEntityTypeBuilder(context, "Journal").build(); + EntityType journalVolume = EntityTypeBuilder.createEntityTypeBuilder(context, "JournalVolume").build(); + EntityType journalIssue = EntityTypeBuilder.createEntityTypeBuilder(context, "JournalIssue").build(); + + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, publication, person, "isAuthorOfPublication", + "isPublicationOfAuthor", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, publication, project, "isProjectOfPublication", + "isPublicationOfProject", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, publication, orgUnit, "isOrgUnitOfPublication", + "isPublicationOfOrgUnit", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, person, project, "isProjectOfPerson", + "isPersonOfProject", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, person, orgUnit, "isOrgUnitOfPerson", + "isPersonOfOrgUnit", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, project, orgUnit, "isOrgUnitOfProject", + "isProjectOfOrgUnit", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, journal, journalVolume, "isVolumeOfJournal", + "isJournalOfVolume", 0, null, 1, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, journalVolume, journalIssue, + "isIssueOfJournalVolume", "isJournalVolumeOfIssue", 0, + null, 1, + 1).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, publication, orgUnit, "isAuthorOfPublication", + "isPublicationOfAuthor", 0, null, 0, + null).build(); + + RelationshipTypeBuilder.createRelationshipTypeBuilder(context, journalIssue, publication, + "isPublicationOfJournalIssue", + "isJournalIssueOfPublication", 0, null, 0, + 1).build(); + + context.restoreAuthSystemState(); + } + + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/core/HibernateTestUtil.java b/dspace-spring-rest/src/test/java/org/dspace/core/HibernateTestUtil.java new file mode 100644 index 0000000000..3f214daf34 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/core/HibernateTestUtil.java @@ -0,0 +1,32 @@ +/** + * 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.core; + +import java.sql.SQLException; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; + +/** + * Helper class to execute Hibernate queries in the DSpace test classes + */ +public class HibernateTestUtil { + + private HibernateTestUtil() { + //private constructor required for utility classes + } + + public static Session getHibernateSession(Context context) throws SQLException { + return ((Session) context.getDBConnection().getSession()); + } + + public static SessionFactory getHibernateSessionFactory(Context context) throws SQLException { + return ((Session) context.getDBConnection().getSession()).getSessionFactory(); + } + +} From b71b6e9f1b351d08be72ef3d8d8df21d07ad4acd Mon Sep 17 00:00:00 2001 From: Yana De Pauw Date: Thu, 28 Mar 2019 11:13:35 +0100 Subject: [PATCH 106/188] Fix check style issues in RelationShipTypeBuilder --- .../dspace/app/rest/builder/RelationshipTypeBuilder.java | 6 ++++-- dspace-spring-rest/test.csv | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 dspace-spring-rest/test.csv diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipTypeBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipTypeBuilder.java index 222f850827..22011a5fa7 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipTypeBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipTypeBuilder.java @@ -75,7 +75,8 @@ public class RelationshipTypeBuilder extends AbstractBuilder Date: Tue, 28 Aug 2018 13:38:50 -0400 Subject: [PATCH 107/188] DS-3658 Configure ReindexerThread disable reindex --- .../org/dspace/storage/rdbms/DatabaseUtils.java | 15 ++++++++------- dspace/config/modules/discovery.cfg | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java index f4b0936c6f..cadd3eee52 100644 --- a/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java +++ b/dspace-api/src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java @@ -1190,14 +1190,15 @@ public class DatabaseUtils { *

* Because the DB migration may be initialized by commandline or any one of * the many DSpace webapps, this checks for the existence of a temporary - * file to know when Discovery/Solr needs reindexing. - * - * @return whether reindex flag is true/false + * file, and the discovery.autoReindex setting to know when + * Discovery/Solr needs reindexing. + * @return whether reindexing should happen. */ public static boolean getReindexDiscovery() { - // Simply check if the flag file exists - File reindexFlag = new File(reindexDiscoveryFilePath); - return reindexFlag.exists(); + boolean autoReindex = DSpaceServicesFactory.getInstance() + .getConfigurationService() + .getBooleanProperty("discovery.autoReindex", true); + return (autoReindex && new File(reindexDiscoveryFilePath).exists()); } /** @@ -1222,7 +1223,7 @@ public class DatabaseUtils { /** * Internal class to actually perform re-indexing in a separate thread. - * (See checkReindexDiscovery() method)> + * (See checkReindexDiscovery() method). */ private static class ReindexerThread extends Thread { private final IndexingService indexer; diff --git a/dspace/config/modules/discovery.cfg b/dspace/config/modules/discovery.cfg index b9d35a65df..44bb264f8e 100644 --- a/dspace/config/modules/discovery.cfg +++ b/dspace/config/modules/discovery.cfg @@ -22,3 +22,5 @@ discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued # 1) you need to set the DiscoverySearchRequestProcessor in the dspace.cfg # 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection # Processors plugin in the dspace.cfg + +#discovery.autoReindex = false \ No newline at end of file From 0324787e3593af869f2ca63a8eacbeb6ca355d6a Mon Sep 17 00:00:00 2001 From: Andrew Wood Date: Tue, 28 Aug 2018 15:14:28 -0400 Subject: [PATCH 108/188] DS-3658 Document new property reflect default behavior in value --- dspace/config/modules/discovery.cfg | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dspace/config/modules/discovery.cfg b/dspace/config/modules/discovery.cfg index 44bb264f8e..93a74c89b7 100644 --- a/dspace/config/modules/discovery.cfg +++ b/dspace/config/modules/discovery.cfg @@ -23,4 +23,6 @@ discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued # 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection # Processors plugin in the dspace.cfg -#discovery.autoReindex = false \ No newline at end of file +#Allow auto-reindexing +#Defaults to true: auto-reindexing is enabled +#discovery.autoReindex = true \ No newline at end of file From 77928c256053da58e83d1faae18dbdba81fb6076 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 27 Mar 2019 15:45:42 -0500 Subject: [PATCH 109/188] Add info about how/when auto-reindexing takes place --- dspace/config/modules/discovery.cfg | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dspace/config/modules/discovery.cfg b/dspace/config/modules/discovery.cfg index 93a74c89b7..7ca1292069 100644 --- a/dspace/config/modules/discovery.cfg +++ b/dspace/config/modules/discovery.cfg @@ -23,6 +23,9 @@ discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued # 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection # Processors plugin in the dspace.cfg -#Allow auto-reindexing -#Defaults to true: auto-reindexing is enabled -#discovery.autoReindex = true \ No newline at end of file +# Allow auto-reindexing +# When enabled, if any database migrations are applied to your database (via Flyway), then a reindex flag +# is written to [dspace]/solr/search/conf/reindex.flag. Whenever the DSpace webapp is (re)started, it checks +# for the existence of that file. If found, a background reindex of all content is triggered in Discovery. +# Defaults to true: auto-reindexing is enabled. +#discovery.autoReindex = true From 4fc6ebc28c226c7e50fc33dd7da859edde2b16c9 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Fri, 5 Apr 2019 15:46:18 +0200 Subject: [PATCH 110/188] Intermediary Commit --- .../dspace/content/service/DSpaceObjectService.java | 10 ++++++++++ .../dspace/app/rest/builder/ClaimedTaskBuilder.java | 10 +++++----- .../org/dspace/app/rest/builder/PoolTaskBuilder.java | 10 +++++----- .../dspace/app/rest/builder/WorkflowItemBuilder.java | 10 +++++----- dspace-spring-rest/test.csv | 2 +- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java index 58a28f7b0f..96ccd3c83a 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/DSpaceObjectService.java @@ -40,6 +40,16 @@ public interface DSpaceObjectService extends BrowsableOb */ public abstract String getName(T dso); + /** + * Generic find for when the precise type of a BDSO is not known, just the + * a pair of type number and database ID. + * + * @param context - the context + * @param id - id within table of type'd objects + * @return the object found, or null if it does not exist. + * @throws SQLException only upon failure accessing the database. + */ + public T find(Context context, UUID id) throws SQLException; /** * Tries to lookup all Identifiers of this DSpaceObject. diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java index b36a5cac41..d1828be94e 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java @@ -14,7 +14,7 @@ import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; import org.dspace.content.LicenseUtils; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -175,19 +175,19 @@ public class ClaimedTaskBuilder extends AbstractBuilder } public PoolTaskBuilder withTitle(final String title) { - return setMetadataSingleValue(MetadataSchema.DC_SCHEMA, "title", null, title); + return setMetadataSingleValue(MetadataSchemaEnum.DC.getName(), "title", null, title); } public PoolTaskBuilder withIssueDate(final String issueDate) { - return addMetadataValue(MetadataSchema.DC_SCHEMA, "date", "issued", new DCDate(issueDate).toString()); + return addMetadataValue(MetadataSchemaEnum.DC.getName(), "date", "issued", new DCDate(issueDate).toString()); } public PoolTaskBuilder withAuthor(final String authorName) { - return addMetadataValue(MetadataSchema.DC_SCHEMA, "contributor", "author", authorName); + return addMetadataValue(MetadataSchemaEnum.DC.getName(), "contributor", "author", authorName); } public PoolTaskBuilder withSubject(final String subject) { - return addMetadataValue(MetadataSchema.DC_SCHEMA, "subject", null, subject); + return addMetadataValue(MetadataSchemaEnum.DC.getName(), "subject", null, subject); } public PoolTaskBuilder grantLicense() { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java index e5026ea00a..c331143d92 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java @@ -17,7 +17,7 @@ import org.dspace.content.Collection; import org.dspace.content.DCDate; import org.dspace.content.Item; import org.dspace.content.LicenseUtils; -import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.WorkspaceItem; import org.dspace.core.Context; import org.dspace.discovery.SearchServiceException; @@ -145,19 +145,19 @@ public class WorkflowItemBuilder extends AbstractBuilder Date: Mon, 8 Apr 2019 14:56:23 +0200 Subject: [PATCH 111/188] Fixed tests and refactored the way priorities work in the builders --- .../app/rest/builder/AbstractBuilder.java | 37 +++----- .../builder/AbstractDSpaceObjectBuilder.java | 2 +- .../app/rest/builder/BitstreamBuilder.java | 3 +- .../rest/builder/BitstreamFormatBuilder.java | 2 +- .../app/rest/builder/ClaimedTaskBuilder.java | 10 +-- .../app/rest/builder/CollectionBuilder.java | 11 +-- .../app/rest/builder/CommunityBuilder.java | 3 +- .../app/rest/builder/EPersonBuilder.java | 12 +-- .../app/rest/builder/EntityTypeBuilder.java | 8 +- .../dspace/app/rest/builder/GroupBuilder.java | 13 +-- .../dspace/app/rest/builder/ItemBuilder.java | 3 +- .../rest/builder/MetadataFieldBuilder.java | 8 +- .../rest/builder/MetadataSchemaBuilder.java | 7 +- .../app/rest/builder/PoolTaskBuilder.java | 10 +-- .../app/rest/builder/RelationshipBuilder.java | 3 +- .../rest/builder/RelationshipTypeBuilder.java | 8 +- .../dspace/app/rest/builder/SiteBuilder.java | 2 +- .../app/rest/builder/WorkflowItemBuilder.java | 9 +- .../rest/builder/WorkspaceItemBuilder.java | 10 +-- .../util/AbstractBuilderCleanupUtil.java | 90 +++++++++++++++++++ dspace-spring-rest/test.csv | 2 +- 21 files changed, 132 insertions(+), 121 deletions(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/util/AbstractBuilderCleanupUtil.java diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java index 25206a7055..96d0c48c72 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractBuilder.java @@ -7,12 +7,11 @@ */ package org.dspace.app.rest.builder; -import java.util.Comparator; -import java.util.LinkedList; import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.logging.log4j.Logger; +import org.dspace.app.rest.builder.util.AbstractBuilderCleanupUtil; import org.dspace.authorize.factory.AuthorizeServiceFactory; import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.ResourcePolicyService; @@ -86,7 +85,11 @@ public abstract class AbstractBuilder { protected Context context; - private static List builders = new LinkedList<>(); + /** + * This static class will make sure that the objects built with the builders are disposed of in a foreign-key + * constraint safe manner by predefining an order + */ + private static AbstractBuilderCleanupUtil abstractBuilderCleanupUtil = new AbstractBuilderCleanupUtil(); /** * log4j category */ @@ -94,7 +97,8 @@ public abstract class AbstractBuilder { protected AbstractBuilder(Context context) { this.context = context; - builders.add(this); + //Register this specific builder to be deleted later on + abstractBuilderCleanupUtil.addToMap(this); } public static void init() { @@ -161,16 +165,9 @@ public abstract class AbstractBuilder { } public static void cleanupObjects() throws Exception { - builders.sort(new Comparator() { - @Override - public int compare(AbstractBuilder o1, AbstractBuilder o2) { - // we want descending order, hight priority first - return o2.getPriority() - o1.getPriority(); - } - }); - for (AbstractBuilder builder : builders) { - builder.cleanup(); - } + + // This call will make sure that the map with AbstractBuilders will be cleaned up + abstractBuilderCleanupUtil.cleanupBuilders(); // Bitstreams still leave a trace when deleted, so we need to fully "expunge" them try (Context c = new Context()) { @@ -188,16 +185,10 @@ public abstract class AbstractBuilder { } /** - * Return the priority to give to the builder during the cleanup phase. It MUST be a positive integer. High values - * mean that the builder will be invoked soon during the cleanup phase - * - * @return + * This method will ensure that the DSpaceObject contained within the Builder will be cleaned up properly + * @throws Exception If something goes wrong */ - protected int getPriority() { - return 100; - } - - protected abstract void cleanup() throws Exception; + public abstract void cleanup() throws Exception; public abstract T build(); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java index f74d09adfc..b61cb041f2 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/AbstractDSpaceObjectBuilder.java @@ -41,7 +41,7 @@ public abstract class AbstractDSpaceObjectBuilder this.context = context; } - protected abstract void cleanup() throws Exception; + public abstract void cleanup() throws Exception; protected abstract DSpaceObjectService getService(); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java index 080a6d68c3..f472ae987b 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamBuilder.java @@ -120,7 +120,8 @@ public class BitstreamBuilder extends AbstractDSpaceObjectBuilder { return bitstream; } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { delete(bitstream); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java index b0d169bfb8..5635386ae2 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/BitstreamFormatBuilder.java @@ -31,7 +31,7 @@ public class BitstreamFormatBuilder extends AbstractCRUDBuilder } @Override - protected void cleanup() throws Exception { + public void cleanup() throws Exception { delete(bitstreamFormat); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java index d1828be94e..fa52905d8f 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ClaimedTaskBuilder.java @@ -136,7 +136,7 @@ public class ClaimedTaskBuilder extends AbstractBuilder { return collection; } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { deleteWorkflowGroups(collection); delete(collection); } @@ -123,12 +124,4 @@ public class CollectionBuilder extends AbstractDSpaceObjectBuilder { protected DSpaceObjectService getService() { return collectionService; } - - @Override - /** - * Collection must be deleted before community - */ - protected int getPriority() { - return 150; - } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java index a517d71f2a..420e614e0b 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java @@ -83,7 +83,8 @@ public class CommunityBuilder extends AbstractDSpaceObjectBuilder { return community; } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { delete(community); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java index 4f4f740e21..025bac7096 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EPersonBuilder.java @@ -24,7 +24,8 @@ public class EPersonBuilder extends AbstractDSpaceObjectBuilder { super(context); } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { delete(ePerson); } @@ -88,13 +89,4 @@ public class EPersonBuilder extends AbstractDSpaceObjectBuilder { ePersonService.setPassword(ePerson, password); return this; } - - @Override - /** - * Set a lower custom priority for the EPerson. It is one of the last object to delete to reduced the risk of - * pending references - */ - protected int getPriority() { - return 50; - } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java index f11cdb090d..36b1e48f85 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/EntityTypeBuilder.java @@ -32,7 +32,8 @@ public class EntityTypeBuilder extends AbstractBuilder { } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { delete(group); } @@ -104,14 +105,4 @@ public class GroupBuilder extends AbstractDSpaceObjectBuilder { } } - /** - * Set a lower custom priority for the Group. It could be referenced in several places. It needs to go first than - * EPersonBuilder - * - */ - @Override - protected int getPriority() { - return 80; - } - } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java index 0faa7b22cc..aef0a5ce58 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/ItemBuilder.java @@ -129,7 +129,8 @@ public class ItemBuilder extends AbstractDSpaceObjectBuilder { } } - protected void cleanup() throws Exception { + @Override + public void cleanup() throws Exception { delete(item); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java index 9a8c6bd3a4..1476cf0f24 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/MetadataFieldBuilder.java @@ -26,12 +26,6 @@ public class MetadataFieldBuilder extends AbstractBuilder @Override - protected void cleanup() throws Exception { + public void cleanup() throws Exception { if (workspaceItem != null) { deleteWsi(workspaceItem); } @@ -192,12 +192,4 @@ public class PoolTaskBuilder extends AbstractBuilder } return this; } - - @Override - /** - * Set a higher priority than workflowitem for the pooltask has it holds a reference to it - */ - protected int getPriority() { - return 300; - } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java index 2e51b536a0..f792f7e8ab 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/RelationshipBuilder.java @@ -34,7 +34,8 @@ public class RelationshipBuilder extends AbstractBuilder byRelationshipType = relationshipService.findByRelationshipType(context, relationshipType); for (Relationship relationship : byRelationshipType) { @@ -103,9 +104,4 @@ public class RelationshipTypeBuilder extends AbstractBuilder { } @Override - protected void cleanup() throws Exception { + public void cleanup() throws Exception { //Do nothing } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java index c331143d92..eaa41ef3e3 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkflowItemBuilder.java @@ -108,7 +108,7 @@ public class WorkflowItemBuilder extends AbstractBuilder> map = new LinkedHashMap<>(); + + /** + * Constructor that will initialize the Map with a predefined order for deletion + */ + public AbstractBuilderCleanupUtil() { + map.put(RelationshipBuilder.class.getName(), new LinkedList<>()); + map.put(RelationshipTypeBuilder.class.getName(), new LinkedList<>()); + map.put(EntityTypeBuilder.class.getName(), new LinkedList<>()); + map.put(PoolTaskBuilder.class.getName(), new LinkedList<>()); + map.put(WorkflowItemBuilder.class.getName(), new LinkedList<>()); + map.put(WorkspaceItemBuilder.class.getName(), new LinkedList<>()); + map.put(BitstreamBuilder.class.getName(), new LinkedList<>()); + map.put(BitstreamFormatBuilder.class.getName(), new LinkedList<>()); + map.put(ClaimedTaskBuilder.class.getName(), new LinkedList<>()); + map.put(CollectionBuilder.class.getName(), new LinkedList<>()); + map.put(CommunityBuilder.class.getName(), new LinkedList<>()); + map.put(EPersonBuilder.class.getName(), new LinkedList<>()); + map.put(GroupBuilder.class.getName(), new LinkedList<>()); + map.put(ItemBuilder.class.getName(), new LinkedList<>()); + map.put(MetadataFieldBuilder.class.getName(), new LinkedList<>()); + map.put(MetadataSchemaBuilder.class.getName(), new LinkedList<>()); + map.put(SiteBuilder.class.getName(), new LinkedList<>()); + + } + + /** + * Adds a builder to the map. + * This will make a new linkedList if the name doesn't exist yet as a key in the map with a list, if it already + * exists it will simply add the AbstractBuilder to that list. + * @param abstractBuilder The AbstractBuilder to be added + */ + public void addToMap(AbstractBuilder abstractBuilder) { + map.computeIfAbsent(abstractBuilder.getClass().getName(), k -> new LinkedList<>()).add(abstractBuilder); + } + + /** + * This method takes care of iterating over all the AbstractBuilders in the predefined order and calls + * the cleanup method to delete the objects from the database. + * @throws Exception If something goes wrong + */ + public void cleanupBuilders() throws Exception { + for (Map.Entry> entry : map.entrySet()) { + List list = entry.getValue(); + for (AbstractBuilder abstractBuilder : list) { + abstractBuilder.cleanup(); + } + } + } +} diff --git a/dspace-spring-rest/test.csv b/dspace-spring-rest/test.csv index cef084d3ad..c3cde716c2 100644 --- a/dspace-spring-rest/test.csv +++ b/dspace-spring-rest/test.csv @@ -1,2 +1,2 @@ id,collection,dc.title,relationship.type,relation.isAuthorOfPublication -ef0260c4-162c-4e2a-87c6-6874c2d4b189,123456789/242,Article,Publication,dd850f5d-7db0-42b5-b9e3-7a5c0f036267||6c6850b5-e50c-43e7-ae8e-da19e7aca29b||e6fddeda-9039-426f-bb45-fb23d85d6a9d +1f415faa-c16d-4eb8-86b4-9d0d181ebff4,123456789/674,Article,Publication,b19a67d7-6a35-42ad-9acd-0eed29de69e0||f0fad09c-a585-43bf-9931-1c0ba522bb78||da4fe4c3-ed11-4263-b211-1039937168a4 From 92cb9730fb6a45f2bfa8f5ed5ca7c29ff2b315fb Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 8 Apr 2019 16:16:13 +0200 Subject: [PATCH 112/188] Changed the URI parsing to better fit a generic approach on Repository level --- .../app/rest/RestResourceController.java | 9 +- .../rest/repository/DSpaceRestRepository.java | 19 ++--- .../RelationshipRestRepository.java | 8 +- .../WorkflowItemRestRepository.java | 7 +- .../app/rest/submit/SubmissionService.java | 84 ++++++++----------- .../java/org/dspace/app/rest/utils/Utils.java | 19 ++--- .../org/dspace/app/rest/UriListParsingIT.java | 4 +- dspace-spring-rest/test.csv | 2 +- 8 files changed, 69 insertions(+), 83 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index 7585f44f1b..0d932690cd 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -51,7 +51,6 @@ import org.dspace.app.rest.repository.LinkRestRepository; import org.dspace.app.rest.utils.RestRepositoryUtils; import org.dspace.app.rest.utils.Utils; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.DSpaceObject; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -474,9 +473,9 @@ public class RestResourceController implements InitializingBean { checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; - List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); + List stringListFromRequest = utils.getStringListFromRequest(request); try { - modelObject = repository.createAndReturn(dSpaceObjectList); + modelObject = repository.createAndReturn(stringListFromRequest); } catch (ClassCastException e) { log.error("Something went wrong whilst creating the object for apiCategory: " + apiCategory + " and model: " + model, e); @@ -1207,8 +1206,8 @@ public class RestResourceController implements InitializingBean { checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; - List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(request); - modelObject = repository.put(request, apiCategory, model, id, dSpaceObjectList); + List stringList = utils.getStringListFromRequest(request); + modelObject = repository.put(request, apiCategory, model, id, stringList); if (modelObject == null) { throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 46ffb527bb..c9d99992de 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -26,7 +26,6 @@ import org.dspace.app.rest.model.hateoas.DSpaceResource; import org.dspace.app.rest.model.patch.Patch; import org.dspace.app.util.DCInputsReaderException; import org.dspace.authorize.AuthorizeException; -import org.dspace.content.DSpaceObject; import org.dspace.content.service.MetadataFieldService; import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; @@ -264,10 +263,10 @@ public abstract class DSpaceRestRepository list) { + public T createAndReturn(List list) { Context context = null; try { context = obtainContext(); @@ -307,14 +306,14 @@ public abstract class DSpaceRestRepository list) + protected T createAndReturn(Context context, List list) throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); } @@ -498,14 +497,14 @@ public abstract class DSpaceRestRepository dSpaceObjects) { + List stringList) { Context context = obtainContext(); try { - thisRepository.put(context, request, apiCategory, model, id, dSpaceObjects); + thisRepository.put(context, request, apiCategory, model, id, stringList); context.commit(); } catch (SQLException | AuthorizeException e) { throw new RuntimeException(e.getMessage(), e); @@ -540,7 +539,7 @@ public abstract class DSpaceRestRepository dSpaceObjects) + List stringList) throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException { throw new RepositoryMethodNotImplementedException(apiCategory, model); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index ed367bcfb4..c96dc8c047 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -93,11 +93,11 @@ public class RelationshipRestRepository extends DSpaceRestRepository list) + protected RelationshipRest createAndReturn(Context context, List stringList) throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException { HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest(); - + List list = utils.constructDSpaceObjectList(context, stringList); if (list.size() == 2 && list.get(0).getType() == Constants.ITEM && list.get(1).getType() == Constants.ITEM) { Item leftItem = (Item) list.get(0); Item rightItem = (Item) list.get(1); @@ -131,14 +131,14 @@ public class RelationshipRestRepository extends DSpaceRestRepository dSpaceObjects) + Integer id, List stringList) throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException { Relationship relationship = relationshipService.find(context, id); if (relationship == null) { throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); } - + List dSpaceObjects = utils.constructDSpaceObjectList(context, stringList); if (dSpaceObjects.size() == 2 && dSpaceObjects.get(0).getType() == Constants.ITEM && dSpaceObjects.get(1).getType() == Constants.ITEM) { Item leftItem = (Item) dSpaceObjects.get(0); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java index b847338df6..e5fa4b9d7c 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkflowItemRestRepository.java @@ -144,10 +144,13 @@ public class WorkflowItemRestRepository extends DSpaceRestRepository stringList) { XmlWorkflowItem source; + if (stringList.isEmpty()) { + throw new UnprocessableEntityException("The given URI list could not be parsed and is empty as a result"); + } try { - source = submissionService.createWorkflowItem(context, getRequestService().getCurrentRequest()); + source = submissionService.createWorkflowItem(context, stringList.get(0)); } catch (AuthorizeException e) { throw new RESTAuthorizationException(e); } catch (WorkflowException e) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java index c704007bf4..eecf0f5424 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java @@ -8,7 +8,6 @@ package org.dspace.app.rest.submit; import java.io.IOException; -import java.io.Reader; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; @@ -196,63 +195,48 @@ public class SubmissionService { * * @param context * the dspace context - * @param currentRequest - * the request containing the details about the workspace to create + * @param requestUriListString + * the id of the workspaceItem * @return * @throws SQLException * @throws AuthorizeException * @throws WorkflowException */ - public XmlWorkflowItem createWorkflowItem(Context context, Request currentRequest) + public XmlWorkflowItem createWorkflowItem(Context context, String requestUriListString) throws SQLException, AuthorizeException, WorkflowException { - Reader reader = null; XmlWorkflowItem wi = null; - try { - //FIXME use utility method to extract the ID from the text/uri-list body - reader = currentRequest.getHttpServletRequest().getReader(); - char[] arr = new char[1024]; - StringBuilder buffer = new StringBuilder(); - int numCharsRead = reader.read(arr, 0, arr.length); - if (numCharsRead > 0) { - buffer.append(arr, 0, numCharsRead); - } - if (numCharsRead == arr.length) { - throw new UnprocessableEntityException("Malformed body... too long"); - } - String regex = "\\/api\\/" + WorkspaceItemRest.CATEGORY + "\\/" + English.plural(WorkspaceItemRest.NAME) - + "\\/"; - String[] split = buffer.toString().split(regex, 2); - if (split.length != 2) { - throw new UnprocessableEntityException("Malformed body..." + buffer); - } - // END FIXME - WorkspaceItem wsi = null; - try { - wsi = workspaceItemService.find(context, Integer.parseInt(split[1])); - } catch (NumberFormatException e) { - throw new UnprocessableEntityException("The provided workspaceitem URI is not valid"); - } - if (wsi == null) { - throw new UnprocessableEntityException("Workspace item is not found"); - } - if (!workspaceItemConverter.convert(wsi).getErrors().isEmpty()) { - throw new UnprocessableEntityException( - "Start workflow failed due to validation error on workspaceitem"); - } - - wi = workflowService.start(context, wsi); - - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - throw new RuntimeException(e.getMessage(), e); - } - } + if (StringUtils.isBlank(requestUriListString)) { + throw new UnprocessableEntityException("Malformed body..." + requestUriListString); } + String regex = "\\/api\\/" + WorkspaceItemRest.CATEGORY + "\\/" + English.plural(WorkspaceItemRest.NAME) + + "\\/"; + String[] split = requestUriListString.split(regex, 2); + if (split.length != 2) { + throw new UnprocessableEntityException("Malformed body..." + requestUriListString); + } + WorkspaceItem wsi = null; + int id = 0; + try { + id = Integer.parseInt(split[1]); + wsi = workspaceItemService.find(context, id); + } catch (NumberFormatException e) { + throw new UnprocessableEntityException("The provided workspaceitem URI is not valid"); + } + if (wsi == null) { + throw new UnprocessableEntityException("Workspace item is not found"); + } + if (!workspaceItemConverter.convert(wsi).getErrors().isEmpty()) { + throw new UnprocessableEntityException( + "Start workflow failed due to validation error on workspaceitem"); + } + + try { + wi = workflowService.start(context, wsi); + } catch (IOException e) { + throw new RuntimeException("The workflow could not be started for workspaceItem with" + + "id: " + id); + } + return wi; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java index 6f18b016ab..2823925792 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/Utils.java @@ -247,14 +247,7 @@ public class Utils { * @param request The request out of which we'll create the List of DSpaceObjects * @return The resulting list of DSpaceObjects that we parsed out of the request */ - private List constructDSpaceObjectList(Context context, HttpServletRequest request) { - List list = null; - try { - list = readFromRequest(request); - } catch (IOException e) { - log.error("Something went wrong with reading in the inputstream from the request", e); - } - + public List constructDSpaceObjectList(Context context, List list) { List dSpaceObjects = new LinkedList<>(); for (String string : list) { if (string.endsWith("/")) { @@ -312,7 +305,13 @@ public class Utils { * @return The list of DSpaceObjects that we could find in the InputStream * @throws IOException If something goes wrong */ - public List getdSpaceObjectsFromRequest(HttpServletRequest request) { - return constructDSpaceObjectList(ContextUtil.obtainContext(request), request); + public List getStringListFromRequest(HttpServletRequest request) { + List list = null; + try { + list = readFromRequest(request); + } catch (IOException e) { + log.error("Something went wrong with reading in the inputstream from the request", e); + } + return list; } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java index 6e51b61ccd..33aa52dfec 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/UriListParsingIT.java @@ -17,6 +17,7 @@ import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; import org.dspace.app.rest.builder.ItemBuilder; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.Utils; import org.dspace.content.Collection; import org.dspace.content.Community; @@ -74,7 +75,8 @@ public class UriListParsingIT extends AbstractControllerIntegrationTest { "https://localhost:8080/spring-rest/api/core/items/" + publicItem2.getID(); mockRequest.setContentType("text/uri-list"); mockRequest.setContent(uriListString.getBytes()); - List dSpaceObjectList = utils.getdSpaceObjectsFromRequest(mockRequest); + List dSpaceObjectList = utils.constructDSpaceObjectList( + ContextUtil.obtainContext(mockRequest), utils.getStringListFromRequest(mockRequest)); assertThat("DSpaceObject List is of size 2" ,dSpaceObjectList.size(), equalTo(2)); assertThat("DSpaceObject 1 is an item", dSpaceObjectList.get(0).getType(), equalTo(Constants.ITEM)); assertThat("DSpaceObject 2 is an item", dSpaceObjectList.get(1).getType(), equalTo(Constants.ITEM)); diff --git a/dspace-spring-rest/test.csv b/dspace-spring-rest/test.csv index c3cde716c2..7404229297 100644 --- a/dspace-spring-rest/test.csv +++ b/dspace-spring-rest/test.csv @@ -1,2 +1,2 @@ id,collection,dc.title,relationship.type,relation.isAuthorOfPublication -1f415faa-c16d-4eb8-86b4-9d0d181ebff4,123456789/674,Article,Publication,b19a67d7-6a35-42ad-9acd-0eed29de69e0||f0fad09c-a585-43bf-9931-1c0ba522bb78||da4fe4c3-ed11-4263-b211-1039937168a4 +636e440b-f554-4c27-9b9f-1696b18adbb2,123456789/674,Article,Publication,9cb4955a-abbd-40a0-b1aa-124e7ff83c1d||bb7053bf-7963-464a-bd70-2253d6b3cb37||77020ca8-f04e-4370-b259-d05b4939bab1 From 750bdecbc09236c3e21f212d28b4a51fcbf311cb Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 9 Apr 2019 14:16:37 +0200 Subject: [PATCH 113/188] Moved the virtual metadata populator xml logic to a separate file --- dspace/config/spring/api/core-services.xml | 255 ----------------- dspace/config/spring/api/virtual-metadata.xml | 263 ++++++++++++++++++ 2 files changed, 263 insertions(+), 255 deletions(-) create mode 100644 dspace/config/spring/api/virtual-metadata.xml diff --git a/dspace/config/spring/api/core-services.xml b/dspace/config/spring/api/core-services.xml index 21ffd0d781..43959b25fd 100644 --- a/dspace/config/spring/api/core-services.xml +++ b/dspace/config/spring/api/core-services.xml @@ -112,260 +112,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - person.identifier.lastname - person.identifier.firstname - - - - , - - - - - - - - - - - - orgunit.identifier.name - - - - - - - - - - - - person.identifier.lastname - person.identifier.firstname - - - - , - - - - - - - - - - - orgunit.identifier.name - - - - - - - - - - - orgunit.identifier.name - - - - - - - - - - - - - - journalvolume.identifier.volume - - - - - - - - - - - - - - - - - - - - - - - - journal.identifier.issn - - - - - - - journal.identifier.name - - - - - - - - - - - - - - journalissue.identifier.number - - - - - - - - - - - - - - journalvolume.identifier.name - - - - , - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dspace/config/spring/api/virtual-metadata.xml b/dspace/config/spring/api/virtual-metadata.xml new file mode 100644 index 0000000000..676626f3c8 --- /dev/null +++ b/dspace/config/spring/api/virtual-metadata.xml @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + person.identifier.lastname + person.identifier.firstname + + + + , + + + + + + + + + + + + orgunit.identifier.name + + + + + + + + + + + + person.identifier.lastname + person.identifier.firstname + + + + , + + + + + + + + + + + orgunit.identifier.name + + + + + + + + + + + orgunit.identifier.name + + + + + + + + + + + + + + journalvolume.identifier.volume + + + + + + + + + + + + + + + + + + + + + + + + journal.identifier.issn + + + + + + + journal.identifier.name + + + + + + + + + + + + + + journalissue.identifier.number + + + + + + + + + + + + + + journalvolume.identifier.name + + + + , + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a23a8821e615d4091e9c3c2ea6af74ecc4062c71 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 9 Apr 2019 15:16:17 +0200 Subject: [PATCH 114/188] Feedback on PR-2376 --- .../org/dspace/app/bulkedit/MetadataImport.java | 10 ++++------ .../org/dspace/app/util/InitializeEntities.java | 3 +-- .../java/org/dspace/content/EntityServiceImpl.java | 12 ++++++------ .../dspace/content/RelationshipTypeServiceImpl.java | 2 +- .../org/dspace/content/dao/RelationshipTypeDAO.java | 2 +- .../content/dao/impl/RelationshipTypeDAOImpl.java | 2 +- .../config/entities/relationship-types.dtd | 13 +++++++++++++ .../config/entities/relationship-types.xml | 2 ++ .../dspace/app/rest/RootRestResourceController.java | 2 -- .../dspace/app/rest/converter/ItemConverter.java | 2 +- dspace-spring-rest/test.csv | 2 -- 11 files changed, 30 insertions(+), 22 deletions(-) create mode 100644 dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.dtd delete mode 100644 dspace-spring-rest/test.csv 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 037f2c7902..e1b1224809 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 @@ -730,17 +730,16 @@ public class MetadataImport { } if (acceptableRelationshipTypes.size() > 1) { - System.out.println("Ambiguous relationship_types were found"); log.error("Ambiguous relationship_types were found"); return; } if (acceptableRelationshipTypes.size() == 0) { - System.out.println("no relationship_types were found"); log.error("no relationship_types were found"); return; } - buildRelationObject(c, item, value, left, acceptableRelationshipTypes); + //There is exactly one + buildRelationObject(c, item, value, left, acceptableRelationshipTypes.get(0)); } /** @@ -749,16 +748,15 @@ public class MetadataImport { * @param item The item for which this relationship will be constructed * @param value The value for the relationship * @param left A boolean indicating whether the item is the leftItem or the rightItem - * @param acceptableRelationshipTypes The acceptable relationship types + * @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, String value, boolean left, - List acceptableRelationshipTypes) + RelationshipType acceptedRelationshipType) throws SQLException, AuthorizeException { Item leftItem = null; Item rightItem = null; - RelationshipType acceptedRelationshipType = acceptableRelationshipTypes.get(0); if (left) { leftItem = item; rightItem = itemService.findByIdOrLegacyId(c, value); diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index b43e67ad02..c8e14b81d2 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -124,7 +124,6 @@ public class InitializeEntities { relationshipTypeService.update(context, relationshipTypeFromDb); } } - context.commit(); context.complete(); } @@ -187,7 +186,7 @@ public class InitializeEntities { } return relationshipTypes; } catch (ParserConfigurationException | SAXException | IOException | SQLException e) { - log.error(e, e); + log.error("An error occurred while parsing the XML file to relations", e); } return null; } diff --git a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java index 5339fb440e..5a00616229 100644 --- a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java @@ -59,7 +59,7 @@ public class EntityServiceImpl implements EntityService { List fullList = this.getAllRelations(context, entity); List listToReturn = new LinkedList<>(); for (Relationship relationship : fullList) { - if (relationship.getLeftItem() == entity.getItem()) { + if (relationship.getLeftItem().getID() == entity.getItem().getID()) { listToReturn.add(relationship); } } @@ -70,7 +70,7 @@ public class EntityServiceImpl implements EntityService { List fullList = this.getAllRelations(context, entity); List listToReturn = new LinkedList<>(); for (Relationship relationship : fullList) { - if (relationship.getRightItem() == entity.getItem()) { + if (relationship.getRightItem().getID() == entity.getItem().getID()) { listToReturn.add(relationship); } } @@ -94,8 +94,8 @@ public class EntityServiceImpl implements EntityService { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { - if (relationshipType.getLeftType() == entityType || - relationshipType.getRightType() == entityType) { + if (relationshipType.getLeftType().getID() == entityType.getID() || + relationshipType.getRightType().getID() == entityType.getID()) { listToReturn.add(relationshipType); } } @@ -106,7 +106,7 @@ public class EntityServiceImpl implements EntityService { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { - if (relationshipType.getLeftType() == entityType) { + if (relationshipType.getLeftType().getID() == entityType.getID()) { listToReturn.add(relationshipType); } } @@ -117,7 +117,7 @@ public class EntityServiceImpl implements EntityService { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { - if (relationshipType.getRightType() == entityType) { + if (relationshipType.getRightType().getID() == entityType.getID()) { listToReturn.add(relationshipType); } } diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index f26df2a223..d505c3df12 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -48,7 +48,7 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { @Override public RelationshipType findbyTypesAndLabels(Context context,EntityType leftType,EntityType rightType, String leftLabel,String rightLabel) throws SQLException { - return relationshipTypeDAO.findbyTypesAndLabels(context, leftType, rightType, leftLabel, rightLabel); + return relationshipTypeDAO.findByTypesAndLabels(context, leftType, rightType, leftLabel, rightLabel); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java index f3193594df..d3be8f233b 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/RelationshipTypeDAO.java @@ -34,7 +34,7 @@ public interface RelationshipTypeDAO extends GenericDAO { * @return The RelationshipType object that matches all the given parameters * @throws SQLException If something goes wrong */ - RelationshipType findbyTypesAndLabels(Context context, + RelationshipType findByTypesAndLabels(Context context, EntityType leftType,EntityType rightType,String leftLabel,String rightLabel) throws SQLException; diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java index 7914040fa0..b4eaece569 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/RelationshipTypeDAOImpl.java @@ -23,7 +23,7 @@ import org.dspace.core.Context; public class RelationshipTypeDAOImpl extends AbstractHibernateDAO implements RelationshipTypeDAO { @Override - public RelationshipType findbyTypesAndLabels(Context context, EntityType leftType, EntityType rightType, + public RelationshipType findByTypesAndLabels(Context context, EntityType leftType, EntityType rightType, String leftLabel, String rightLabel) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); diff --git a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.dtd b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.dtd new file mode 100644 index 0000000000..021ad2267c --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.dtd @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml index 6f71b3e19c..0a0d70c929 100644 --- a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml +++ b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types.xml @@ -1,4 +1,6 @@ + + Publication diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java index 93eb7c3c55..e81522d286 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java @@ -41,8 +41,6 @@ public class RootRestResourceController { @Autowired RootRestRepository rootRestRepository; - private static Logger log = LogManager.getLogger(); - @RequestMapping(method = RequestMethod.GET) public RootResource listDefinedEndpoint(HttpServletRequest request) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index 33a083ff64..fd9f3bd899 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -86,7 +86,7 @@ public class ItemConverter extends DSpaceObjectConverter relationshipRestList = new LinkedList<>(); for (Relationship relationship : relationships) { diff --git a/dspace-spring-rest/test.csv b/dspace-spring-rest/test.csv deleted file mode 100644 index 7404229297..0000000000 --- a/dspace-spring-rest/test.csv +++ /dev/null @@ -1,2 +0,0 @@ -id,collection,dc.title,relationship.type,relation.isAuthorOfPublication -636e440b-f554-4c27-9b9f-1696b18adbb2,123456789/674,Article,Publication,9cb4955a-abbd-40a0-b1aa-124e7ff83c1d||bb7053bf-7963-464a-bd70-2253d6b3cb37||77020ca8-f04e-4370-b259-d05b4939bab1 From 62c0f0714d5bdee96195dc3c50f7dafd7c0bc6ef Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 9 Apr 2019 16:01:56 +0200 Subject: [PATCH 115/188] Feedback on PR-2376 --- .../java/org/dspace/app/rest/RootRestResourceController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java index e81522d286..0f8d770b37 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RootRestResourceController.java @@ -9,8 +9,6 @@ package org.dspace.app.rest; import javax.servlet.http.HttpServletRequest; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.model.RootRest; import org.dspace.app.rest.model.hateoas.RootResource; From cfd4e0b435c9bec1984ea1b836a46b7a97351bbc Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 17 Apr 2019 13:41:24 +0200 Subject: [PATCH 116/188] Updated the InitializeEntities implementation and added a unique constraint to RelationshipType table based on types and labels --- .../dspace/app/util/InitializeEntities.java | 49 +++++++------------ .../h2/V7.0_2018.04.16__dspace-entities.sql | 4 +- .../V7.0_2018.04.16__dspace-entities.sql | 4 +- .../V7.0_2018.04.16__dspace-entities.sql | 3 +- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index c8e14b81d2..b3fa73fcde 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -103,31 +103,10 @@ public class InitializeEntities { private void run(String fileLocation) throws SQLException, AuthorizeException { Context context = new Context(); context.turnOffAuthorisationSystem(); - List relationshipTypes = this.parseXMLToRelations(context, fileLocation); - this.saveRelations(context, relationshipTypes); + this.parseXMLToRelations(context, fileLocation); } - private void saveRelations(Context context, List list) throws SQLException, AuthorizeException { - for (RelationshipType relationshipType : list) { - RelationshipType relationshipTypeFromDb = relationshipTypeService.findbyTypesAndLabels(context, - relationshipType.getLeftType(), - relationshipType.getRightType(), - relationshipType.getLeftLabel(), - relationshipType.getRightLabel()); - if (relationshipTypeFromDb == null) { - relationshipTypeService.create(context, relationshipType); - } else { - relationshipTypeFromDb.setLeftMinCardinality(relationshipType.getLeftMinCardinality()); - relationshipTypeFromDb.setLeftMaxCardinality(relationshipType.getLeftMaxCardinality()); - relationshipTypeFromDb.setRightMinCardinality(relationshipType.getRightMinCardinality()); - relationshipTypeFromDb.setRightMaxCardinality(relationshipType.getRightMaxCardinality()); - relationshipTypeService.update(context, relationshipTypeFromDb); - } - } - context.complete(); - } - - private List parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException { + private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException { try { File fXmlFile = new File(fileLocation); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); @@ -174,21 +153,17 @@ public class InitializeEntities { rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max"); } - RelationshipType relationshipType = populateRelationshipType(context,leftType,rightType,leftLabel, - rightLabel,leftCardinalityMin, + populateRelationshipType(context,leftType,rightType,leftLabel, rightLabel,leftCardinalityMin, leftCardinalityMax, rightCardinalityMin, rightCardinalityMax); - relationshipTypes.add(relationshipType); } } - return relationshipTypes; } catch (ParserConfigurationException | SAXException | IOException | SQLException e) { log.error("An error occurred while parsing the XML file to relations", e); } - return null; } private String getString(String leftCardinalityMin,Element node, String minOrMax) { @@ -198,7 +173,7 @@ public class InitializeEntities { return leftCardinalityMin; } - private RelationshipType populateRelationshipType(Context context,String leftType,String rightType,String leftLabel, + private void populateRelationshipType(Context context,String leftType,String rightType,String leftLabel, String rightLabel,String leftCardinalityMin, String leftCardinalityMax,String rightCardinalityMin, String rightCardinalityMax) @@ -236,8 +211,18 @@ public class InitializeEntities { } else { rightCardinalityMaxInteger = null; } - return relationshipTypeService.create(context, leftEntityType, rightEntityType, leftLabel, rightLabel, - leftCardinalityMinInteger, leftCardinalityMaxInteger, - rightCardinalityMinInteger, rightCardinalityMaxInteger); + RelationshipType relationshipType = relationshipTypeService + .findbyTypesAndLabels(context, leftEntityType, rightEntityType, leftLabel, rightLabel); + if (relationshipType == null) { + relationshipTypeService.create(context, leftEntityType, rightEntityType, leftLabel, rightLabel, + leftCardinalityMinInteger, leftCardinalityMaxInteger, + rightCardinalityMinInteger, rightCardinalityMaxInteger); + } else { + relationshipType.setLeftMinCardinality(leftCardinalityMinInteger); + relationshipType.setLeftMaxCardinality(leftCardinalityMaxInteger); + relationshipType.setRightMinCardinality(rightCardinalityMinInteger); + relationshipType.setRightMaxCardinality(rightCardinalityMaxInteger); + relationshipTypeService.update(context, relationshipType); + } } } diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql index 60bc9dc984..1b87eb8ee6 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.0_2018.04.16__dspace-entities.sql @@ -39,7 +39,9 @@ CREATE TABLE relationship_type right_min_cardinality INTEGER, right_max_cardinality INTEGER, FOREIGN KEY (left_type) REFERENCES entity_type(id), - FOREIGN KEY (right_type) REFERENCES entity_type(id) + FOREIGN KEY (right_type) REFERENCES entity_type(id), + CONSTRAINT u_relationship_type_constraint UNIQUE (left_type, right_type, left_label, right_label) + ); CREATE TABLE relationship diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql index c4b84d8623..68855dc2dc 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/V7.0_2018.04.16__dspace-entities.sql @@ -39,7 +39,9 @@ CREATE TABLE relationship_type right_min_cardinality INTEGER, right_max_cardinality INTEGER, FOREIGN KEY (left_type) REFERENCES entity_type(id), - FOREIGN KEY (right_type) REFERENCES entity_type(id) + FOREIGN KEY (right_type) REFERENCES entity_type(id), + CONSTRAINT u_relationship_type_constraint UNIQUE (left_type, right_type, left_label, right_label) + ); CREATE TABLE relationship diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql index c4b84d8623..3a80b7a5fa 100644 --- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.0_2018.04.16__dspace-entities.sql @@ -39,7 +39,8 @@ CREATE TABLE relationship_type right_min_cardinality INTEGER, right_max_cardinality INTEGER, FOREIGN KEY (left_type) REFERENCES entity_type(id), - FOREIGN KEY (right_type) REFERENCES entity_type(id) + FOREIGN KEY (right_type) REFERENCES entity_type(id), + CONSTRAINT u_relationship_type_constraint UNIQUE (left_type, right_type, left_label, right_label) ); CREATE TABLE relationship From 22b297b20776ad1cf713f0d7c15e76c3414e2d87 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 18 Apr 2019 08:47:33 +0200 Subject: [PATCH 117/188] Added IT for the updated InitializeEntities script --- .../entities/relationship-types-update.xml | 127 ++++++++++++++ .../dspace/app/rest/InitializeEntitiesIT.java | 155 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types-update.xml create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java diff --git a/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types-update.xml b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types-update.xml new file mode 100644 index 0000000000..217d898f94 --- /dev/null +++ b/dspace-api/src/test/data/dspaceFolder/config/entities/relationship-types-update.xml @@ -0,0 +1,127 @@ + + + + + + Publication + Person + isAuthorOfPublication + isPublicationOfAuthor + + 10 + + + 0 + + + + Publication + Project + isProjectOfPublication + isPublicationOfProject + + 0 + + + 0 + + + + Publication + OrgUnit + isOrgUnitOfPublication + isPublicationOfOrgUnit + + 0 + + + 0 + + + + Person + Project + isProjectOfPerson + isPersonOfProject + + 0 + + + 0 + + + + Person + OrgUnit + isOrgUnitOfPerson + isPersonOfOrgUnit + + 0 + + + 0 + + + + Project + OrgUnit + isOrgUnitOfProject + isProjectOfOrgUnit + + 0 + + + 0 + + + + Journal + JournalVolume + isVolumeOfJournal + isJournalOfVolume + + 0 + + + 1 + + + + JournalVolume + JournalIssue + isIssueOfJournalVolume + isJournalVolumeOfIssue + + 0 + + + 1 + 1 + + + + Publication + OrgUnit + isAuthorOfPublication + isPublicationOfAuthor + + 0 + + + 0 + + + + JournalIssue + Publication + isPublicationOfJournalIssue + isJournalIssueOfPublication + + 0 + + + 0 + 1 + + + \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java new file mode 100644 index 0000000000..5c6559aef7 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java @@ -0,0 +1,155 @@ +/** + * 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.rest; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.util.Iterator; +import java.util.List; + +import org.dspace.app.rest.matcher.RelationshipTypeMatcher; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.EntityType; +import org.dspace.content.Relationship; +import org.dspace.content.RelationshipType; +import org.dspace.content.service.EntityTypeService; +import org.dspace.content.service.RelationshipService; +import org.dspace.content.service.RelationshipTypeService; +import org.dspace.services.ConfigurationService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { + + @Autowired + private RelationshipTypeService relationshipTypeService; + + @Autowired + private EntityTypeService entityTypeService; + + @Autowired + private RelationshipService relationshipService; + + @Autowired + private ConfigurationService configurationService; + + @Before + public void setup() throws Exception { + + //Set up the database for the next test + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + + } + + @After + public void destroy() throws Exception { + //Clean up the database for the next test + context.turnOffAuthorisationSystem(); + List relationshipTypeList = relationshipTypeService.findAll(context); + List entityTypeList = entityTypeService.findAll(context); + List relationships = relationshipService.findAll(context); + + Iterator relationshipIterator = relationships.iterator(); + while (relationshipIterator.hasNext()) { + Relationship relationship = relationshipIterator.next(); + relationshipIterator.remove(); + relationshipService.delete(context, relationship); + } + + Iterator relationshipTypeIterator = relationshipTypeList.iterator(); + while (relationshipTypeIterator.hasNext()) { + RelationshipType relationshipType = relationshipTypeIterator.next(); + relationshipTypeIterator.remove(); + relationshipTypeService.delete(context, relationshipType); + } + + Iterator entityTypeIterator = entityTypeList.iterator(); + while (entityTypeIterator.hasNext()) { + EntityType entityType = entityTypeIterator.next(); + entityTypeIterator.remove(); + entityTypeService.delete(context, entityType); + } + + super.destroy(); + } + + @Test + public void test() throws Exception { + + + + List relationshipTypes = relationshipTypeService.findAll(context); + + getClient().perform(get("/api/core/relationshiptypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.totalElements", is(10))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) + )); + + getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftMinCardinality", is(0))); + String pathToFile = configurationService.getProperty("dspace.dir") + + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types-update.xml"; + runDSpaceScript("initialize-entities", "-f", pathToFile); + + RelationshipType alteredRelationshipType = relationshipTypes.get(0); + alteredRelationshipType.setLeftMinCardinality(10); + getClient().perform(get("/api/core/relationshiptypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.totalElements", is(10))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(alteredRelationshipType), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) + )); + + getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftMinCardinality", is(10))); + } +} From f8b0eac67ad3f3daaf72a7398a1f0d5c86f57cc2 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Thu, 18 Apr 2019 12:15:17 +0200 Subject: [PATCH 118/188] Fix indentation --- .../org/dspace/app/util/InitializeEntities.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index b3fa73fcde..ff602e8ee9 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -153,10 +153,9 @@ public class InitializeEntities { rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max"); } - populateRelationshipType(context,leftType,rightType,leftLabel, rightLabel,leftCardinalityMin, - leftCardinalityMax, - rightCardinalityMin, - rightCardinalityMax); + populateRelationshipType(context, leftType, rightType, leftLabel, rightLabel, + leftCardinalityMin, leftCardinalityMax, + rightCardinalityMin, rightCardinalityMax); } @@ -173,10 +172,9 @@ public class InitializeEntities { return leftCardinalityMin; } - private void populateRelationshipType(Context context,String leftType,String rightType,String leftLabel, - String rightLabel,String leftCardinalityMin, - String leftCardinalityMax,String rightCardinalityMin, - String rightCardinalityMax) + private void populateRelationshipType(Context context, String leftType, String rightType, String leftLabel, + String rightLabel, String leftCardinalityMin, String leftCardinalityMax, + String rightCardinalityMin, String rightCardinalityMax) throws SQLException, AuthorizeException { EntityType leftEntityType = entityTypeService.findByEntityType(context,leftType); From c83ae49e7f6831a43aef2256697b11dcd90b2731 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Wed, 24 Apr 2019 09:50:11 +0200 Subject: [PATCH 119/188] Feedback on PR-2404 Missing context complete, this was lost in the previous commit from this PR --- .../dspace/app/util/InitializeEntities.java | 1 + .../dspace/app/rest/InitializeEntitiesIT.java | 23 +++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java index ff602e8ee9..52d61ee17a 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java +++ b/dspace-api/src/main/java/org/dspace/app/util/InitializeEntities.java @@ -104,6 +104,7 @@ public class InitializeEntities { Context context = new Context(); context.turnOffAuthorisationSystem(); this.parseXMLToRelations(context, fileLocation); + context.complete(); } private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java index 5c6559aef7..a509aa0516 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java @@ -46,6 +46,9 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { @Autowired private ConfigurationService configurationService; + /** + * Build the relationships using the standard test XML with the initialize-entities script + */ @Before public void setup() throws Exception { @@ -88,22 +91,22 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { super.destroy(); } + /** + * Verify whether the initialize-entities script can update the relationship types correctly + */ @Test public void test() throws Exception { - - - List relationshipTypes = relationshipTypeService.findAll(context); getClient().perform(get("/api/core/relationshiptypes")) //We expect a 200 OK status .andExpect(status().isOk()) - //The type has to be 'discover' + //10 relationship types should be created .andExpect(jsonPath("$.page.totalElements", is(10))) //There needs to be a self link to this endpoint .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) - //We have 4 facets in the default configuration, they need to all be present in the embedded section + //We have 10 relationship types, they need to all be present in the embedded section .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), @@ -117,24 +120,29 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) )); + //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) is 0 getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) .andExpect(status().isOk()) .andExpect(jsonPath("$.leftMinCardinality", is(0))); + + //Update the relationships using a different test XML with the initialize-entities script String pathToFile = configurationService.getProperty("dspace.dir") + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types-update.xml"; runDSpaceScript("initialize-entities", "-f", pathToFile); + //This is a helper object to compare whether the update was successful RelationshipType alteredRelationshipType = relationshipTypes.get(0); alteredRelationshipType.setLeftMinCardinality(10); getClient().perform(get("/api/core/relationshiptypes")) //We expect a 200 OK status .andExpect(status().isOk()) - //The type has to be 'discover' + //10 relationship types should remain present (no duplicates created) .andExpect(jsonPath("$.page.totalElements", is(10))) //There needs to be a self link to this endpoint .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) - //We have 4 facets in the default configuration, they need to all be present in the embedded section + //We have 10 relationship types, they need to all be present in the embedded section + //Verify the left min cardinality of the isAuthorOfPublication has been updated to 10 .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( RelationshipTypeMatcher.matchRelationshipTypeEntry(alteredRelationshipType), RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), @@ -148,6 +156,7 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) )); + //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) has been updated to 10 getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) .andExpect(status().isOk()) .andExpect(jsonPath("$.leftMinCardinality", is(10))); From 0898e33319aa53fec6811d8e5ad0652a95f7bdb1 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 14:36:53 +0200 Subject: [PATCH 120/188] An additional use case in the comments --- .../java/org/dspace/content/RelationshipMetadataValue.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index 51b206c4dc..e419aa3be0 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -30,6 +30,10 @@ public class RelationshipMetadataValue extends MetadataValue { * Relationship for a Publication will have its useForPlace set to true. This means that the place * calculation will take both these RelationshipMetadataValues into account together with the normal * plain text metadatavalues. + * On the other hand, the journal name, volume and issue number which are constructed through a + * Relationship from a Publication to a journal issue will have its useForPlace set to false. + * This would typically be set to false for any singular metadata, and for any relationship where no mixing + * with plain text variables is applicable */ public boolean isUseForPlace() { return useForPlace; From 72afed29b851a31b1b8a9bb4e5522e026e696823 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:01:11 +0200 Subject: [PATCH 121/188] Rename VirtualBean to VirtualMetadataPopularConfiguration --- .../org/dspace/content/ItemServiceImpl.java | 10 ++--- .../org/dspace/content/virtual/Collected.java | 5 ++- .../dspace/content/virtual/Concatenate.java | 5 ++- .../org/dspace/content/virtual/Related.java | 38 +++++++++---------- .../org/dspace/content/virtual/UUIDValue.java | 2 +- ... VirtualMetadataPopularConfiguration.java} | 2 +- .../virtual/VirtualMetadataPopulator.java | 12 +++--- dspace/config/spring/api/virtual-metadata.xml | 26 ++++++------- 8 files changed, 51 insertions(+), 49 deletions(-) rename dspace-api/src/main/java/org/dspace/content/virtual/{VirtualBean.java => VirtualMetadataPopularConfiguration.java} (96%) 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 d3021e95e9..051cfead98 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -44,7 +44,7 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.content.virtual.VirtualBean; +import org.dspace.content.virtual.VirtualMetadataPopularConfiguration; import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -1424,7 +1424,7 @@ prevent the generation of resource policy entry values with null dspace_object a throws SQLException { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); - HashMap hashMaps; + HashMap hashMaps; String relationName = ""; Item otherItem = null; int place = 0; @@ -1460,15 +1460,15 @@ prevent the generation of resource policy entry values with null dspace_object a //hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects //and the keys of the hashmap will be used to construct the RelationshipMetadataValue object. private List handleRelationshipTypeMetadataMapping(Context context, Item item, - HashMap + HashMap hashMaps, Item otherItem, String relationName, Integer relationshipId, int place) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); - for (Map.Entry entry : hashMaps.entrySet()) { + for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); - VirtualBean virtualBean = entry.getValue(); + VirtualMetadataPopularConfiguration virtualBean = entry.getValue(); for (String value : virtualBean.getValues(context, otherItem)) { RelationshipMetadataValue metadataValue = constructMetadataValue(context, key); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java index 16daab017c..61d7a041db 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -18,12 +18,13 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of Virtual + * metadata * The Collected bean will take all the values of each metadata field defined in the list and it'll * create a list of virtual metadata fields defined by the map in which it's defined. * All values from the metadata fields will returned as separate elements */ -public class Collected implements VirtualBean { +public class Collected implements VirtualMetadataPopularConfiguration { @Autowired private ItemService itemService; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index dd12355b75..5284b8b109 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -18,13 +18,14 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata + * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of Virtual + * metadata * The Concatenate bean will take all the values of each metadata field configured in the list * and it will join all of these together with the separator defined in this bean. This means that whichever * entry this bean belongs to, that metadata field will have the value of the related item's metadata values * joined together with this separator. Only one value will be returned */ -public class Concatenate implements VirtualBean { +public class Concatenate implements VirtualMetadataPopularConfiguration { @Autowired private ItemService itemService; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 6285d7d48f..ee7c134cd2 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -25,16 +25,16 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualBean} interface to achieve the generation of Virtual metadata - * by traversing the path of relation specified in the config for this bean + * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of + * Virtual metadata by traversing the path of relation specified in the config for this bean * The Related bean will find the relationshiptype defined in the relationshipTypeString property on - * the current item and it'll use the related item from that relationship to pass it along to the virtualBean - * property which in turn refers to another VirtualBean instance and it continues the chain until it reaches - * either a Concatenate or Collected bean to retrieve the values. It will then return that value through the chain - * again and it'll fill the values into the virtual metadata fields that are defined in the map for the first - * Related bean. + * the current item and it'll use the related item from that relationship to pass it along to the + * virtualMetadataPopularConfiguration property which in turn refers to another VirtualBean instance and it continues + * the chain until it reaches either a Concatenate or Collected bean to retrieve the values. It will then return + * that value through the chain again and it'll fill the values into the virtual metadata fields that are defined + * in the map for the first Related bean. */ -public class Related implements VirtualBean { +public class Related implements VirtualMetadataPopularConfiguration { @Autowired private RelationshipTypeService relationshipTypeService; @@ -59,7 +59,7 @@ public class Related implements VirtualBean { /** * The next bean to call its getValues() method on */ - private VirtualBean virtualBean; + private VirtualMetadataPopularConfiguration virtualMetadataPopularConfiguration; /** * The boolean value indicating whether this field should be used for place or not @@ -99,19 +99,19 @@ public class Related implements VirtualBean { } /** - * Generic getter for the virtualBean property of this class - * @return The virtualBean property + * Generic getter for the virtualMetadataPopularConfiguration property of this class + * @return The virtualMetadataPopularConfiguration property */ - public VirtualBean getVirtualBean() { - return virtualBean; + public VirtualMetadataPopularConfiguration getVirtualMetadataPopularConfiguration() { + return virtualMetadataPopularConfiguration; } /** - * Generic setter for the virtualBean property of this class - * @param virtualBean The VirtualBean to which the virtualBean property will be set to + * Generic setter for the virtualMetadataPopularConfiguration property of this class + * @param virtualMetadataPopularConfiguration The VirtualBean to which the virtualMetadataPopularConfiguration property will be set to */ - public void setVirtualBean(VirtualBean virtualBean) { - this.virtualBean = virtualBean; + public void setVirtualMetadataPopularConfiguration(VirtualMetadataPopularConfiguration virtualMetadataPopularConfiguration) { + this.virtualMetadataPopularConfiguration = virtualMetadataPopularConfiguration; } /** @@ -162,12 +162,12 @@ public class Related implements VirtualBean { if (relationship.getRelationshipType().getLeftType() == entityType) { if (relationship.getLeftPlace() == place) { Item otherItem = relationship.getRightItem(); - return virtualBean.getValues(context, otherItem); + return virtualMetadataPopularConfiguration.getValues(context, otherItem); } } else if (relationship.getRelationshipType().getRightType() == entityType) { if (relationship.getRightPlace() == place) { Item otherItem = relationship.getLeftItem(); - return virtualBean.getValues(context, otherItem); + return virtualMetadataPopularConfiguration.getValues(context, otherItem); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java index 407ef2a459..194c0c663c 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java @@ -18,7 +18,7 @@ import org.dspace.core.Context; * This class is used by the VirtualMetadataPopulator. It will simply take the ID of the item that's passed along * to this and return that as it's value */ -public class UUIDValue implements VirtualBean { +public class UUIDValue implements VirtualMetadataPopularConfiguration { private boolean useForPlace; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java similarity index 96% rename from dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java rename to dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java index 5fe08c43fe..2c8b586a30 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualBean.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java @@ -18,7 +18,7 @@ import org.dspace.core.Context; * The config is located in core-services.xml whilst the actual code implementation is located in * {@link org.dspace.content.ItemServiceImpl} */ -public interface VirtualBean { +public interface VirtualMetadataPopularConfiguration { /** * This method will return a list filled with String values which will be determine by the bean that's responsible diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java index 72bf89c002..7d29edea80 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java @@ -22,13 +22,13 @@ public class VirtualMetadataPopulator { /** * The map that holds this representation */ - private Map> map; + private Map> map; /** * Standard setter for the map * @param map The map to be used in the VirtualMetadataPopulator */ - public void setMap(Map> map) { + public void setMap(Map> map) { this.map = map; } @@ -36,7 +36,7 @@ public class VirtualMetadataPopulator { * Standard getter for the map * @return The map that is used in the VirtualMetadataPopulator */ - public Map> getMap() { + public Map> getMap() { return map; } @@ -48,15 +48,15 @@ public class VirtualMetadataPopulator { * @return A boolean indicating whether the useForPlace is true or not for the given parameters */ public boolean isUseForPlaceTrueForRelationshipType(RelationshipType relationshipType, boolean isLeft) { - HashMap hashMaps; + HashMap hashMaps; if (isLeft) { hashMaps = this.getMap().get(relationshipType.getLeftLabel()); } else { hashMaps = this.getMap().get(relationshipType.getRightLabel()); } if (hashMaps != null) { - for (Map.Entry entry : hashMaps.entrySet()) { - VirtualBean virtualBean = entry.getValue(); + for (Map.Entry entry : hashMaps.entrySet()) { + VirtualMetadataPopularConfiguration virtualBean = entry.getValue(); boolean useForPlace = virtualBean.getUseForPlace(); if (useForPlace) { return true; diff --git a/dspace/config/spring/api/virtual-metadata.xml b/dspace/config/spring/api/virtual-metadata.xml index 676626f3c8..42848cf19c 100644 --- a/dspace/config/spring/api/virtual-metadata.xml +++ b/dspace/config/spring/api/virtual-metadata.xml @@ -37,7 +37,7 @@ + This value-ref should be a bean of type VirtualMetadataPopularConfiguration --> @@ -62,7 +62,7 @@ + This value-ref should be a bean of type VirtualMetadataPopularConfiguration --> @@ -154,18 +154,18 @@ alone, we need to pass this call higher up the chain to the journalvolume's relationships to find the journal. Therefore we've created this Related bean which will look at the journalvolume's relationships with type 'isJournalOfVolume' to find the journal that this journalvolume is related to and it'll then call the next - VirtualBean with that journal to retrieve the value. This will leave the retrieving of the values to the - next bean in the chain --> + VirtualMetadataPopularConfiguration with that journal to retrieve the value. This will leave the retrieving + of the values to the next bean in the chain --> - + - + @@ -224,39 +224,39 @@ alone, we need to pass this call higher up the chain to the journalissue's relationships to find the journal. Therefore we've created this Related bean which will look at the journalissue's relationships with type 'isJournalVolumeOfIssue' to find the journalvolume that this journalissue is related to and it'll then call the next - VirtualBean with that journalvolume to retrieve the value. This will leave the retrieving of the values to the - next bean in the chain. + VirtualMetadataPopularConfiguration with that journalvolume to retrieve the value. This will leave the retrieving + of the values to the next bean in the chain. In this specific case, it'll call another Related bean to retrieve the journal for the journalvolume and it'll then retrieve the volume. This example has 2 Related beans chained to eachother to finally chain to a Collected bean to retrieve the final value --> - + - + - + - + - + From 5a6930121283500b10af1cb5cbd9b34b2a31f316 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:15:39 +0200 Subject: [PATCH 122/188] Rename VirtualBean to VirtualMetadataPopularConfiguration --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 3 +-- .../src/main/java/org/dspace/content/virtual/Related.java | 6 ++++-- 2 files changed, 5 insertions(+), 4 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 051cfead98..44ea75e030 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1460,8 +1460,7 @@ prevent the generation of resource policy entry values with null dspace_object a //hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects //and the keys of the hashmap will be used to construct the RelationshipMetadataValue object. private List handleRelationshipTypeMetadataMapping(Context context, Item item, - HashMap - hashMaps, + HashMap hashMaps, Item otherItem, String relationName, Integer relationshipId, int place) throws SQLException { diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index ee7c134cd2..86ba32a8ce 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -108,9 +108,11 @@ public class Related implements VirtualMetadataPopularConfiguration { /** * Generic setter for the virtualMetadataPopularConfiguration property of this class - * @param virtualMetadataPopularConfiguration The VirtualBean to which the virtualMetadataPopularConfiguration property will be set to + * @param virtualMetadataPopularConfiguration The VirtualBean to which the + * virtualMetadataPopularConfiguration property will be set to */ - public void setVirtualMetadataPopularConfiguration(VirtualMetadataPopularConfiguration virtualMetadataPopularConfiguration) { + public void setVirtualMetadataPopularConfiguration(VirtualMetadataPopularConfiguration + virtualMetadataPopularConfiguration) { this.virtualMetadataPopularConfiguration = virtualMetadataPopularConfiguration; } From ec8109a67e57d296d2c4d51fb33ed558c99e766d Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:34:44 +0200 Subject: [PATCH 123/188] Missing @Override --- .../java/org/dspace/content/EntityTypeServiceImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java index 2eb4ab96ad..e35a8a20e4 100644 --- a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java @@ -27,14 +27,17 @@ public class EntityTypeServiceImpl implements EntityTypeService { @Autowired(required = true) protected AuthorizeService authorizeService; + @Override public EntityType findByEntityType(Context context,String entityType) throws SQLException { return entityTypeDAO.findByEntityType(context, entityType); } + @Override public List findAll(Context context) throws SQLException { return entityTypeDAO.findAll(context, EntityType.class); } + @Override public EntityType create(Context context) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( @@ -43,6 +46,7 @@ public class EntityTypeServiceImpl implements EntityTypeService { return entityTypeDAO.create(context, new EntityType()); } + @Override public EntityType create(Context context, String entityTypeString) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( @@ -53,15 +57,18 @@ public class EntityTypeServiceImpl implements EntityTypeService { return entityTypeDAO.create(context, entityType); } + @Override public EntityType find(Context context,int id) throws SQLException { EntityType entityType = entityTypeDAO.findByID(context, EntityType.class, id); return entityType; } + @Override public void update(Context context,EntityType entityType) throws SQLException, AuthorizeException { update(context,Collections.singletonList(entityType)); } + @Override public void update(Context context,List entityTypes) throws SQLException, AuthorizeException { if (CollectionUtils.isNotEmpty(entityTypes)) { // Check authorisation - only administrators can change formats @@ -76,6 +83,7 @@ public class EntityTypeServiceImpl implements EntityTypeService { } } + @Override public void delete(Context context,EntityType entityType) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( From dcf9240f42bfe2a1a49f3fb31efd363505234541 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:45:24 +0200 Subject: [PATCH 124/188] Refactoring instanceof --- .../main/java/org/dspace/content/RelationshipMetadataValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java index e419aa3be0..88d2e38beb 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataValue.java @@ -48,7 +48,7 @@ public class RelationshipMetadataValue extends MetadataValue { if (obj == null) { return false; } - if (getClass() != RelationshipMetadataValue.class) { + if (! (obj instanceof RelationshipMetadataValue)) { return false; } final RelationshipMetadataValue other = (RelationshipMetadataValue) obj; From 658708832a6e935e65ba7a4ff5d1721bd4790145 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:48:30 +0200 Subject: [PATCH 125/188] Missing @Override --- .../main/java/org/dspace/content/RelationshipServiceImpl.java | 4 ++++ .../java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java | 1 + 2 files changed, 5 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 0239740d09..8c166edc85 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -47,6 +47,7 @@ public class RelationshipServiceImpl implements RelationshipService { @Autowired private VirtualMetadataPopulator virtualMetadataPopulator; + @Override public Relationship create(Context context) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( @@ -284,11 +285,13 @@ public class RelationshipServiceImpl implements RelationshipService { return relationshipDAO.findAll(context, Relationship.class); } + @Override public void update(Context context, Relationship relationship) throws SQLException, AuthorizeException { update(context, Collections.singletonList(relationship)); } + @Override public void update(Context context, List relationships) throws SQLException, AuthorizeException { if (CollectionUtils.isNotEmpty(relationships)) { for (Relationship relationship : relationships) { @@ -304,6 +307,7 @@ public class RelationshipServiceImpl implements RelationshipService { } } + @Override public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException { if (isRelationshipValidToDelete(context, relationship)) { // To delete a relationship, a user must have WRITE permissions on one of the related Items diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java index f2f6364987..b9c48c6711 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/EntityTypeDAOImpl.java @@ -20,6 +20,7 @@ import org.dspace.core.Context; public class EntityTypeDAOImpl extends AbstractHibernateDAO implements EntityTypeDAO { + @Override public EntityType findByEntityType(Context context, String entityType) throws SQLException { CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EntityType.class); From 7b9f08e7adedeee92bb82f185cc0c6ef7a086990 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 15:52:57 +0200 Subject: [PATCH 126/188] JavaDoc --- .../factory/ContentServiceFactory.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java index d6ba49f285..7dee8f607f 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java @@ -84,12 +84,32 @@ public abstract class ContentServiceFactory { public abstract SiteService getSiteService(); + /** + * Return the list of all the available implementations of the RelationshipTypeService interface + * + * @return the list of RelationshipTypeService + */ public abstract RelationshipTypeService getRelationshipTypeService(); + /** + * Return the list of all the available implementations of the RelationshipService interface + * + * @return the list of RelationshipService + */ public abstract RelationshipService getRelationshipService(); + /** + * Return the list of all the available implementations of the EntityTypeService interface + * + * @return the list of EntityTypeService + */ public abstract EntityTypeService getEntityTypeService(); + /** + * Return the list of all the available implementations of the EntityService interface + * + * @return the list of EntityService + */ public abstract EntityService getEntityService(); public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) { From b2d28fcf83f74ad566382792e9a964e50d5d3ccf Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 16:44:16 +0200 Subject: [PATCH 127/188] Avoid creating a new context --- .../app/rest/converter/ItemConverter.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index f4f682daff..9727213553 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -16,6 +16,7 @@ import org.apache.logging.log4j.Logger; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.model.RelationshipRest; +import org.dspace.app.rest.utils.ContextUtil; import org.dspace.content.Bitstream; import org.dspace.content.Bundle; import org.dspace.content.Collection; @@ -26,9 +27,13 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.RelationshipService; import org.dspace.core.Context; import org.dspace.discovery.IndexableObject; +import org.dspace.services.RequestService; +import org.dspace.services.model.Request; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; + /** * This is the converter from/to the Item in the DSpace API data model and the * REST data model @@ -45,6 +50,8 @@ public class ItemConverter @Autowired(required = true) private BitstreamConverter bitstreamConverter; @Autowired + private RequestService requestService; + @Autowired private RelationshipService relationshipService; @Autowired private RelationshipConverter relationshipConverter; @@ -88,7 +95,15 @@ public class ItemConverter item.setBitstreams(bitstreams); List relationships = new LinkedList<>(); try { - relationships = relationshipService.findByItem(new Context(), obj); + Context context; + Request currentRequest = requestService.getCurrentRequest(); + if (currentRequest != null) { + HttpServletRequest request = currentRequest.getHttpServletRequest(); + context = ContextUtil.obtainContext(request); + } else { + context = new Context(); + } + relationships = relationshipService.findByItem(context, obj); } catch (SQLException e) { log.error("Error retrieving relationships for item " + item.getHandle(), e); } From b331b26f8098e78a82beec56acaf95c37030cdd0 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Thu, 25 Apr 2019 17:01:23 +0200 Subject: [PATCH 128/188] Avoid creating a new context --- .../org/dspace/content/ItemServiceImpl.java | 10 +++--- .../org/dspace/content/virtual/Collected.java | 4 +-- .../dspace/content/virtual/Concatenate.java | 4 +-- .../org/dspace/content/virtual/Related.java | 32 +++++++++---------- .../org/dspace/content/virtual/UUIDValue.java | 2 +- ...java => VirtualMetadataConfiguration.java} | 2 +- .../virtual/VirtualMetadataPopulator.java | 12 +++---- dspace/config/spring/api/virtual-metadata.xml | 22 ++++++------- 8 files changed, 44 insertions(+), 44 deletions(-) rename dspace-api/src/main/java/org/dspace/content/virtual/{VirtualMetadataPopularConfiguration.java => VirtualMetadataConfiguration.java} (96%) 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 44ea75e030..be289826d8 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -44,7 +44,7 @@ import org.dspace.content.service.ItemService; import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.RelationshipService; import org.dspace.content.service.WorkspaceItemService; -import org.dspace.content.virtual.VirtualMetadataPopularConfiguration; +import org.dspace.content.virtual.VirtualMetadataConfiguration; import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.core.Constants; import org.dspace.core.Context; @@ -1424,7 +1424,7 @@ prevent the generation of resource policy entry values with null dspace_object a throws SQLException { List resultingMetadataValueList = new LinkedList<>(); RelationshipType relationshipType = relationship.getRelationshipType(); - HashMap hashMaps; + HashMap hashMaps; String relationName = ""; Item otherItem = null; int place = 0; @@ -1460,14 +1460,14 @@ prevent the generation of resource policy entry values with null dspace_object a //hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects //and the keys of the hashmap will be used to construct the RelationshipMetadataValue object. private List handleRelationshipTypeMetadataMapping(Context context, Item item, - HashMap hashMaps, + HashMap hashMaps, Item otherItem, String relationName, Integer relationshipId, int place) throws SQLException { List resultingMetadataValueList = new LinkedList<>(); - for (Map.Entry entry : hashMaps.entrySet()) { + for (Map.Entry entry : hashMaps.entrySet()) { String key = entry.getKey(); - VirtualMetadataPopularConfiguration virtualBean = entry.getValue(); + VirtualMetadataConfiguration virtualBean = entry.getValue(); for (String value : virtualBean.getValues(context, otherItem)) { RelationshipMetadataValue metadataValue = constructMetadataValue(context, key); diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java index 61d7a041db..4820e34e4e 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Collected.java @@ -18,13 +18,13 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of Virtual + * A bean implementing the {@link VirtualMetadataConfiguration} interface to achieve the generation of Virtual * metadata * The Collected bean will take all the values of each metadata field defined in the list and it'll * create a list of virtual metadata fields defined by the map in which it's defined. * All values from the metadata fields will returned as separate elements */ -public class Collected implements VirtualMetadataPopularConfiguration { +public class Collected implements VirtualMetadataConfiguration { @Autowired private ItemService itemService; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java index 5284b8b109..04d3e911ec 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Concatenate.java @@ -18,14 +18,14 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of Virtual + * A bean implementing the {@link VirtualMetadataConfiguration} interface to achieve the generation of Virtual * metadata * The Concatenate bean will take all the values of each metadata field configured in the list * and it will join all of these together with the separator defined in this bean. This means that whichever * entry this bean belongs to, that metadata field will have the value of the related item's metadata values * joined together with this separator. Only one value will be returned */ -public class Concatenate implements VirtualMetadataPopularConfiguration { +public class Concatenate implements VirtualMetadataConfiguration { @Autowired private ItemService itemService; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java index 86ba32a8ce..09eb951f06 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/Related.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/Related.java @@ -25,16 +25,16 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; /** - * A bean implementing the {@link VirtualMetadataPopularConfiguration} interface to achieve the generation of + * A bean implementing the {@link VirtualMetadataConfiguration} interface to achieve the generation of * Virtual metadata by traversing the path of relation specified in the config for this bean * The Related bean will find the relationshiptype defined in the relationshipTypeString property on * the current item and it'll use the related item from that relationship to pass it along to the - * virtualMetadataPopularConfiguration property which in turn refers to another VirtualBean instance and it continues + * virtualMetadataConfiguration property which in turn refers to another VirtualBean instance and it continues * the chain until it reaches either a Concatenate or Collected bean to retrieve the values. It will then return * that value through the chain again and it'll fill the values into the virtual metadata fields that are defined * in the map for the first Related bean. */ -public class Related implements VirtualMetadataPopularConfiguration { +public class Related implements VirtualMetadataConfiguration { @Autowired private RelationshipTypeService relationshipTypeService; @@ -59,7 +59,7 @@ public class Related implements VirtualMetadataPopularConfiguration { /** * The next bean to call its getValues() method on */ - private VirtualMetadataPopularConfiguration virtualMetadataPopularConfiguration; + private VirtualMetadataConfiguration virtualMetadataConfiguration; /** * The boolean value indicating whether this field should be used for place or not @@ -99,21 +99,21 @@ public class Related implements VirtualMetadataPopularConfiguration { } /** - * Generic getter for the virtualMetadataPopularConfiguration property of this class - * @return The virtualMetadataPopularConfiguration property + * Generic getter for the virtualMetadataConfiguration property of this class + * @return The virtualMetadataConfiguration property */ - public VirtualMetadataPopularConfiguration getVirtualMetadataPopularConfiguration() { - return virtualMetadataPopularConfiguration; + public VirtualMetadataConfiguration getVirtualMetadataConfiguration() { + return virtualMetadataConfiguration; } /** - * Generic setter for the virtualMetadataPopularConfiguration property of this class - * @param virtualMetadataPopularConfiguration The VirtualBean to which the - * virtualMetadataPopularConfiguration property will be set to + * Generic setter for the virtualMetadataConfiguration property of this class + * @param virtualMetadataConfiguration The VirtualBean to which the + * virtualMetadataConfiguration property will be set to */ - public void setVirtualMetadataPopularConfiguration(VirtualMetadataPopularConfiguration - virtualMetadataPopularConfiguration) { - this.virtualMetadataPopularConfiguration = virtualMetadataPopularConfiguration; + public void setVirtualMetadataConfiguration(VirtualMetadataConfiguration + virtualMetadataConfiguration) { + this.virtualMetadataConfiguration = virtualMetadataConfiguration; } /** @@ -164,12 +164,12 @@ public class Related implements VirtualMetadataPopularConfiguration { if (relationship.getRelationshipType().getLeftType() == entityType) { if (relationship.getLeftPlace() == place) { Item otherItem = relationship.getRightItem(); - return virtualMetadataPopularConfiguration.getValues(context, otherItem); + return virtualMetadataConfiguration.getValues(context, otherItem); } } else if (relationship.getRelationshipType().getRightType() == entityType) { if (relationship.getRightPlace() == place) { Item otherItem = relationship.getLeftItem(); - return virtualMetadataPopularConfiguration.getValues(context, otherItem); + return virtualMetadataConfiguration.getValues(context, otherItem); } } } diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java index 194c0c663c..c5c45cac8c 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/UUIDValue.java @@ -18,7 +18,7 @@ import org.dspace.core.Context; * This class is used by the VirtualMetadataPopulator. It will simply take the ID of the item that's passed along * to this and return that as it's value */ -public class UUIDValue implements VirtualMetadataPopularConfiguration { +public class UUIDValue implements VirtualMetadataConfiguration { private boolean useForPlace; diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataConfiguration.java similarity index 96% rename from dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java rename to dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataConfiguration.java index 2c8b586a30..0cbb685c96 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopularConfiguration.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataConfiguration.java @@ -18,7 +18,7 @@ import org.dspace.core.Context; * The config is located in core-services.xml whilst the actual code implementation is located in * {@link org.dspace.content.ItemServiceImpl} */ -public interface VirtualMetadataPopularConfiguration { +public interface VirtualMetadataConfiguration { /** * This method will return a list filled with String values which will be determine by the bean that's responsible diff --git a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java index 7d29edea80..94545ab9fe 100644 --- a/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java +++ b/dspace-api/src/main/java/org/dspace/content/virtual/VirtualMetadataPopulator.java @@ -22,13 +22,13 @@ public class VirtualMetadataPopulator { /** * The map that holds this representation */ - private Map> map; + private Map> map; /** * Standard setter for the map * @param map The map to be used in the VirtualMetadataPopulator */ - public void setMap(Map> map) { + public void setMap(Map> map) { this.map = map; } @@ -36,7 +36,7 @@ public class VirtualMetadataPopulator { * Standard getter for the map * @return The map that is used in the VirtualMetadataPopulator */ - public Map> getMap() { + public Map> getMap() { return map; } @@ -48,15 +48,15 @@ public class VirtualMetadataPopulator { * @return A boolean indicating whether the useForPlace is true or not for the given parameters */ public boolean isUseForPlaceTrueForRelationshipType(RelationshipType relationshipType, boolean isLeft) { - HashMap hashMaps; + HashMap hashMaps; if (isLeft) { hashMaps = this.getMap().get(relationshipType.getLeftLabel()); } else { hashMaps = this.getMap().get(relationshipType.getRightLabel()); } if (hashMaps != null) { - for (Map.Entry entry : hashMaps.entrySet()) { - VirtualMetadataPopularConfiguration virtualBean = entry.getValue(); + for (Map.Entry entry : hashMaps.entrySet()) { + VirtualMetadataConfiguration virtualBean = entry.getValue(); boolean useForPlace = virtualBean.getUseForPlace(); if (useForPlace) { return true; diff --git a/dspace/config/spring/api/virtual-metadata.xml b/dspace/config/spring/api/virtual-metadata.xml index 42848cf19c..3172346123 100644 --- a/dspace/config/spring/api/virtual-metadata.xml +++ b/dspace/config/spring/api/virtual-metadata.xml @@ -37,7 +37,7 @@ + This value-ref should be a bean of type VirtualMetadataConfiguration --> @@ -62,7 +62,7 @@ + This value-ref should be a bean of type VirtualMetadataConfiguration --> @@ -154,18 +154,18 @@ alone, we need to pass this call higher up the chain to the journalvolume's relationships to find the journal. Therefore we've created this Related bean which will look at the journalvolume's relationships with type 'isJournalOfVolume' to find the journal that this journalvolume is related to and it'll then call the next - VirtualMetadataPopularConfiguration with that journal to retrieve the value. This will leave the retrieving + VirtualMetadataConfiguration with that journal to retrieve the value. This will leave the retrieving of the values to the next bean in the chain --> - + - + @@ -224,7 +224,7 @@ alone, we need to pass this call higher up the chain to the journalissue's relationships to find the journal. Therefore we've created this Related bean which will look at the journalissue's relationships with type 'isJournalVolumeOfIssue' to find the journalvolume that this journalissue is related to and it'll then call the next - VirtualMetadataPopularConfiguration with that journalvolume to retrieve the value. This will leave the retrieving + VirtualMetadataConfiguration with that journalvolume to retrieve the value. This will leave the retrieving of the values to the next bean in the chain. In this specific case, it'll call another Related bean to retrieve the journal for the journalvolume and it'll then retrieve the volume. This example has 2 Related beans chained to eachother to finally chain to a Collected @@ -232,31 +232,31 @@ - + - + - + - + - + From 09c9d851a569c3d197592c5b42def9de90f2ad21 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Fri, 26 Apr 2019 09:32:29 +0200 Subject: [PATCH 129/188] JavaDoc --- .../content/factory/ContentServiceFactory.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java index 7dee8f607f..ab09eb2347 100644 --- a/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java +++ b/dspace-api/src/main/java/org/dspace/content/factory/ContentServiceFactory.java @@ -85,30 +85,30 @@ public abstract class ContentServiceFactory { public abstract SiteService getSiteService(); /** - * Return the list of all the available implementations of the RelationshipTypeService interface + * Return the implementation of the RelationshipTypeService interface * - * @return the list of RelationshipTypeService + * @return the RelationshipTypeService */ public abstract RelationshipTypeService getRelationshipTypeService(); /** - * Return the list of all the available implementations of the RelationshipService interface + * Return the implementation of the RelationshipService interface * - * @return the list of RelationshipService + * @return the RelationshipService */ public abstract RelationshipService getRelationshipService(); /** - * Return the list of all the available implementations of the EntityTypeService interface + * Return the implementation of the EntityTypeService interface * - * @return the list of EntityTypeService + * @return the EntityTypeService */ public abstract EntityTypeService getEntityTypeService(); /** - * Return the list of all the available implementations of the EntityService interface + * Return the implementation of the EntityService interface * - * @return the list of EntityService + * @return the EntityService */ public abstract EntityService getEntityService(); From 8f56970c33bc01c919fb1d26fed4460a9f06905a Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Fri, 26 Apr 2019 09:34:37 +0200 Subject: [PATCH 130/188] order of imports --- .../main/java/org/dspace/app/rest/converter/ItemConverter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java index 9727213553..cbf4c20479 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/ItemConverter.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import javax.servlet.http.HttpServletRequest; import org.apache.logging.log4j.Logger; import org.dspace.app.rest.model.BitstreamRest; @@ -32,8 +33,6 @@ import org.dspace.services.model.Request; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.servlet.http.HttpServletRequest; - /** * This is the converter from/to the Item in the DSpace API data model and the * REST data model From 70e34edfef4b3274c84adbe06ef3ba00b1bcc443 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 29 Apr 2019 11:13:55 +0200 Subject: [PATCH 131/188] override --- .../org/dspace/content/EntityServiceImpl.java | 17 +++++++++++------ .../org/dspace/content/ItemServiceImpl.java | 1 + .../content/RelationshipTypeServiceImpl.java | 6 +++++- .../dspace/content/service/EntityService.java | 8 -------- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java index 5a00616229..07b2b3062d 100644 --- a/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/EntityServiceImpl.java @@ -35,12 +35,14 @@ public class EntityServiceImpl implements EntityService { @Autowired(required = true) protected ItemService itemService; + @Override public Entity findByItemId(Context context, UUID itemId) throws SQLException { Item item = itemService.find(context, itemId); List relationshipList = relationshipService.findByItem(context, item); return new Entity(item, relationshipList); } + @Override public EntityType getType(Context context, Entity entity) throws SQLException { Item item = entity.getItem(); List list = itemService.getMetadata(item, "relationship", "type", null, Item.ANY); @@ -51,12 +53,9 @@ public class EntityServiceImpl implements EntityService { } } - public List getAllRelations(Context context, Entity entity) { - return entity.getRelationships(); - } - + @Override public List getLeftRelations(Context context, Entity entity) { - List fullList = this.getAllRelations(context, entity); + List fullList = entity.getRelationships(); List listToReturn = new LinkedList<>(); for (Relationship relationship : fullList) { if (relationship.getLeftItem().getID() == entity.getItem().getID()) { @@ -66,8 +65,9 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getRightRelations(Context context, Entity entity) { - List fullList = this.getAllRelations(context, entity); + List fullList = entity.getRelationships(); List listToReturn = new LinkedList<>(); for (Relationship relationship : fullList) { if (relationship.getRightItem().getID() == entity.getItem().getID()) { @@ -77,6 +77,7 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getRelationsByLabel(Context context, String label) throws SQLException { List listToReturn = new LinkedList<>(); List relationshipList = relationshipService.findAll(context); @@ -90,6 +91,7 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getAllRelationshipTypes(Context context, Entity entity) throws SQLException { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); @@ -102,6 +104,7 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getLeftRelationshipTypes(Context context, Entity entity) throws SQLException { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); @@ -113,6 +116,7 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getRightRelationshipTypes(Context context, Entity entity) throws SQLException { EntityType entityType = this.getType(context, entity); List listToReturn = new LinkedList<>(); @@ -124,6 +128,7 @@ public class EntityServiceImpl implements EntityService { return listToReturn; } + @Override public List getRelationshipTypesByLabel(Context context, String label) throws SQLException { List listToReturn = new LinkedList<>(); for (RelationshipType relationshipType : relationshipTypeService.findAll(context)) { 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 be289826d8..ae020c537e 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1355,6 +1355,7 @@ prevent the generation of resource policy entry values with null dspace_object a return fullMetadataValueList; } + @Override public List getMetadata(Item item, String schema, String element, String qualifier, String lang, boolean enableVirtualMetadata) { //Fields of the relation schema are virtual metadata diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java index d505c3df12..1900de8777 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipTypeServiceImpl.java @@ -27,6 +27,7 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { @Autowired(required = true) protected AuthorizeService authorizeService; + @Override public RelationshipType create(Context context) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( @@ -84,15 +85,17 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { return create(context, relationshipType); } - + @Override public RelationshipType find(Context context,int id) throws SQLException { return relationshipTypeDAO.findByID(context, RelationshipType.class, id); } + @Override public void update(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException { update(context,Collections.singletonList(relationshipType)); } + @Override public void update(Context context,List relationshipTypes) throws SQLException, AuthorizeException { if (CollectionUtils.isNotEmpty(relationshipTypes)) { @@ -109,6 +112,7 @@ public class RelationshipTypeServiceImpl implements RelationshipTypeService { } + @Override public void delete(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException { if (!authorizeService.isAdmin(context)) { throw new AuthorizeException( diff --git a/dspace-api/src/main/java/org/dspace/content/service/EntityService.java b/dspace-api/src/main/java/org/dspace/content/service/EntityService.java index b5c42421d0..ec603d7690 100644 --- a/dspace-api/src/main/java/org/dspace/content/service/EntityService.java +++ b/dspace-api/src/main/java/org/dspace/content/service/EntityService.java @@ -47,14 +47,6 @@ public interface EntityService { */ EntityType getType(Context context, Entity entity) throws SQLException; - /** - * Returns the list of relations for the given Entity object - * @param context The relevant DSpace context - * @param entity The Entity object for which the list of relationships will be returned - * @return The list of relationships for the given Entity object - */ - List getAllRelations(Context context, Entity entity); - /** * Retrieves the list of relationships, which are attached to the Entity object that is passed along, where the * left item object of each relationship is equal to the Item object of the Entity object that is passed along From 6707dfb2e6bf5101341c21d36fc3b47266e93d3b Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 29 Apr 2019 11:50:45 +0200 Subject: [PATCH 132/188] feedback on configurable entities --- .../app/rest/model/RelationshipRestWrapper.java | 11 +++++++++-- .../app/rest/repository/DSpaceRestRepository.java | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java index 54cbfd7184..52b87a8fbc 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/RelationshipRestWrapper.java @@ -10,14 +10,18 @@ package org.dspace.app.rest.model; import java.util.List; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import org.dspace.app.rest.RelationshipRestController; /** * This is the RestWrapper object for the RelationshipRestResource class. This will contain all the data that is * used in that resource and more specifically, the label, dsoid and list of RelationshipRest objects * The other methods are generic getters and setters + * This will be updated in https://jira.duraspace.org/browse/DS-4084 */ public class RelationshipRestWrapper implements RestAddressableModel { + public static final String NAME = "relationship"; + public static final String CATEGORY = RestAddressableModel.CORE; @JsonIgnore private List relationshipRestList; @@ -35,16 +39,19 @@ public class RelationshipRestWrapper implements RestAddressableModel { this.relationshipRestList = relationshipRestList; } + @Override public String getCategory() { - return "core"; + return CATEGORY; } public Class getController() { return RelationshipRestController.class; } + @Override + @JsonProperty(access = JsonProperty.Access.READ_ONLY) public String getType() { - return "relationship"; + return NAME; } public String getLabel() { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 93ef0f2c0e..5a72bc2738 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -261,7 +261,7 @@ public abstract class DSpaceRestRepository Date: Mon, 29 Apr 2019 11:54:29 +0200 Subject: [PATCH 133/188] feedback on configurable entities --- .../org/dspace/app/rest/repository/DSpaceRestRepository.java | 1 + 1 file changed, 1 insertion(+) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 5a72bc2738..93f2adbfc6 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -307,6 +307,7 @@ public abstract class DSpaceRestRepository Date: Mon, 29 Apr 2019 15:42:57 +0200 Subject: [PATCH 134/188] feedback on configurable entities --- .../org/dspace/app/rest/model/hateoas/DSpaceResource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java index e1f423ed63..ef06f1360f 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/hateoas/DSpaceResource.java @@ -118,8 +118,8 @@ public abstract class DSpaceResource extends HAL DSpaceRestRepository resourceRepository = utils .getResourceRepository(linkedRMList.get(0).getCategory(), linkedRMList.get(0).getType()); - // TODO should we force pagination also of embedded resource? - // This will force pagination with size 10 for embedded collections as well + // force pagination also of embedded resource + // This will force pagination with size 20 for embedded collections as well int pageSize = 20; PageImpl page = new PageImpl( linkedRMList.subList(0, From 9a40fd817c3d4627803c9d289ebc793fa5dbad0a Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 29 Apr 2019 17:59:38 +0200 Subject: [PATCH 135/188] store place in relation virtual metadata --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 ae020c537e..4b96e29b56 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1450,7 +1450,7 @@ prevent the generation of resource policy entry values with null dspace_object a relationship.getID(), place)); } RelationshipMetadataValue relationMetadataFromOtherItem = - getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID()); + getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID(), place); if (relationMetadataFromOtherItem != null) { resultingMetadataValueList.add(relationMetadataFromOtherItem); } @@ -1487,13 +1487,14 @@ prevent the generation of resource policy entry values with null dspace_object a private RelationshipMetadataValue getRelationMetadataFromOtherItem(Context context, Item otherItem, String relationName, - Integer relationshipId) { + Integer relationshipId, int place) { RelationshipMetadataValue metadataValue = constructMetadataValue(context, MetadataSchemaEnum.RELATION .getName() + "." + relationName); if (metadataValue != null) { metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId); metadataValue.setValue(otherItem.getID().toString()); + metadataValue.setPlace(place); return metadataValue; } return null; From 62ca358f33b67bcda644e33bbfb421aa6cc04041 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Mon, 29 Apr 2019 18:15:14 +0200 Subject: [PATCH 136/188] support for displaying an org unit as author of a publication --- dspace/config/spring/api/virtual-metadata.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dspace/config/spring/api/virtual-metadata.xml b/dspace/config/spring/api/virtual-metadata.xml index 3172346123..9367a26b31 100644 --- a/dspace/config/spring/api/virtual-metadata.xml +++ b/dspace/config/spring/api/virtual-metadata.xml @@ -52,6 +52,7 @@ person.identifier.lastname person.identifier.firstname + orgunit.identifier.name From 7dfd34036cf1b5164f6fd165b3cd8aa8faefa071 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 30 Apr 2019 15:51:28 +0200 Subject: [PATCH 137/188] Implemented feedback --- .../repository/EntityTypeRestRepository.java | 7 +- .../WorkflowItemRestRepository.java | 4 +- .../app/rest/EntityTypeRestRepositoryIT.java | 95 ++++++++----------- .../rest/RelationshipRestRepositoryIT.java | 69 ++++++++------ .../RelationshipTypeRestControllerIT.java | 1 + 5 files changed, 88 insertions(+), 88 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java index 1ab11d0e61..31c4e4392c 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EntityTypeRestRepository.java @@ -20,6 +20,7 @@ import org.dspace.core.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.stereotype.Component; /** @@ -36,7 +37,11 @@ public class EntityTypeRestRepository extends DSpaceRestRepository stringList) { XmlWorkflowItem source; - if (stringList.isEmpty()) { - throw new UnprocessableEntityException("The given URI list could not be parsed and is empty as a result"); + if (stringList == null || stringList.isEmpty() || stringList.size() > 1) { + throw new UnprocessableEntityException("The given URI list could not be properly parsed to one result"); } try { source = submissionService.createWorkflowItem(context, stringList.get(0)); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java index 8b5f19d158..15d1ca589f 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java @@ -10,14 +10,10 @@ package org.dspace.app.rest; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import java.sql.SQLException; - import org.dspace.app.rest.matcher.EntityTypeMatcher; import org.dspace.app.rest.test.AbstractEntityIntegrationTest; import org.dspace.content.EntityType; @@ -31,59 +27,6 @@ public class EntityTypeRestRepositoryIT extends AbstractEntityIntegrationTest { @Autowired private EntityTypeService entityTypeService; - @Test - public void findAllEntityTypesSizeTest() throws SQLException { - assertEquals(7, entityTypeService.findAll(context).size()); - } - - @Test - public void findPublicationEntityTypeTest() throws SQLException { - String type = "Publication"; - checkEntityType(type); - } - - @Test - public void findPersonEntityTypeTest() throws SQLException { - String type = "Person"; - checkEntityType(type); - } - - @Test - public void findProjectEntityTypeTest() throws SQLException { - String type = "Project"; - checkEntityType(type); - } - - @Test - public void findOrgUnitEntityTypeTest() throws SQLException { - String type = "OrgUnit"; - checkEntityType(type); - } - - @Test - public void findJournalEntityTypeTest() throws SQLException { - String type = "Journal"; - checkEntityType(type); - } - - @Test - public void findJournalVolumeEntityTypeTest() throws SQLException { - String type = "JournalVolume"; - checkEntityType(type); - } - - @Test - public void findJournalIssueEntityTypeTest() throws SQLException { - String type = "JournalIssue"; - checkEntityType(type); - } - - private void checkEntityType(String type) throws SQLException { - EntityType entityType = entityTypeService.findByEntityType(context, type); - assertNotNull(entityType); - assertEquals(type, entityType.getLabel()); - } - @Test public void getAllEntityTypeEndpoint() throws Exception { //When we call this facets endpoint @@ -109,4 +52,42 @@ public class EntityTypeRestRepositoryIT extends AbstractEntityIntegrationTest { .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalIssue")) ))); } + + @Test + public void getAllEntityTypeEndpointWithPaging() throws Exception { + //When we call this facets endpoint + getClient().perform(get("/api/core/entitytypes").param("size", "5")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(7))) + .andExpect(jsonPath("$.page.totalPages", is(2))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/entitytypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.entitytypes", containsInAnyOrder( + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Publication")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Person")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Project")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "OrgUnit")), + EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Journal")) + ))); + } + + @Test + public void retrieveOneEntityType() throws Exception { + EntityType entityType = entityTypeService.findByEntityType(context, "Publication"); + getClient().perform(get("/api/core/entitytypes/" + entityType.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", EntityTypeMatcher.matchEntityTypeEntry(entityType))); + } + + @Test + public void retrieveOneEntityTypeThatDoesNotExist() throws Exception { + getClient().perform(get("/api/core/entitytypes/" + 5555)) + .andExpect(status().isNotFound()); + } } \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 0837f4a86c..723f85e086 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; import org.dspace.app.rest.builder.ItemBuilder; import org.dspace.app.rest.builder.RelationshipBuilder; import org.dspace.app.rest.matcher.PageMatcher; @@ -160,6 +161,19 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest RelationshipMatcher.matchRelationship(relationship3) ))) ; + + getClient().perform(get("/api/core/relationships").param("size", "2")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntryWithTotalPagesAndElements(0, 2, 2, 3)))) + .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( + RelationshipMatcher.matchRelationship(relationship1), + RelationshipMatcher.matchRelationship(relationship2) + ))) + ; + + } @Test @@ -197,16 +211,8 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest "isAuthorOfPublication", "isPublicationOfAuthor"); - - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testaze@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context).withEmail("testaze@email.com") + .withNameInMetadata("first", "last").withPassword(password).build(); context.setCurrentUser(user); authorizeService.addPolicy(context, publication, Constants.WRITE, user); @@ -228,6 +234,17 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest .andExpect(status().isCreated()) .andReturn(); + ObjectMapper mapper = new ObjectMapper(); + + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String firstRelationshipIdString = String.valueOf(map.get("id")); + + getClient().perform(get("/api/core/relationships/" + firstRelationshipIdString)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftId", is(publication.getID().toString()))) + .andExpect(jsonPath("$.rightId", is(author1.getID().toString()))); + } @Test @@ -266,15 +283,8 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testazhfhdfhe@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context).withEmail("testaze@email.com") + .withNameInMetadata("first", "last").withPassword(password).build(); context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); @@ -295,6 +305,16 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest .andExpect(status().isCreated()) .andReturn(); + ObjectMapper mapper = new ObjectMapper(); + + String content = mvcResult.getResponse().getContentAsString(); + Map map = mapper.readValue(content, Map.class); + String firstRelationshipIdString = String.valueOf(map.get("id")); + + getClient().perform(get("/api/core/relationships/" + firstRelationshipIdString)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftId", is(publication.getID().toString()))) + .andExpect(jsonPath("$.rightId", is(author1.getID().toString()))); } @@ -334,15 +354,8 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testazeazeazezae@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context).withEmail("testaze@email.com") + .withNameInMetadata("first", "last").withPassword(password).build(); context.setCurrentUser(user); context.restoreAuthSystemState(); diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java index c8d2322d29..22caaf77ff 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java @@ -186,6 +186,7 @@ public class RelationshipTypeRestControllerIT extends AbstractEntityIntegrationT Relationship relationship4 = RelationshipBuilder .createRelationshipBuilder(context, publication2, author3, isAuthorOfPublicationRelationshipType).build(); + context.restoreAuthSystemState(); getClient().perform(get("/api/core/relationships/isAuthorOfPublication")) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( From 4c6e939e57352acc854053302df37f78c995571a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 2 May 2019 13:26:30 +0200 Subject: [PATCH 138/188] Implemented feedback --- .../app/rest/DiscoveryRestControllerIT.java | 3319 ++++++++--------- .../RelationshipTypeRestControllerIT.java | 4 +- 2 files changed, 1658 insertions(+), 1665 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java index e911e86f3c..cdee407282 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/DiscoveryRestControllerIT.java @@ -66,16 +66,16 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //When we call this endpoint getClient().perform(get("/api/discover")) - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a link to the facets endpoint - .andExpect(jsonPath("$._links.facets.href", containsString("api/discover/facets"))) - //There needs to be a link to the search endpoint - .andExpect(jsonPath("$._links.search.href", containsString("api/discover/search"))) - //There needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover"))); + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a link to the facets endpoint + .andExpect(jsonPath("$._links.facets.href", containsString("api/discover/facets"))) + //There needs to be a link to the search endpoint + .andExpect(jsonPath("$._links.search.href", containsString("api/discover/search"))) + //There needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover"))); } @Test @@ -84,20 +84,20 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //When we call this facets endpoint getClient().perform(get("/api/discover/facets")) - //We expect a 200 OK status - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a self link to this endpoint - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets"))) - //We have 4 facets in the default configuration, they need to all be present in the embedded section - .andExpect(jsonPath("$._embedded.facets", containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.facets", containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false))) - ); + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false))) + ); } @Test @@ -108,69 +108,69 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects and authors Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 getClient().perform(get("/api/discover/facets/author") - .param("size", "2")) + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type needs to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet needs to be author, because that's what we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's how the author facet is configured by default - .andExpect(jsonPath("$.facetType", is("text"))) - //Because we've constructed such a structure so that we have more than 2 (size) authors, there - // needs to be a next link - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //Because there are more authors than is represented (because of the size param), hasMore has to - // be true - //The page object needs to be present and just like specified in the matcher - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //These authors need to be in the response because it's sorted on how many times the author comes - // up in different items - //These authors are the most used ones. Only two show up because of the size. - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //Because we've constructed such a structure so that we have more than 2 (size) authors, there + // needs to be a next link + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are the most used ones. Only two show up because of the size. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) ; } @@ -182,64 +182,64 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects and authors Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system and enters a size of 2 getClient().perform(get("/api/discover/facets/author?prefix=smith") - .param("size", "10")) + .param("size", "10")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type needs to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet needs to be author, because that's what we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's how the author facet is configured by default - .andExpect(jsonPath("$.facetType", is("text"))) - //We only request value starting with "smith", so we expect to only receive one page - .andExpect(jsonPath("$._links.next").doesNotExist()) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author?prefix=smith"))) - //Because there are more authors than is represented (because of the size param), hasMore has to - // be true - //The page object needs to be present and just like specified in the matcher - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 10)))) - //These authors need to be in the response because it's sorted on how many times the author comes - // up in different items - //These authors are order according to count. Only two show up because of the prefix. - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type needs to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet needs to be author, because that's what we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's how the author facet is configured by default + .andExpect(jsonPath("$.facetType", is("text"))) + //We only request value starting with "smith", so we expect to only receive one page + .andExpect(jsonPath("$._links.next").doesNotExist()) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author?prefix=smith"))) + //Because there are more authors than is represented (because of the size param), hasMore has to + // be true + //The page object needs to be present and just like specified in the matcher + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 10)))) + //These authors need to be in the response because it's sorted on how many times the author comes + // up in different items + //These authors are order according to count. Only two show up because of the prefix. + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -251,64 +251,64 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facets and doesn't enter a size getClient().perform(get("/api/discover/facets/author")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author, because that's the facet that we called upon - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' because that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //There always needs to be a self link present - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The page object needs to present and exactly like how it is specified here. 20 is entered as the - // size because that's the default in the configuration if no size parameter has been given - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //The authors need to be embedded in the values, all 4 of them have to be present as the size - // allows it - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author, because that's the facet that we called upon + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link present + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object needs to present and exactly like how it is specified here. 20 is entered as the + // size because that's the default in the configuration if no size parameter has been given + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The authors need to be embedded in the values, all 4 of them have to be present as the size + // allows it + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -321,69 +321,69 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John").withAuthor("Smith, Maria") - .withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John").withAuthor("Smith, Maria") + .withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Doe, John") - .withAuthor("Smith, Donald") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Doe, John") + .withAuthor("Smith, Donald") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facet //The user enters a size of two and wants to see page 1, this is the second page. getClient().perform(get("/api/discover/facets/author") - .param("size", "2") - .param("page", "1")) + .param("size", "2") + .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name of the facet has to be author as that's the one we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as this is the default configuration - .andExpect(jsonPath("$.facetType", is("text"))) - //There needs to be a next link because there are more authors than the current size is allowed to - // show. There are more pages after this one - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The page object has to be like this because that's what we've asked in the parameters - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(1, 2)))) - //These authors have to be present because of the current configuration - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name of the facet has to be author as that's the one we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as this is the default configuration + .andExpect(jsonPath("$.facetType", is("text"))) + //There needs to be a next link because there are more authors than the current size is allowed to + // show. There are more pages after this one + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/author?page"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The page object has to be like this because that's what we've asked in the parameters + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(1, 2)))) + //These authors have to be present because of the current configuration + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))) ; } @@ -396,76 +396,76 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the authors by the facet //The user enters a small query, namely the title has to contain 'test' getClient().perform(get("/api/discover/facets/author") - .param("f.title", "test,contains")) + .param("f.title", "test,contains")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author as that's the facet that we've asked - .andExpect(jsonPath("$.name", is("author"))) - //The facetType needs to be 'text' as that's the default configuration for the given facet - .andExpect(jsonPath("$.facetType", is("text"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //The self link needs to contain the query that was specified in the parameters, this is how it - // looks like - .andExpect(jsonPath("$._links.self.href", containsString("f.title=test,contains"))) - //The applied filters have to be specified like this, applied filters are the parameters given - // below starting with f. - .andExpect(jsonPath("$.appliedFilters", contains( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //This is how the page object must look like because it's the default - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //These authors need to be present in the result because these have made items that contain 'test' - // in the title - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Donald"), - FacetValueMatcher.entryAuthor("Testing, Works") - ))) - //These authors cannot be present because they've not produced an item with 'test' in the title - .andExpect(jsonPath("$._embedded.values", not(containsInAnyOrder( - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, Jane") - )))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've asked + .andExpect(jsonPath("$.name", is("author"))) + //The facetType needs to be 'text' as that's the default configuration for the given facet + .andExpect(jsonPath("$.facetType", is("text"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //The self link needs to contain the query that was specified in the parameters, this is how it + // looks like + .andExpect(jsonPath("$._links.self.href", containsString("f.title=test,contains"))) + //The applied filters have to be specified like this, applied filters are the parameters given + // below starting with f. + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //This is how the page object must look like because it's the default + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //These authors need to be present in the result because these have made items that contain 'test' + // in the title + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Donald"), + FacetValueMatcher.entryAuthor("Testing, Works") + ))) + //These authors cannot be present because they've not produced an item with 'test' in the title + .andExpect(jsonPath("$._embedded.values", not(containsInAnyOrder( + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, Jane") + )))) ; } @@ -477,62 +477,62 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2000-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2000-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet getClient().perform(get("/api/discover/facets/dateIssued")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be 'dateIssued' as that's the facet that we've called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //The facetType has to be 'date' because that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //This is how the page object must look like because it's the default with size 20 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 20)))) - //The date values need to be as specified below - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - //We'll always get atleast two intervals with the items specified above, so we ask to match - // twice atleast - FacetValueMatcher.entryDateIssued(), - FacetValueMatcher.entryDateIssued() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'dateIssued' as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType has to be 'date' because that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //This is how the page object must look like because it's the default with size 20 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 20)))) + //The date values need to be as specified below + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + //We'll always get atleast two intervals with the items specified above, so we ask to match + // twice atleast + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) ; } @@ -545,90 +545,90 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Public item 1") - .withIssueDate("2017-10-17") - .withAuthor("Smith, Donald").withAuthor("Doe, John") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2016-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2016-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the author results by the facet //With a certain scope getClient().perform(get("/api/discover/facets/author") - .param("scope", "testScope")) + .param("scope", "testScope")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be author as that's the facet that we've called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //The scope has to be the same as the one that we've given in the parameters - .andExpect(jsonPath("$.scope", is("testScope"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //These are all the authors for the items that were created and thus they have to be present in - // the embedded values section - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria"), - FacetValueMatcher.entryAuthor("Doe, John"), - FacetValueMatcher.entryAuthor("Smith, Donald") - ))); + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be author as that's the facet that we've called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be the same as the one that we've given in the parameters + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are all the authors for the items that were created and thus they have to be present in + // the embedded values section + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria"), + FacetValueMatcher.entryAuthor("Doe, John"), + FacetValueMatcher.entryAuthor("Smith, Donald") + ))); //** WHEN ** //An anonymous user browses this endpoint to find the author results by the facet //With a certain scope //And a size of 2 getClient().perform(get("/api/discover/facets/author") - .param("scope", "testScope") - .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be 'author' as that's the facet that we called - .andExpect(jsonPath("$.name", is("author"))) - //The facetType has to be 'text' as that's the default configuration for this facet - .andExpect(jsonPath("$.facetType", is("text"))) - //The scope has to be same as the param that we've entered - .andExpect(jsonPath("$.scope", is("testScope"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) - //These are the values that need to be present as it's ordered by count and these authors are the - // most common ones in the items that we've created - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryAuthor("Doe, Jane"), - FacetValueMatcher.entryAuthor("Smith, Maria") - ))) + .param("scope", "testScope") + .param("size", "2")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be 'author' as that's the facet that we called + .andExpect(jsonPath("$.name", is("author"))) + //The facetType has to be 'text' as that's the default configuration for this facet + .andExpect(jsonPath("$.facetType", is("text"))) + //The scope has to be same as the param that we've entered + .andExpect(jsonPath("$.scope", is("testScope"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/author"))) + //These are the values that need to be present as it's ordered by count and these authors are the + // most common ones in the items that we've created + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryAuthor("Doe, Jane"), + FacetValueMatcher.entryAuthor("Smith, Maria") + ))) ; } @@ -640,105 +640,105 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. 7 public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1940-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1940-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem4 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1950-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem5 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1960-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1960-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem6 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1970-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem7 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("1980-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("1980-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet //And a size of 2 getClient().perform(get("/api/discover/facets/dateIssued") - .param("size", "2")) + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name needs to be dateIssued as that's the facet that we've called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //the facetType needs to be 'date' as that's the default facetType for this facet in the - // configuration - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //Seeing as we've entered a size of two and there are more dates than just two, we'll need a next - // link to go to the next page to see the rest of the dates - .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/dateIssued?page"))) - //The page object needs to look like this because we've entered a size of 2 and we didn't specify - // a starting page so it defaults to 0 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //There needs to be two date results in the embedded values section because that's what we've - // specified - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryDateIssued(), - FacetValueMatcher.entryDateIssued() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name needs to be dateIssued as that's the facet that we've called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //the facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //Seeing as we've entered a size of two and there are more dates than just two, we'll need a next + // link to go to the next page to see the rest of the dates + .andExpect(jsonPath("$._links.next.href", containsString("api/discover/facets/dateIssued?page"))) + //The page object needs to look like this because we've entered a size of 2 and we didn't specify + // a starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be two date results in the embedded values section because that's what we've + // specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssued(), + FacetValueMatcher.entryDateIssued() + ))) ; } @@ -752,71 +752,71 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the dateIssued results by the facet //With a query stating that the title needs to contain 'test' //And a size of 2 getClient().perform(get("/api/discover/facets/dateIssued") - .param("f.title", "test,contains") - .param("size", "2")) + .param("f.title", "test,contains") + .param("size", "2")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The name has to be dateIssued because that's the facet that we called - .andExpect(jsonPath("$.name", is("dateIssued"))) - //The facetType needs to be 'date' as that's the default facetType for this facet in the - // configuration - .andExpect(jsonPath("$.facetType", is("date"))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) - //There needs to be an appliedFilters section that looks like this because we've specified a query - // in the parameters - .andExpect(jsonPath("$.appliedFilters", containsInAnyOrder( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //The page object needs to look like this because we entered a size of 2 and we didn't specify a - // starting page so it defaults to 0 - .andExpect(jsonPath("$.page", - is(PageMatcher.pageEntry(0, 2)))) - //There needs to be only two date intervals with a count of 1 because of the query we specified - .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( - FacetValueMatcher.entryDateIssuedWithCountOne(), - FacetValueMatcher.entryDateIssuedWithCountOne() - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The name has to be dateIssued because that's the facet that we called + .andExpect(jsonPath("$.name", is("dateIssued"))) + //The facetType needs to be 'date' as that's the default facetType for this facet in the + // configuration + .andExpect(jsonPath("$.facetType", is("date"))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("api/discover/facets/dateIssued"))) + //There needs to be an appliedFilters section that looks like this because we've specified a query + // in the parameters + .andExpect(jsonPath("$.appliedFilters", containsInAnyOrder( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //The page object needs to look like this because we entered a size of 2 and we didn't specify a + // starting page so it defaults to 0 + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntry(0, 2)))) + //There needs to be only two date intervals with a count of 1 because of the query we specified + .andExpect(jsonPath("$._embedded.values", containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithCountOne(), + FacetValueMatcher.entryDateIssuedWithCountOne() + ))) ; } @@ -870,75 +870,75 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //There needs to be a page object that shows the total pages and total elements as well as the - // size and the current page (number) - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //These search results have to be shown in the embedded.objects section as these are the items - // given in the structure defined above. - //Seeing as everything fits onto one page, they have to all be present - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //There needs to be a page object that shows the total pages and total elements as well as the + // size and the current page (number) + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //These search results have to be shown in the embedded.objects section as these are the items + // given in the structure defined above. + //Seeing as everything fits onto one page, they have to all be present + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "community", "communities"), SearchResultMatcher.match("core", "community", "communities"), - //This has to be like this because collections don't have anything else - SearchResultMatcher.match(), - SearchResultMatcher.match(), + //This has to be like this because collections don't have anything else + SearchResultMatcher.match(), + SearchResultMatcher.match(), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -950,80 +950,80 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works").withAuthor("a1, a1") - .withAuthor("b, b").withAuthor("c, c").withAuthor("d, d").withAuthor("e, e") - .withAuthor("f, f").withAuthor("g, g") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works").withAuthor("a1, a1") + .withAuthor("b, b").withAuthor("c, c").withAuthor("d, d").withAuthor("e, e") + .withAuthor("f, f").withAuthor("g, g") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because we've only made 7 elements, the default size is 20 - // and they all fit onto one page (20 > 7) so totalPages has to be 1. Number is 0 because - //page 0 is the default page we view if not specified otherwise - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //All elements have to be present in the embedded.objects section, these are the ones we made in - // the structure defined above - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 elements, the default size is 20 + // and they all fit onto one page (20 > 7) so totalPages has to be 1. Number is 0 because + //page 0 is the default page we view if not specified otherwise + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All elements have to be present in the embedded.objects section, these are the ones we made in + // the structure defined above + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "community", "communities"), SearchResultMatcher.match("core", "community", "communities"), - //Match without any parameters because collections don't have anything special to check in the - // json - SearchResultMatcher.match(), - SearchResultMatcher.match(), + //Match without any parameters because collections don't have anything special to check in the + // json + SearchResultMatcher.match(), + SearchResultMatcher.match(), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - //We do however exceed the limit for the authors, so this property has to be true for the author - // facet - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(true), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the authors, so this property has to be true for the author + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1037,81 +1037,81 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry").withSubject("a") - .withSubject("b").withSubject("c") - .withSubject("d").withSubject("e") - .withSubject("f").withSubject("g") - .withSubject("h").withSubject("i") - .withSubject("j").withSubject("k") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry").withSubject("a") + .withSubject("b").withSubject("c") + .withSubject("d").withSubject("e") + .withSubject("f").withSubject("g") + .withSubject("h").withSubject("i") + .withSubject("j").withSubject("k") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because we've only made 7 items, they all fit onto 1 page - // because the default size is 20 and the default starting page is 0. - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //All the elements created in the structure above have to be present in the embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because we've only made 7 items, they all fit onto 1 page + // because the default size is 20 and the default starting page is 0. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "community", "communities"), SearchResultMatcher.match("core", "community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - //We do however exceed the limit for the subject, so this property has to be true for the subject - // facet - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + //We do however exceed the limit for the subject, so this property has to be true for the subject + // facet + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1123,73 +1123,73 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a query that says that the title has to contain 'test' getClient().perform(get("/api/discover/search/objects") - .param("f.title", "test,contains")) + .param("f.title", "test,contains")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because of the query we specified, only two elements match - // the query. - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) - ))) - //Only the two item elements match the query, therefore those are the only ones that can be in the - // embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because of the query we specified, only two elements match + // the query. + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2) + ))) + //Only the two item elements match the query, therefore those are the only ones that can be in the + // embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //We need to display the appliedFilters object that contains the query that we've ran - .andExpect(jsonPath("$.appliedFilters", contains( - AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //We need to display the appliedFilters object that contains the query that we've ran + .andExpect(jsonPath("$.appliedFilters", contains( + AppliedFilterMatcher.appliedFilterEntry("title", "contains", "test", "test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1202,76 +1202,76 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a scope 'test' getClient().perform(get("/api/discover/search/objects") - .param("scope", "test")) + .param("scope", "test")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page element has to look like this because it contains all the elements we've just created - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) - ))) - //The scope property has to be set to the value we entered in the parameters - .andExpect(jsonPath("$.scope", is("test"))) - //All the elements created in the structure above have to be present in the embedded.objects section - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element has to look like this because it contains all the elements we've just created + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7) + ))) + //The scope property has to be set to the value we entered in the parameters + .andExpect(jsonPath("$.scope", is("test"))) + //All the elements created in the structure above have to be present in the embedded.objects section + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "community", "communities"), SearchResultMatcher.match("core", "community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1283,72 +1283,72 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a dsoType 'item' getClient().perform(get("/api/discover/search/objects") - .param("dsoType", "item")) + .param("dsoType", "item")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page element needs to look like this and only have three totalElements because we only want - // the items (dsoType) and we only created three items - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) - ))) - //Only the three items can be present in the embedded.objects section as that's what we specified - // in the dsoType parameter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page element needs to look like this and only have three totalElements because we only want + // the items (dsoType) and we only created three items + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1359,86 +1359,86 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("Testing, Works") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("Testing, Works") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Testing") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Testing") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a dsoType 'item' //And a sort on the dc.title ascending getClient().perform(get("/api/discover/search/objects") - .param("dsoType", "item") - .param("sort", "dc.title,ASC")) + .param("dsoType", "item") + .param("sort", "dc.title,ASC")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this and only contain three total elements because we only want - // to get the items back - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) - ))) - //Only the three items can be present in the embedded.objects section as that's what we specified - // in the dsoType parameter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this and only contain three total elements because we only want + // to get the items back + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3) + ))) + //Only the three items can be present in the embedded.objects section as that's what we specified + // in the dsoType parameter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items"), SearchResultMatcher.match("core", "item", "items") - ))) - //Here we want to match on the item name in a certain specified order because we want to check the - // sort properly - //We check whether the items are sorted properly as we expected - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Public"), - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Testing") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //We want to get the sort that's been used as well in the response - .andExpect(jsonPath("$.sort", is( - SortOptionMatcher.sortByAndOrder("dc.title", "ASC") - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //Here we want to match on the item name in a certain specified order because we want to check the + // sort properly + //We check whether the items are sorted properly as we expected + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public"), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Testing") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //We want to get the sort that's been used as well in the response + .andExpect(jsonPath("$.sort", is( + SortOptionMatcher.sortByAndOrder("dc.title", "ASC") + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1453,114 +1453,114 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. 9 public items that are readable by Anonymous with different subjects Item publicItem6 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2017-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2017-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem7 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem8 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem9 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1970-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1970-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem10 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1950-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1950-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem11 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1930-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1930-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem12 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1910-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1910-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem13 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1890-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1890-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); Item publicItem14 = ItemBuilder.createItem(context, col2) - .withTitle("Public") - .withIssueDate("1866-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public") + .withIssueDate("1866-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find dateIssued facet values getClient().perform(get("/api/discover/facets/dateIssued")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object has to look like this because the default size is 20 and the default starting - // page is 0 - .andExpect(jsonPath("$.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Then we expect these dateIssued values to be present with the labels as specified - .andExpect(jsonPath("$._embedded.values", Matchers.containsInAnyOrder( - FacetValueMatcher.entryDateIssuedWithLabel("2000 - 2017"), - FacetValueMatcher.entryDateIssuedWithLabel("1980 - 1999"), - FacetValueMatcher.entryDateIssuedWithLabel("1960 - 1979"), - FacetValueMatcher.entryDateIssuedWithLabel("1940 - 1959"), - FacetValueMatcher.entryDateIssuedWithLabel("1920 - 1939"), - FacetValueMatcher.entryDateIssuedWithLabel("1880 - 1899"), - FacetValueMatcher.entryDateIssuedWithLabel("1866 - 1879"), - FacetValueMatcher.entryDateIssuedWithLabel("1900 - 1919") + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object has to look like this because the default size is 20 and the default starting + // page is 0 + .andExpect(jsonPath("$.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Then we expect these dateIssued values to be present with the labels as specified + .andExpect(jsonPath("$._embedded.values", Matchers.containsInAnyOrder( + FacetValueMatcher.entryDateIssuedWithLabel("2000 - 2017"), + FacetValueMatcher.entryDateIssuedWithLabel("1980 - 1999"), + FacetValueMatcher.entryDateIssuedWithLabel("1960 - 1979"), + FacetValueMatcher.entryDateIssuedWithLabel("1940 - 1959"), + FacetValueMatcher.entryDateIssuedWithLabel("1920 - 1939"), + FacetValueMatcher.entryDateIssuedWithLabel("1880 - 1899"), + FacetValueMatcher.entryDateIssuedWithLabel("1866 - 1879"), + FacetValueMatcher.entryDateIssuedWithLabel("1900 - 1919") - ))) + ))) ; } @@ -1572,77 +1572,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("size", "2") - .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - //Size of 2 because that's what we entered - //Page number 1 because that's the param we entered - //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages - //We made 7 elements -> 7 total elements - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) - ))) - //These are the two elements that'll be shown (because page = 1, so the third and fourth element - // in the list) and they'll be the only ones because the size is 2 - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match(), - SearchResultMatcher.match() - ))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(true), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false), - FacetEntryMatcher.entityTypeFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(true), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false), + FacetEntryMatcher.entityTypeFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1656,45 +1656,45 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); String bitstreamContent = "ThisIsSomeDummyText"; //Add a bitstream to an item try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { Bitstream bitstream = BitstreamBuilder. - createBitstream(context, publicItem1, is) - .withName("Bitstream") - .withMimeType("text/plain") - .build(); + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withMimeType("text/plain") + .build(); } //Run the filter media to make the text in the bitstream searchable through the query @@ -1704,33 +1704,33 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'ThisIsSomeDummyText' getClient().perform(get("/api/discover/search/objects") - .param("query", "ThisIsSomeDummyText")) + .param("query", "ThisIsSomeDummyText")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //This is the only item that should be returned with the query given - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - ))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //This is the only item that should be returned with the query given + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1743,40 +1743,40 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); //Make this one public to make sure that it doesn't show up in the search Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .withEmbargoPeriod("12 months") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .withEmbargoPeriod("12 months") + .build(); //Turn on the authorization again context.restoreAuthSystemState(); @@ -1784,39 +1784,39 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system // getClient().perform(get("/api/discover/search/objects")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //These are the items that aren't set to private - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //These are the items that aren't set to private + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( SearchResultMatcher.match("core", "community", "communities"), SearchResultMatcher.match("core", "community", "communities"), - //Collections are specified like this because they don't have any special properties - SearchResultMatcher.match(), - SearchResultMatcher.match(), - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //This is a private item, this shouldn't show up in the result - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", - Matchers.not(SearchResultMatcher.matchOnItemName("item", "items", "Test 2")))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //Collections are specified like this because they don't have any special properties + SearchResultMatcher.match(), + SearchResultMatcher.match(), + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //This is a private item, this shouldn't show up in the result + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", + Matchers.not(SearchResultMatcher.matchOnItemName("item", "items", "Test 2")))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1831,37 +1831,37 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); //2. one public item that is readable by Anonymous Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); String bitstreamContent = "ThisIsSomeDummyText"; //Make the group that anon doesn't have access to Group internalGroup = GroupBuilder.createGroup(context) - .withName("Internal Group") - .build(); + .withName("Internal Group") + .build(); //Add this bitstream with the internal group as the reader group try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { Bitstream bitstream = BitstreamBuilder. - createBitstream(context, publicItem1, is) - .withName("Bitstream") - .withDescription("Test Private Bitstream") - .withMimeType("text/plain") - .withReaderGroup(internalGroup) - .build(); + createBitstream(context, publicItem1, is) + .withName("Bitstream") + .withDescription("Test Private Bitstream") + .withMimeType("text/plain") + .withReaderGroup(internalGroup) + .build(); } @@ -1875,32 +1875,32 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("query", "ThisIsSomeDummyText")) + .param("query", "ThisIsSomeDummyText")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Make sure that the item with the private bitstream doesn't show up - .andExpect(jsonPath("$._embedded.object", Matchers.not(Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - )))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the item with the private bitstream doesn't show up + .andExpect(jsonPath("$._embedded.object", Matchers.not(Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + )))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1914,70 +1914,70 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the scope given getClient().perform(get("/api/discover/search/objects") - .param("scope", String.valueOf(scope))) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The scope has to be equal to the one given in the parameters - .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items belonging to the scope specified - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The scope has to be equal to the one given in the parameters + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items belonging to the scope specified + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -1990,77 +1990,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Two items that are readable by Anonymous with different subjects and one private item Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("scope", String.valueOf(scope))) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //Make sure that the scope is set to the scope given in the param - .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //Make sure that the search results contains the item with the correct scope - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2") + .param("scope", String.valueOf(scope))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //Make sure that the scope is set to the scope given in the param + .andExpect(jsonPath("$.scope", is(String.valueOf(scope)))) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //Make sure that the search results contains the item with the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") // SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //Make sure that the search result doesn't contain the item that's set to private but does have - // the correct scope - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( - Matchers.contains( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - )))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + ))) + //Make sure that the search result doesn't contain the item that's set to private but does have + // the correct scope + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + )))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2073,34 +2073,34 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .build(); String query = "Public"; @@ -2108,34 +2108,34 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'public' getClient().perform(get("/api/discover/search/objects") - .param("query", query)) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results has to contain the item with the query in the title and the hithighlight has - // to be filled in with a string containing the query - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( - SearchResultMatcher - .matchOnItemNameAndHitHighlight("item", "items", - "Public item 2", query, "dc.title") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore - // property because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results has to contain the item with the query in the title and the hithighlight has + // to be filled in with a string containing the query + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore + // property because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2149,35 +2149,35 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Two public items that are readable by Anonymous with different subjects and one private item Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane") - .withSubject("AnotherTest").withSubject("ExtraEntry") - .makeUnDiscoverable() - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane") + .withSubject("AnotherTest").withSubject("ExtraEntry") + .makeUnDiscoverable() + .build(); String query = "Public"; @@ -2185,25 +2185,25 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //An anonymous user browses this endpoint to find the the objects in the system //With a query stating 'Public' getClient().perform(get("/api/discover/search/objects") - .param("query", query)) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results should not contain this - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( - Matchers.contains( - SearchResultMatcher - .matchOnItemNameAndHitHighlight("item", "items", - "Public item 2", query, "dc.title") - )))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("query", query)) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results should not contain this + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.not( + Matchers.contains( + SearchResultMatcher + .matchOnItemNameAndHitHighlight("item", "items", + "Public item 2", query, "dc.title") + )))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2216,68 +2216,67 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "test*,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test"), - SearchResultMatcher.matchOnItemName("item", "items", "Test 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test"), + SearchResultMatcher.matchOnItemName("item", "items", "Test 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2290,67 +2289,66 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-test*,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-test*,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2363,77 +2361,77 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/objects") - .param("size", "2") - .param("page", "1")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - //Size of 2 because that's what we entered - //Page number 1 because that's the param we entered - //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages - //We made 7 elements -> 7 total elements - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) - ))) - //These are the two elements that'll be shown (because page = 1, so the third and fourth element - // in the list) and they'll be the only ones because the size is 2 - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.match(), - SearchResultMatcher.match() - ))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("size", "2") + .param("page", "1")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + //Size of 2 because that's what we entered + //Page number 1 because that's the param we entered + //TotalPages 4 because size = 2 and total elements is 7 -> 4 pages + //We made 7 elements -> 7 total elements + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 4, 7) + ))) + //These are the two elements that'll be shown (because page = 1, so the third and fourth element + // in the list) and they'll be the only ones because the size is 2 + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.match(), + SearchResultMatcher.match() + ))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2446,61 +2444,61 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") - .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") - .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") - .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald").withAuthor("t, t").withAuthor("t, y") + .withAuthor("t, r").withAuthor("t, e").withAuthor("t, z").withAuthor("t, a") + .withAuthor("t, tq").withAuthor("t, ts").withAuthor("t, td").withAuthor("t, tf") + .withAuthor("t, tg").withAuthor("t, th").withAuthor("t, tj").withAuthor("t, tk") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") - .withSubject("d").withSubject("e").withSubject("f").withSubject("g") - .withSubject("h").withSubject("i").withSubject("j") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore") + .withSubject("ExtraEntry").withSubject("a").withSubject("b").withSubject("c") + .withSubject("d").withSubject("e").withSubject("f").withSubject("g") + .withSubject("h").withSubject("i").withSubject("j") + .build(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With a size 2 getClient().perform(get("/api/discover/search/facets")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(true), - FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/facets"))) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacetWithMinMax(true, "Doe, Jane", "Testing, Works"), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(true), + FacetEntryMatcher.dateIssuedFacetWithMinMax(false, "1990-02-13", "2010-10-17"), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/facets"))) ; } @@ -2513,67 +2511,66 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "Test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( - SearchResultMatcher.matchOnItemName("item", "items", "Test") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.containsInAnyOrder( + SearchResultMatcher.matchOnItemName("item", "items", "Test") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2586,68 +2583,67 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-Test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItems( - SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-Test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItems( + SearchResultMatcher.matchOnItemName("item", "items", "Test 2"), + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -2660,67 +2656,66 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest //** GIVEN ** //1. A community-collection structure with one parent community with sub-community and two collections. parentCommunity = CommunityBuilder.createCommunity(context) - .withName("Parent Community") - .build(); + .withName("Parent Community") + .build(); Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) - .withName("Sub Community") - .build(); + .withName("Sub Community") + .build(); Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); //2. Three public items that are readable by Anonymous with different subjects Item publicItem1 = ItemBuilder.createItem(context, col1) - .withTitle("Test") - .withIssueDate("2010-10-17") - .withAuthor("Smith, Donald") - .withSubject("ExtraEntry") - .build(); + .withTitle("Test") + .withIssueDate("2010-10-17") + .withAuthor("Smith, Donald") + .withSubject("ExtraEntry") + .build(); Item publicItem2 = ItemBuilder.createItem(context, col2) - .withTitle("Test 2") - .withIssueDate("1990-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") - .withSubject("TestingForMore").withSubject("ExtraEntry") - .build(); + .withTitle("Test 2") + .withIssueDate("1990-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("Testing, Works") + .withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); Item publicItem3 = ItemBuilder.createItem(context, col2) - .withTitle("Public item 2") - .withIssueDate("2010-02-13") - .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") - .withAuthor("test2, test2").withAuthor("Maybe, Maybe") - .withSubject("AnotherTest").withSubject("TestingForMore") - .withSubject("ExtraEntry") - .build(); + .withTitle("Public item 2") + .withIssueDate("2010-02-13") + .withAuthor("Smith, Maria").withAuthor("Doe, Jane").withAuthor("test,test") + .withAuthor("test2, test2").withAuthor("Maybe, Maybe") + .withSubject("AnotherTest").withSubject("TestingForMore").withSubject("ExtraEntry") + .build(); UUID scope = col2.getID(); //** WHEN ** //An anonymous user browses this endpoint to find the the objects in the system //With the given search filter getClient().perform(get("/api/discover/search/objects") - .param("f.title", "-id:test,query")) - //** THEN ** - //The status has to be 200 OK - .andExpect(status().isOk()) - //The type has to be 'discover' - .andExpect(jsonPath("$.type", is("discover"))) - //The page object needs to look like this - .andExpect(jsonPath("$._embedded.searchResult.page", is( - PageMatcher.pageEntry(0, 20) - ))) - //The search results have to contain the items that match the searchFilter - .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( - SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") - ))) - //These facets have to show up in the embedded.facets section as well with the given hasMore property - // because we don't exceed their default limit for a hasMore true (the default is 10) - .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( - FacetEntryMatcher.authorFacet(false), - FacetEntryMatcher.entityTypeFacet(false), - FacetEntryMatcher.subjectFacet(false), - FacetEntryMatcher.dateIssuedFacet(false), - FacetEntryMatcher.hasContentInOriginalBundleFacet(false) - ))) - //There always needs to be a self link available - .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) + .param("f.title", "-id:test,query")) + //** THEN ** + //The status has to be 200 OK + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.type", is("discover"))) + //The page object needs to look like this + .andExpect(jsonPath("$._embedded.searchResult.page", is( + PageMatcher.pageEntry(0, 20) + ))) + //The search results have to contain the items that match the searchFilter + .andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.hasItem( + SearchResultMatcher.matchOnItemName("item", "items", "Public item 2") + ))) + //These facets have to show up in the embedded.facets section as well with the given hasMore property + // because we don't exceed their default limit for a hasMore true (the default is 10) + .andExpect(jsonPath("$._embedded.facets", Matchers.containsInAnyOrder( + FacetEntryMatcher.authorFacet(false), + FacetEntryMatcher.entityTypeFacet(false), + FacetEntryMatcher.subjectFacet(false), + FacetEntryMatcher.dateIssuedFacet(false), + FacetEntryMatcher.hasContentInOriginalBundleFacet(false) + ))) + //There always needs to be a self link available + .andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects"))) ; } @@ -3587,4 +3582,4 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest } -} +} \ No newline at end of file diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java index c8d2322d29..4f2c307ac8 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipTypeRestControllerIT.java @@ -44,8 +44,6 @@ public class RelationshipTypeRestControllerIT extends AbstractEntityIntegrationT @Test public void findAllEntityTypes() throws Exception { - context.turnOffAuthorisationSystem(); - getClient().perform(get("/api/core/entitytypes")) .andExpect(status().isOk()) @@ -67,7 +65,6 @@ public class RelationshipTypeRestControllerIT extends AbstractEntityIntegrationT @Test public void findAllRelationshipTypesForPublications() throws Exception { - context.turnOffAuthorisationSystem(); EntityType publicationEntityType = entityTypeService.findByEntityType(context, "Publication"); EntityType personEntityType = entityTypeService.findByEntityType(context, "Person"); EntityType projectEntityType = entityTypeService.findByEntityType(context, "Project"); @@ -186,6 +183,7 @@ public class RelationshipTypeRestControllerIT extends AbstractEntityIntegrationT Relationship relationship4 = RelationshipBuilder .createRelationshipBuilder(context, publication2, author3, isAuthorOfPublicationRelationshipType).build(); + context.restoreAuthSystemState(); getClient().perform(get("/api/core/relationships/isAuthorOfPublication")) .andExpect(status().isOk()) .andExpect(jsonPath("$._embedded.relationships", containsInAnyOrder( From 6e21bcdad1db025237f0837c759a5b553be86d2a Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Thu, 2 May 2019 15:08:08 +0200 Subject: [PATCH 139/188] Implemented feedback --- .../src/main/java/org/dspace/content/ItemServiceImpl.java | 5 ++--- .../java/org/dspace/content/RelationshipServiceImpl.java | 5 +---- 2 files changed, 3 insertions(+), 7 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 ae020c537e..1e8f00ff3c 100644 --- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java @@ -1500,17 +1500,16 @@ prevent the generation of resource policy entry values with null dspace_object a } private String getEntityTypeStringFromMetadata(List list) { - String entityType = null; for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getMetadataField().getMetadataSchema().getName(), "relationship") && StringUtils.equals(mdv.getMetadataField().getElement(), "type")) { - entityType = mdv.getValue(); + return mdv.getValue(); } } - return entityType; + return null; } private RelationshipMetadataValue constructResultingMetadataValue(Item item, String value, diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java index 8c166edc85..7e4827ea06 100644 --- a/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/RelationshipServiceImpl.java @@ -248,10 +248,7 @@ public class RelationshipServiceImpl implements RelationshipService { return false; } String leftEntityType = list.get(0).getValue(); - if (!StringUtils.equals(leftEntityType, entityTypeToProcess.getLabel())) { - return false; - } - return true; + return StringUtils.equals(leftEntityType, entityTypeToProcess.getLabel()); } public Relationship find(Context context, int id) throws SQLException { From a3334bd10ef84b2428100a625916af5de753af98 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Mon, 6 May 2019 15:48:38 +0200 Subject: [PATCH 140/188] Added inline comments to the RelatinshipRestRepositoryIT --- .../rest/RelationshipRestRepositoryIT.java | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 0837f4a86c..f0c9de8615 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -731,6 +731,8 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest // First create the structure of 5 metadatavalues just like the additions test. context.restoreAuthSystemState(); + // This post request will add a first relationship to the publiction and thus create a first set of metadata + // For the author values, namely "Donald Smith" MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -749,13 +751,17 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest Map map = mapper.readValue(content, Map.class); String firstRelationshipIdString = String.valueOf(map.get("id")); + // This test will double check that the leftPlace for this relationship is indeed 0 getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); context.turnOffAuthorisationSystem(); + // We retrieve the publication again to ensure that we have the latest DB object of it publication = itemService.find(context, publication.getID()); + // Add a plain text metadatavalue to the publication + // After this addition, the list of authors should like like "Donald Smith", "plain text" itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text"); itemService.update(context, publication); context.restoreAuthSystemState(); @@ -763,14 +769,18 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text")) { + // Ensure that this is indeed the second metadatavalue in the list of authors for the publication assertEquals(1, mdv.getPlace()); } } + // This test checks again that the first relationship is still on leftplace 0 and not altered + // Because of the MetadataValue addition getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + // Creates another Relationship for the Publication and thus adding a third metadata value for the author mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -788,11 +798,15 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest map = mapper.readValue(content, Map.class); String secondRelationshipIdString = String.valueOf(map.get("id")); + // This test verifies that the newly created Relationship is on leftPlace 2, because the first relationship + // is on leftPlace 0 and the plain text metadataValue occupies the place 1 getClient(adminToken).perform(get("/api/core/relationships/" + secondRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); context.turnOffAuthorisationSystem(); + // Get the publication from the DB again to ensure that we have the latest object publication = itemService.find(context, publication.getID()); + // Add a fourth metadata value to the publication itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); itemService.update(context, publication); context.restoreAuthSystemState(); @@ -800,11 +814,14 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text two")) { + // Ensure that this plain text metadata value is on the fourth place (place 3) for the publication assertEquals(3, mdv.getPlace()); } } + // The list should currently look like this: "Donald Smith", "plain text", "Maria Smith", "plain text two" + // This creates a third relationship for the publication and thus adding a fifth value for author metadatavalues mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -822,12 +839,14 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest map = mapper.readValue(content, Map.class); String thirdRelationshipIdString = String.valueOf(map.get("id")); + // This verifies that the newly created third relationship is on leftPlace 4. getClient(adminToken).perform(get("/api/core/relationships/" + thirdRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); + // Create another plain text metadata value on the publication itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); context.restoreAuthSystemState(); @@ -835,12 +854,13 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text three")) { + // Verify that this plain text value is indeed the 6th author in the list (place 5) assertEquals(5, mdv.getPlace()); } } - // Now we will have a dc.contributor.author metadatavalue list of size 5 in the following order: - // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe" + // Now we will have a dc.contributor.author metadatavalue list of size 6 in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe", "plain text three" List authors = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); List listToRemove = new LinkedList<>(); for (MetadataValue metadataValue : authors) { @@ -891,6 +911,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest @Test public void deleteRelationshipsAndValidatePlace() throws Exception { + context.turnOffAuthorisationSystem(); parentCommunity = CommunityBuilder.createCommunity(context) @@ -937,11 +958,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest entityTypeService.findByEntityType(context, "Person"), "isAuthorOfPublication", "isPublicationOfAuthor"); - context.restoreAuthSystemState(); String adminToken = getAuthToken(admin.getEmail(), password); // First create the structure of 5 metadatavalues just like the additions test. - + context.restoreAuthSystemState(); + // This post request will add a first relationship to the publiction and thus create a first set of metadata + // For the author values, namely "Donald Smith" MvcResult mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -960,28 +982,36 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest Map map = mapper.readValue(content, Map.class); String firstRelationshipIdString = String.valueOf(map.get("id")); + // This test will double check that the leftPlace for this relationship is indeed 0 getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + context.turnOffAuthorisationSystem(); + // We retrieve the publication again to ensure that we have the latest DB object of it publication = itemService.find(context, publication.getID()); + // Add a plain text metadatavalue to the publication + // After this addition, the list of authors should like like "Donald Smith", "plain text" itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text"); itemService.update(context, publication); - context.restoreAuthSystemState(); List list = itemService.getMetadata(publication, "dc", "contributor", "author", Item.ANY); for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text")) { + // Ensure that this is indeed the second metadatavalue in the list of authors for the publication assertEquals(1, mdv.getPlace()); } } + // This test checks again that the first relationship is still on leftplace 0 and not altered + // Because of the MetadataValue addition getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(0))); + // Creates another Relationship for the Publication and thus adding a third metadata value for the author mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -999,12 +1029,15 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest map = mapper.readValue(content, Map.class); String secondRelationshipIdString = String.valueOf(map.get("id")); + // This test verifies that the newly created Relationship is on leftPlace 2, because the first relationship + // is on leftPlace 0 and the plain text metadataValue occupies the place 1 getClient(adminToken).perform(get("/api/core/relationships/" + secondRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(2))); - context.turnOffAuthorisationSystem(); + // Get the publication from the DB again to ensure that we have the latest object publication = itemService.find(context, publication.getID()); + // Add a fourth metadata value to the publication itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text two"); itemService.update(context, publication); context.restoreAuthSystemState(); @@ -1012,11 +1045,14 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text two")) { + // Ensure that this plain text metadata value is on the fourth place (place 3) for the publication assertEquals(3, mdv.getPlace()); } } + // The list should currently look like this: "Donald Smith", "plain text", "Maria Smith", "plain text two" + // This creates a third relationship for the publication and thus adding a fifth value for author metadatavalues mvcResult = getClient(adminToken).perform(post("/api/core/relationships") .param("relationshipType", isAuthorOfPublicationRelationshipType.getID() @@ -1034,12 +1070,14 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest map = mapper.readValue(content, Map.class); String thirdRelationshipIdString = String.valueOf(map.get("id")); + // This verifies that the newly created third relationship is on leftPlace 4. getClient(adminToken).perform(get("/api/core/relationships/" + thirdRelationshipIdString)) .andExpect(status().isOk()) .andExpect(jsonPath("leftPlace", is(4))); context.turnOffAuthorisationSystem(); publication = itemService.find(context, publication.getID()); + // Create another plain text metadata value on the publication itemService.addMetadata(context, publication, "dc", "contributor", "author", Item.ANY, "plain text three"); itemService.update(context, publication); context.restoreAuthSystemState(); @@ -1047,13 +1085,14 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest for (MetadataValue mdv : list) { if (StringUtils.equals(mdv.getValue(), "plain text three")) { + // Verify that this plain text value is indeed the 6th author in the list (place 5) assertEquals(5, mdv.getPlace()); } } + // Now we will have a dc.contributor.author metadatavalue list of size 6 in the following order: + // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe", "plain text three" - // Now we will have a dc.contributor.author metadatavalue list of size 5 in the following order: - // "Smith, Donald", "plain text", "Smith, Maria", "plain text two", "Maybe, Maybe" // Now we delete the second relationship, the one that made "Smith, Maria" metadatavalue // Ensure that all metadatavalues before this one in the list still hold the same place From aac6b12de96ddd99222f607a1df39196fc960438 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 7 May 2019 09:19:48 +0200 Subject: [PATCH 141/188] Additional pagination tests --- .../app/rest/EntityTypeRestRepositoryIT.java | 20 ++++++++++++++++++- .../rest/RelationshipRestRepositoryIT.java | 10 ++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java index 15d1ca589f..5a8706cff8 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/EntityTypeRestRepositoryIT.java @@ -55,7 +55,6 @@ public class EntityTypeRestRepositoryIT extends AbstractEntityIntegrationTest { @Test public void getAllEntityTypeEndpointWithPaging() throws Exception { - //When we call this facets endpoint getClient().perform(get("/api/core/entitytypes").param("size", "5")) //We expect a 200 OK status @@ -75,6 +74,25 @@ public class EntityTypeRestRepositoryIT extends AbstractEntityIntegrationTest { EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "OrgUnit")), EntityTypeMatcher.matchEntityTypeEntry(entityTypeService.findByEntityType(context, "Journal")) ))); + + getClient().perform(get("/api/core/entitytypes").param("size", "5").param("page", "1")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //The type has to be 'discover' + .andExpect(jsonPath("$.page.size", is(5))) + .andExpect(jsonPath("$.page.totalElements", is(7))) + .andExpect(jsonPath("$.page.totalPages", is(2))) + .andExpect(jsonPath("$.page.number", is(1))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/entitytypes"))) + //We have 4 facets in the default configuration, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.entitytypes", containsInAnyOrder( + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalVolume")), + EntityTypeMatcher + .matchEntityTypeEntry(entityTypeService.findByEntityType(context, "JournalIssue")) + ))); } @Test diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 723f85e086..d98056f169 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; @@ -173,6 +174,15 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest ))) ; + getClient().perform(get("/api/core/relationships").param("size", "2").param("page", "1")) + + .andExpect(status().isOk()) + .andExpect(jsonPath("$.page", + is(PageMatcher.pageEntryWithTotalPagesAndElements(1, 2, 2, 3)))) + .andExpect(jsonPath("$._embedded.relationships", contains( + RelationshipMatcher.matchRelationship(relationship3) + ))) + ; } From 71cd11b558d8e95a473cc5b96858c9f0997572b5 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 7 May 2019 09:59:32 +0200 Subject: [PATCH 142/188] Implemented the InitializeEntitiesIT changes --- .../dspace/app/rest/InitializeEntitiesIT.java | 80 ++++++++++++------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java index a509aa0516..59f67f00ba 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java @@ -32,6 +32,13 @@ import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +/** + * This class is used to verify the behavior of the {@link org.dspace.app.util.InitializeEntities} script + * It will take the relationship-types.xml as initial input and check if all the objects that created properly. + * It will then also update and verify these objects by using a second XML to verify the update behaviour + * of this script. + * This will ensure that all the EntityTypes and RelationshipTypes are instantiated correctly. + */ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { @Autowired @@ -95,42 +102,21 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { * Verify whether the initialize-entities script can update the relationship types correctly */ @Test - public void test() throws Exception { + public void updateRelationshipTypesTest() throws Exception { List relationshipTypes = relationshipTypeService.findAll(context); - getClient().perform(get("/api/core/relationshiptypes")) - - //We expect a 200 OK status - .andExpect(status().isOk()) - //10 relationship types should be created - .andExpect(jsonPath("$.page.totalElements", is(10))) - //There needs to be a self link to this endpoint - .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) - //We have 10 relationship types, they need to all be present in the embedded section - .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) - )); - - //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) is 0 - getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.leftMinCardinality", is(0))); - //Update the relationships using a different test XML with the initialize-entities script String pathToFile = configurationService.getProperty("dspace.dir") + File.separator + "config" + File.separator + "entities" + File.separator + "relationship-types-update.xml"; runDSpaceScript("initialize-entities", "-f", pathToFile); - //This is a helper object to compare whether the update was successful + // This is a helper object to compare whether the update was successful. We're simply taking the first + // RelationshipType object in the list and altering this by setting the LeftMinCardinality on 10. We've + // Made sure that this RelationshipType object is altered in the same way in the relationship-types-update.xml + // File and thus by running the script, the RelationshipType object in the Database should be the same as our + // alteredRelationshipType object that we just created. + // It's important to note that this object will not alter anything in the Database, this object is merely + // made for the comparison between the REST response and we expect to have happened through the script RelationshipType alteredRelationshipType = relationshipTypes.get(0); alteredRelationshipType.setLeftMinCardinality(10); getClient().perform(get("/api/core/relationshiptypes")) @@ -161,4 +147,40 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { .andExpect(status().isOk()) .andExpect(jsonPath("$.leftMinCardinality", is(10))); } + + /** + * Verifies that the initialize-entities script ran properly and that the objects are created properly + * @throws Exception + */ + @Test + public void getAllRelationshipTypesTest() throws Exception{ + List relationshipTypes = relationshipTypeService.findAll(context); + + getClient().perform(get("/api/core/relationshiptypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //10 relationship types should be created + .andExpect(jsonPath("$.page.totalElements", is(10))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) + //We have 10 relationship types, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) + )); + + //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) is 0 + getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftMinCardinality", is(0))); + } } From b98943ff648fc6e3bbf95379a9382ea8e38011a8 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Tue, 7 May 2019 10:32:35 +0200 Subject: [PATCH 143/188] Fixed checkstyle --- .../src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java index 59f67f00ba..9b421196fa 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java @@ -153,7 +153,7 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { * @throws Exception */ @Test - public void getAllRelationshipTypesTest() throws Exception{ + public void getAllRelationshipTypesTest() throws Exception { List relationshipTypes = relationshipTypeService.findAll(context); getClient().perform(get("/api/core/relationshiptypes")) From b5e29a36b86dab5b927479115aa80178c8a51738 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 7 May 2019 17:48:38 +0200 Subject: [PATCH 144/188] reordered tests to first verify the normal import, and hereafter verify updating (for logic while reading the IT) --- .../dspace/app/rest/InitializeEntitiesIT.java | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java index 9b421196fa..c3d264f67d 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/InitializeEntitiesIT.java @@ -98,6 +98,42 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { super.destroy(); } + /** + * Verifies that the initialize-entities script ran properly and that the objects are created properly + * @throws Exception + */ + @Test + public void getAllRelationshipTypesTest() throws Exception { + List relationshipTypes = relationshipTypeService.findAll(context); + + getClient().perform(get("/api/core/relationshiptypes")) + + //We expect a 200 OK status + .andExpect(status().isOk()) + //10 relationship types should be created + .andExpect(jsonPath("$.page.totalElements", is(10))) + //There needs to be a self link to this endpoint + .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) + //We have 10 relationship types, they need to all be present in the embedded section + .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), + RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) + )); + + //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) is 0 + getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.leftMinCardinality", is(0))); + } + /** * Verify whether the initialize-entities script can update the relationship types correctly */ @@ -147,40 +183,4 @@ public class InitializeEntitiesIT extends AbstractControllerIntegrationTest { .andExpect(status().isOk()) .andExpect(jsonPath("$.leftMinCardinality", is(10))); } - - /** - * Verifies that the initialize-entities script ran properly and that the objects are created properly - * @throws Exception - */ - @Test - public void getAllRelationshipTypesTest() throws Exception { - List relationshipTypes = relationshipTypeService.findAll(context); - - getClient().perform(get("/api/core/relationshiptypes")) - - //We expect a 200 OK status - .andExpect(status().isOk()) - //10 relationship types should be created - .andExpect(jsonPath("$.page.totalElements", is(10))) - //There needs to be a self link to this endpoint - .andExpect(jsonPath("$._links.self.href", containsString("api/core/relationshiptypes"))) - //We have 10 relationship types, they need to all be present in the embedded section - .andExpect(jsonPath("$._embedded.relationshiptypes", containsInAnyOrder( - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(0)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(1)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(2)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(3)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(4)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(5)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(6)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(7)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(8)), - RelationshipTypeMatcher.matchRelationshipTypeEntry(relationshipTypes.get(9))) - )); - - //Verify the left min cardinality of the first relationship type (isAuthorOfPublication) is 0 - getClient().perform(get("/api/core/relationshiptypes/" + relationshipTypes.get(0).getID())) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.leftMinCardinality", is(0))); - } } From 5895f083376660c9cf5be3040225ef9c1d237b1c Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 7 May 2019 18:27:51 +0200 Subject: [PATCH 145/188] Temporarily disabled for https://github.com/DSpace/Rest7Contract/pull/57#discussion_r272605397 --- .../dspace/app/rest/repository/RelationshipRestRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index c96dc8c047..d8500538fe 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -129,6 +129,8 @@ public class RelationshipRestRepository extends DSpaceRestRepository stringList) @@ -160,6 +162,7 @@ public class RelationshipRestRepository extends DSpaceRestRepository Date: Tue, 7 May 2019 18:52:58 +0200 Subject: [PATCH 146/188] Temporarily disabled for https://github.com/DSpace/Rest7Contract/pull/57#discussion_r272605397 --- .../app/rest/RelationshipRestRepositoryIT.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index f0c9de8615..44176c3834 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -44,6 +44,7 @@ import org.dspace.core.Constants; import org.dspace.core.I18nUtil; import org.dspace.eperson.EPerson; import org.dspace.eperson.service.EPersonService; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -1392,7 +1393,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest } - @Test + @Ignore public void putRelationshipAdminAccess() throws Exception { context.turnOffAuthorisationSystem(); @@ -1478,7 +1479,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 1 and author 2 * Verify this is possible for a user with WRITE permissions on author 1 and author 2 */ - @Test + @Ignore public void putRelationshipWriteAccessOnAuthors() throws Exception { context.turnOffAuthorisationSystem(); @@ -1574,7 +1575,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 1 and author 2 * Verify this is possible for a user with WRITE permissions on publication 1 */ - @Test + @Ignore public void putRelationshipWriteAccessOnPublication() throws Exception { context.turnOffAuthorisationSystem(); @@ -1670,7 +1671,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 2 and author 1 * Verify this is possible for a user with WRITE permissions on publication 1 and publication 2 */ - @Test + @Ignore public void putRelationshipWriteAccessOnPublications() throws Exception { context.turnOffAuthorisationSystem(); @@ -1773,7 +1774,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 2 and author 1 * Verify this is possible for a user with WRITE permissions on author 1 */ - @Test + @Ignore public void putRelationshipWriteAccessOnAuthor() throws Exception { context.turnOffAuthorisationSystem(); @@ -1877,7 +1878,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 1 and author 2 * Verify this is NOT possible for a user without WRITE permissions */ - @Test + @Ignore public void putRelationshipNoAccess() throws Exception { context.turnOffAuthorisationSystem(); @@ -1967,7 +1968,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 1 and author 2 * Verify this is NOT possible for a user with WRITE permissions on author 1 */ - @Test + @Ignore public void putRelationshipOnlyAccessOnOneAuthor() throws Exception { context.turnOffAuthorisationSystem(); @@ -2059,7 +2060,7 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest * Change it to a relationship between publication 2 and author 1 * Verify this is NOT possible for a user with WRITE permissions on publication 1 */ - @Test + @Ignore public void putRelationshipOnlyAccessOnOnePublication() throws Exception { context.turnOffAuthorisationSystem(); From be9d80c410e8640062123bfada577c403c5acbc5 Mon Sep 17 00:00:00 2001 From: Ben Bosman Date: Tue, 7 May 2019 19:54:20 +0200 Subject: [PATCH 147/188] Temporarily disabled for https://github.com/DSpace/Rest7Contract/pull/57#discussion_r272605397 --- .../dspace/app/rest/repository/RelationshipRestRepository.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java index d8500538fe..378fea6418 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java @@ -34,7 +34,6 @@ import org.dspace.eperson.EPerson; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.data.rest.webmvc.ResourceNotFoundException; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Component; From 5c035fe6a62e2e0de5416b959dbdcb7b4a0ade7e Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 8 May 2019 13:10:07 +0200 Subject: [PATCH 148/188] Refacted the RelationshipRestRepositoryIT to now use a builder instead of the EPersonService when creating a user --- .../rest/RelationshipRestRepositoryIT.java | 155 +++++++----------- 1 file changed, 61 insertions(+), 94 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 0837f4a86c..74f94e69cd 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.builder.CollectionBuilder; import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; import org.dspace.app.rest.builder.ItemBuilder; import org.dspace.app.rest.builder.RelationshipBuilder; import org.dspace.app.rest.matcher.PageMatcher; @@ -43,7 +44,6 @@ import org.dspace.content.service.RelationshipTypeService; import org.dspace.core.Constants; import org.dspace.core.I18nUtil; import org.dspace.eperson.EPerson; -import org.dspace.eperson.service.EPersonService; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; @@ -57,9 +57,6 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest @Autowired private EntityTypeService entityTypeService; - @Autowired - private EPersonService ePersonService; - @Autowired private AuthorizeService authorizeService; @@ -198,15 +195,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testaze@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, publication, Constants.WRITE, user); @@ -266,15 +260,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testazhfhdfhe@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); @@ -334,15 +325,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("testazeazeazezae@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); context.restoreAuthSystemState(); @@ -1482,15 +1470,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("rrarz@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); @@ -1578,15 +1563,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("uiytirthery@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, publication, Constants.WRITE, user); @@ -1680,15 +1662,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("tturturu@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, publication1, Constants.WRITE, user); @@ -1784,15 +1763,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("tryhrtureery@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); @@ -1881,15 +1857,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("erertertgrdgf@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); context.restoreAuthSystemState(); @@ -1971,15 +1944,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("tjyhrgefdg@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, author1, Constants.WRITE, user); @@ -2069,15 +2039,12 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest - EPerson user = ePersonService.create(context); - user.setFirstName(context, "first"); - user.setLastName(context, "last"); - user.setEmail("tyerzergt@email.com"); - user.setCanLogIn(true); - user.setLanguage(context, I18nUtil.getDefaultLocale().getLanguage()); - ePersonService.setPassword(user, password); - // actually save the eperson to unit testing DB - ePersonService.update(context, user); + EPerson user = EPersonBuilder.createEPerson(context) + .withNameInMetadata("first", "last") + .withEmail("testaze@gmail.com") + .withPassword(password) + .withLanguage(I18nUtil.getDefaultLocale().getLanguage()) + .build(); context.setCurrentUser(user); authorizeService.addPolicy(context, publication1, Constants.WRITE, user); From b76aacc626f2856d606ec9d9723ceb1049d62323 Mon Sep 17 00:00:00 2001 From: Raf Ponsaerts Date: Wed, 8 May 2019 16:23:01 +0200 Subject: [PATCH 149/188] Added the expect status code in test --- .../java/org/dspace/app/rest/RelationshipRestRepositoryIT.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java index 74f94e69cd..a92d48a447 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/RelationshipRestRepositoryIT.java @@ -1329,7 +1329,8 @@ public class RelationshipRestRepositoryIT extends AbstractEntityIntegrationTest .andExpect(jsonPath("rightPlace", is(2))); // Here we will delete the secondRelationship and then verify that the others have their place handled properly - getClient(adminToken).perform(delete("/api/core/relationships/" + secondRelationshipIdString)); + getClient(adminToken).perform(delete("/api/core/relationships/" + secondRelationshipIdString)) + .andExpect(status().isNoContent()); getClient(adminToken).perform(get("/api/core/relationships/" + firstRelationshipIdString)) .andExpect(status().isOk()) From f1073f0af062611240f856630cea1cd6c9753165 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 16 Nov 2018 22:41:55 +0000 Subject: [PATCH 150/188] Update RESTv7 to only use Spring Security on /api path --- .../security/WebSecurityConfiguration.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java index 259ece7d4a..16aef3ffcd 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/security/WebSecurityConfiguration.java @@ -84,23 +84,24 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { //Logout configuration .logout() - //On logout, clear the "session" salt - .addLogoutHandler(customLogoutHandler) - //Configure the logout entry point - .logoutRequestMatcher(new AntPathRequestMatcher("/api/authn/logout")) - //When logout is successful, return OK (204) status - .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT)) - //Everyone can call this endpoint - .permitAll() + //On logout, clear the "session" salt + .addLogoutHandler(customLogoutHandler) + //Configure the logout entry point + .logoutRequestMatcher(new AntPathRequestMatcher("/api/authn/logout")) + //When logout is successful, return OK (204) status + .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT)) + //Everyone can call this endpoint + .permitAll() .and() //Configure the URL patterns with their authentication requirements - .authorizeRequests() - //Allow POST by anyone on the login endpoint - .antMatchers(HttpMethod.POST,"/api/authn/login").permitAll() - //TRACE, CONNECT, OPTIONS, HEAD - //Everyone can call GET on the status endpoint - .antMatchers(HttpMethod.GET, "/api/authn/status").permitAll() + //Enable Spring Security authorization on /api/ URLs only + .antMatcher("/api/**").authorizeRequests() + //Allow POST by anyone on the login endpoint + .antMatchers(HttpMethod.POST,"/api/authn/login").permitAll() + //TRACE, CONNECT, OPTIONS, HEAD + //Everyone can call GET on the status endpoint + .antMatchers(HttpMethod.GET, "/api/authn/status").permitAll() .and() //Add a filter before our login endpoints to do the authentication based on the data in the HTTP request From 5eb338d9b7246bc25297456beca252f838ceef23 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 16 Nov 2018 22:42:44 +0000 Subject: [PATCH 151/188] Update RESTv7 to ComponentScan for webapp configs under org.dspace.app.configuration --- .../java/org/dspace/app/rest/utils/ApplicationConfig.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java index 71651fa133..7e90a21c28 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java @@ -14,12 +14,15 @@ import org.springframework.data.web.config.EnableSpringDataWebSupport; /** * This class provide extra configuration for our Spring Boot Application - * + *

+ * NOTE: @ComponentScan on "org.dspace.app.configuration" provides a way for other modules or plugins + * to "inject" their own configurations / subpaths into our Spring Boot webapp. * @author Andrea Bollini (andrea.bollini at 4science.it) */ @Configuration @EnableSpringDataWebSupport -@ComponentScan( {"org.dspace.app.rest.converter", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils"}) +@ComponentScan( {"org.dspace.app.rest.converter", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils", + "org.dspace.app.configuration"}) public class ApplicationConfig { @Value("${dspace.dir}") private String dspaceHome; From af16e6e7804113a595982126974fd613b43e6546 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 16 Nov 2018 22:43:38 +0000 Subject: [PATCH 152/188] Remove SWORD overlay folders/files --- dspace/modules/sword/pom.xml | 129 ------------------ .../modules/sword/src/main/webapp/.gitignore | 0 2 files changed, 129 deletions(-) delete mode 100644 dspace/modules/sword/pom.xml delete mode 100644 dspace/modules/sword/src/main/webapp/.gitignore diff --git a/dspace/modules/sword/pom.xml b/dspace/modules/sword/pom.xml deleted file mode 100644 index a8498483ce..0000000000 --- a/dspace/modules/sword/pom.xml +++ /dev/null @@ -1,129 +0,0 @@ - - 4.0.0 - org.dspace.modules - sword - war - DSpace SWORD :: Local Customizations - - This project allows you to overlay your own local SWORD customizations - on top of the default SWORD web application provided with DSpace. - - - - - org.dspace - modules - 7.0-SNAPSHOT - .. - - - - - ${basedir}/../../.. - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - prepare-package - - unpack-dependencies - - - org.dspace.modules - additions - - ${project.build.directory}/additions - META-INF/** - - - - - - org.apache.maven.plugins - maven-war-plugin - - false - - true - - - - ${project.build.directory}/additions - WEB-INF/classes - - - - - - prepare-package - - - - - - - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - - - - - org.dspace.modules - additions - - - xml-apis - xml-apis - - - - - org.dspace - dspace-sword - war - - - org.dspace - dspace-sword - jar - classes - - - javax.servlet - javax.servlet-api - provided - - - - diff --git a/dspace/modules/sword/src/main/webapp/.gitignore b/dspace/modules/sword/src/main/webapp/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 From 1b143aa5cdf9c9c6be7f858495d1197c8272e640 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 16 Nov 2018 22:45:08 +0000 Subject: [PATCH 153/188] Change SWORDv1 to a JAR dependency. Add as RESTv7 dependency --- dspace-spring-rest/pom.xml | 6 ++++++ dspace-sword/pom.xml | 9 ++++++++- dspace/pom.xml | 1 - pom.xml | 8 -------- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index 0c904bfe60..390a1c27cd 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -256,6 +256,12 @@ org.dspace dspace-services + + + org.dspace + dspace-sword + + org.apache.commons commons-collections4 diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 63f149e01f..5a07a60e4a 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.dspace dspace-sword - war + jar DSpace SWORD DSpace SWORD Deposit Service Provider Web Application @@ -96,6 +96,13 @@ dspace-api-lang + + + org.springframework.boot + spring-boot-starter-web + 1.4.4.RELEASE + + jaxen jaxen diff --git a/dspace/pom.xml b/dspace/pom.xml index 5961bf9a1c..8b4427a508 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -227,7 +227,6 @@ org.dspace dspace-sword - classes compile diff --git a/pom.xml b/pom.xml index a06a94dfa6..c46616e5da 100644 --- a/pom.xml +++ b/pom.xml @@ -941,14 +941,6 @@ org.dspace dspace-sword 7.0-SNAPSHOT - jar - classes - - - org.dspace - dspace-sword - 7.0-SNAPSHOT - war org.dspace From 7f3877c7bc5c25f403f27791426ab39e36186369 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 16 Nov 2018 22:45:58 +0000 Subject: [PATCH 154/188] Create SWORDWebConfig to replace SWORD's web.xml. Fix compilation error in servlet --- .../app/configuration/SWORDWebConfig.java | 49 +++++++++++++++++++ .../sword/server/AtomDocumentServlet.java | 5 -- 2 files changed, 49 insertions(+), 5 deletions(-) create mode 100644 dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java diff --git a/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java new file mode 100644 index 0000000000..516cbec125 --- /dev/null +++ b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java @@ -0,0 +1,49 @@ +/** + * 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.configuration; + +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SWORDWebConfig { + + @Bean + public ServletContextInitializer swordv1ContextInitializer() { + return servletContext -> { + servletContext.setInitParameter("sword-server-class", "org.dspace.sword.DSpaceSWORDServer"); + servletContext.setInitParameter("authentication-method", "Basic"); + }; + } + + @Bean + public ServletRegistrationBean swordv1ServiceDocumentBean() { + ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.ServiceDocumentServlet(), + "/sword/servicedocument/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + public ServletRegistrationBean swordv1DepositBean() { + ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.DepositServlet(), + "/sword/deposit/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + public ServletRegistrationBean swordv1MediaLinkBean() { + ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.AtomDocumentServlet(), + "/sword/media-link/*"); + bean.setLoadOnStartup(1); + return bean; + } +} diff --git a/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java b/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java index adf049c10a..0b2a675efd 100644 --- a/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java +++ b/dspace-sword/src/main/java/org/purl/sword/server/AtomDocumentServlet.java @@ -27,11 +27,6 @@ import org.purl.sword.base.SWORDException; */ public class AtomDocumentServlet extends DepositServlet { - public AtomDocumentServlet() - throws ServletException { - super(); - } - /** * Process the get request. */ From fa61b737db54b4708f2142b0fb9dce2d8cd007a7 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 28 Nov 2018 17:11:08 +0000 Subject: [PATCH 155/188] Refactor Application startup to load DSpace configs early in boot process. Also fixes DS-3492 --- .../java/org/dspace/app/rest/Application.java | 13 ++--- .../app/rest/utils/ApplicationConfig.java | 19 ++++---- .../utils/DSpaceConfigurationInitializer.java | 48 +++++++++++++++++++ .../rest/utils/DSpaceKernelInitializer.java | 42 +++++++++------- .../src/main/resources/application.properties | 29 ++--------- dspace/config/modules/rest.cfg | 12 ++++- 6 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/Application.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/Application.java index 3e8328d478..0315860178 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/Application.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/Application.java @@ -14,6 +14,7 @@ import org.dspace.app.rest.filter.DSpaceRequestContextFilter; import org.dspace.app.rest.model.hateoas.DSpaceRelProvider; import org.dspace.app.rest.parameter.resolver.SearchFilterResolver; import org.dspace.app.rest.utils.ApplicationConfig; +import org.dspace.app.rest.utils.DSpaceConfigurationInitializer; import org.dspace.app.rest.utils.DSpaceKernelInitializer; import org.dspace.app.util.DSpaceContextListener; import org.dspace.utils.servlet.DSpaceWebappServletFilter; @@ -22,7 +23,6 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; import org.springframework.core.annotation.Order; @@ -62,7 +62,6 @@ public class Application extends SpringBootServletInitializer { * This is necessary to allow us to build a deployable WAR, rather than * always relying on embedded Tomcat. *

- *

* See: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file * * @param application @@ -70,13 +69,10 @@ public class Application extends SpringBootServletInitializer { */ @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + // Pass this Application class, and our initializers for DSpace Kernel and Configuration + // NOTE: Kernel must be initialized before Configuration return application.sources(Application.class) - .initializers(new DSpaceKernelInitializer()); - } - - @Bean - public ServletContextInitializer contextInitializer() { - return servletContext -> servletContext.setInitParameter("dspace.dir", configuration.getDspaceHome()); + .initializers(new DSpaceKernelInitializer(), new DSpaceConfigurationInitializer()); } /** @@ -89,7 +85,6 @@ public class Application extends SpringBootServletInitializer { @Order(2) protected DSpaceContextListener dspaceContextListener() { // This listener initializes the DSpace Context object - // (and loads all DSpace configs) return new DSpaceContextListener(); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java index 7e90a21c28..fd9059faa6 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/ApplicationConfig.java @@ -13,27 +13,24 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.web.config.EnableSpringDataWebSupport; /** - * This class provide extra configuration for our Spring Boot Application + * This class provides extra configuration for our Spring Boot Application *

- * NOTE: @ComponentScan on "org.dspace.app.configuration" provides a way for other modules or plugins - * to "inject" their own configurations / subpaths into our Spring Boot webapp. + * NOTE: @ComponentScan on "org.dspace.app.configuration" provides a way for other DSpace modules or plugins + * to "inject" their own Spring configurations / subpaths into our Spring Boot webapp. + * * @author Andrea Bollini (andrea.bollini at 4science.it) + * @author Tim Donohue */ @Configuration @EnableSpringDataWebSupport @ComponentScan( {"org.dspace.app.rest.converter", "org.dspace.app.rest.repository", "org.dspace.app.rest.utils", "org.dspace.app.configuration"}) public class ApplicationConfig { - @Value("${dspace.dir}") - private String dspaceHome; - - @Value("${cors.allowed-origins}") + // Allowed CORS origins. Defaults to * (everywhere) + // Can be overridden in DSpace configuration + @Value("${rest.cors.allowed-origins:*}") private String corsAllowedOrigins; - public String getDspaceHome() { - return dspaceHome; - } - public String[] getCorsAllowedOrigins() { if (corsAllowedOrigins != null) { return corsAllowedOrigins.split("\\s*,\\s*"); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java new file mode 100644 index 0000000000..2e05ea3fb7 --- /dev/null +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java @@ -0,0 +1,48 @@ +/** + * 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.rest.utils; + +import org.apache.commons.configuration2.Configuration; +import org.apache.commons.configuration2.spring.ConfigurationPropertySource; +import org.dspace.services.ConfigurationService; +import org.dspace.services.factory.DSpaceServicesFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * Utility class that will initialize the DSpace Configuration on Spring Boot startup. + *

+ * NOTE: MUST be loaded after DSpaceKernelInitializer, as it requires the kernel is already initialized. + *

+ * This initializer ensures that our DSpace Configuration is loaded into Spring's list of PropertySources + * very early in the Spring Boot startup process. That is important as it allows us to use DSpace configurations + * within @ConditionalOnProperty annotations on beans, as well as @Value annotations and XML bean definitions. + *

+ * Used by org.dspace.app.rest.Application + */ +public class DSpaceConfigurationInitializer implements ApplicationContextInitializer { + + private static final Logger log = LoggerFactory.getLogger(DSpaceConfigurationInitializer.class); + + @Override + public void initialize(final ConfigurableApplicationContext applicationContext) { + // Load DSpace Configuration service (requires kernel already initialized) + ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); + Configuration configuration = configurationService.getConfiguration(); + + // Create an Apache Commons Configuration Property Source from our configuration + ConfigurationPropertySource apacheCommonsConfigPropertySource = + new ConfigurationPropertySource(configuration.getClass().getName(), configuration); + + // Append it to the Environment's list of PropertySources + applicationContext.getEnvironment().getPropertySources().addLast(apacheCommonsConfigPropertySource); + } +} + diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceKernelInitializer.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceKernelInitializer.java index 039cfa5af9..73a96259bf 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceKernelInitializer.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceKernelInitializer.java @@ -11,6 +11,7 @@ import java.io.File; import javax.naming.Context; import javax.naming.InitialContext; +import org.apache.commons.lang3.StringUtils; import org.dspace.kernel.DSpaceKernel; import org.dspace.kernel.DSpaceKernelManager; import org.dspace.servicemanager.DSpaceKernelImpl; @@ -22,6 +23,7 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; +import org.springframework.core.env.ConfigurableEnvironment; /** * Utility class that will initialize the DSpace Kernel on Spring Boot startup. @@ -35,16 +37,16 @@ public class DSpaceKernelInitializer implements ApplicationContextInitializer Date: Wed, 28 Nov 2018 18:19:15 +0000 Subject: [PATCH 156/188] Make SWORD module configurable via sword-server.cfg. Remove obsolete web.xml --- .../app/configuration/SWORDWebConfig.java | 39 +++++++- dspace-sword/src/main/webapp/WEB-INF/web.xml | 91 ------------------- dspace/config/modules/sword-server.cfg | 22 +++++ 3 files changed, 56 insertions(+), 96 deletions(-) delete mode 100644 dspace-sword/src/main/webapp/WEB-INF/web.xml diff --git a/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java index 516cbec125..4d1578385b 100644 --- a/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java +++ b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java @@ -7,42 +7,71 @@ */ package org.dspace.app.configuration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.web.servlet.ServletContextInitializer; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +/** + * SWORD webapp configuration. Replaces the old web.xml + *

+ * This @Configuration class is automatically discovered by Spring via a @ComponentScan. + *

+ * All SWORD web configurations (beans) can be enabled or disabled by setting "sword-server.enabled" + * to true or false, respectively (in your DSpace configuration). Default is "false". + *

+ * All @Value annotated configurations below can also be overridden in your DSpace configuration. + * + * @author Tim Donohue + */ @Configuration public class SWORDWebConfig { + // Path where SWORD should be deployed (when enabled). Defaults to "sword" + @Value("${sword-server.path:sword}") + private String swordPath; + + // SWORD Server class. Defaults to "org.dspace.sword.DSpaceSWORDServer" + @Value("${sword-server.class:org.dspace.sword.DSpaceSWORDServer}") + private String serverClass; + + // SWORD Authentication Method. Defaults to "Basic" + @Value("${sword-server.authentication-method:Basic}") + private String authenticationMethod; @Bean + @ConditionalOnProperty("sword-server.enabled") public ServletContextInitializer swordv1ContextInitializer() { return servletContext -> { - servletContext.setInitParameter("sword-server-class", "org.dspace.sword.DSpaceSWORDServer"); - servletContext.setInitParameter("authentication-method", "Basic"); + servletContext.setInitParameter("sword-server-class", serverClass); + servletContext.setInitParameter("authentication-method", authenticationMethod); }; } @Bean + @ConditionalOnProperty("sword-server.enabled") public ServletRegistrationBean swordv1ServiceDocumentBean() { ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.ServiceDocumentServlet(), - "/sword/servicedocument/*"); + "/" + swordPath + "/servicedocument/*"); bean.setLoadOnStartup(1); return bean; } @Bean + @ConditionalOnProperty("sword-server.enabled") public ServletRegistrationBean swordv1DepositBean() { ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.DepositServlet(), - "/sword/deposit/*"); + "/" + swordPath + "/deposit/*"); bean.setLoadOnStartup(1); return bean; } @Bean + @ConditionalOnProperty("sword-server.enabled") public ServletRegistrationBean swordv1MediaLinkBean() { ServletRegistrationBean bean = new ServletRegistrationBean( new org.purl.sword.server.AtomDocumentServlet(), - "/sword/media-link/*"); + "/" + swordPath + "/media-link/*"); bean.setLoadOnStartup(1); return bean; } diff --git a/dspace-sword/src/main/webapp/WEB-INF/web.xml b/dspace-sword/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 14b873ccd9..0000000000 --- a/dspace-sword/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,91 +0,0 @@ - - - - - DSpace SWORD Server - - - - The location of the DSpace home directory - dspace.dir - ${dspace.dir} - - - - The SWORDServer class name - sword-server-class - org.dspace.sword.DSpaceSWORDServer - - - - log4jConfiguration - ${dspace.dir}/config/log4j2.xml - - The location of the Log4J configuration - - - - - The type of authentication used : [Basic|None] - authentication-method - Basic - - - - - - org.dspace.app.util.DSpaceContextListener - - - - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - - - - - servicedocument - org.purl.sword.server.ServiceDocumentServlet - - - - deposit - org.purl.sword.server.DepositServlet - - - - media-link - org.purl.sword.server.AtomDocumentServlet - - - - - - servicedocument - /servicedocument/* - - - - deposit - /deposit/* - - - - media-link - /media-link/* - - - diff --git a/dspace/config/modules/sword-server.cfg b/dspace/config/modules/sword-server.cfg index 6c6778d9c7..0da35ba881 100644 --- a/dspace/config/modules/sword-server.cfg +++ b/dspace/config/modules/sword-server.cfg @@ -6,6 +6,28 @@ # SWORD protocol) # #---------------------------------------------------------------# +# Whether or not to enable the SWORD v1 module +# When "true", the SWORD module is accessible on ${sword-server.path} +# When "false" or commented out, SWORD is disabled/inaccessible. +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#sword-server.enabled = true + +# Path where SWORD v1 module is available (in the Spring REST webapp) +# Defaults to "sword", which means the SWORD mould would be available +# at ${dspace.restURL}/sword/ +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#sword-server.path = sword + +# The SWORDServer class name (in charge of all SWORD activities) +# This Java class must implement 'org.purl.sword.server.SWORDServer' +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#sword-server.class = org.dspace.sword.DSpaceSWORDServer + +# The Authentication Method SWORD should use. +# Valid values are "Basic" or "None". Default is "Basic" +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#sword-server.authentication-method = Basic + # tell the SWORD METS implementation which package ingester to use # to install deposited content. This should refer to one of the # classes configured for: From 8e3d12a34dd982adabe9c73a01061c1fc917472b Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 30 Jan 2019 21:05:48 +0000 Subject: [PATCH 157/188] Add basic Integration Tests for SWORDv1 endpoint using new AbstractWebClientIntegrationTest --- dspace-spring-rest/pom.xml | 15 ++- .../AbstractControllerIntegrationTest.java | 16 +++- .../AbstractWebClientIntegrationTest.java | 93 +++++++++++++++++++ .../test/java/org/dspace/sword/Swordv1IT.java | 60 ++++++++++++ 4 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java create mode 100644 dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index 390a1c27cd..611113d355 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -29,8 +29,10 @@ org.dspace.app.rest.Application 1.4.4.RELEASE - 2.2.0 - + + 2.4.0 + + 6.2 @@ -273,7 +275,7 @@ com.nimbusds nimbus-jose-jwt - 6.2 + ${nimbus-jose-jwt.version} org.apache.solr @@ -295,13 +297,18 @@ org.json json + + + com.jayway.jsonpath + json-path + com.jayway.jsonpath json-path - test ${json-path.version} + test com.jayway.jsonpath diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java index 52a113d787..507ea02c0c 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractControllerIntegrationTest.java @@ -22,6 +22,7 @@ import org.apache.commons.io.Charsets; import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.Application; import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.utils.DSpaceConfigurationInitializer; import org.dspace.app.rest.utils.DSpaceKernelInitializer; import org.junit.Assert; import org.junit.runner.RunWith; @@ -44,11 +45,18 @@ import org.springframework.test.web.servlet.setup.DefaultMockMvcBuilder; import org.springframework.web.context.WebApplicationContext; /** - * Abstract controller integration test class that will take care of setting up the - * Spring Boot environment to run the integration test + * Abstract integration test class that will take care of setting up the Spring Boot environment to run + * integration tests against @Controller classes (Spring Controllers). + *

+ * This Abstract class uses Spring Boot's default mock environment testing scheme, which relies on MockMvc to "mock" + * a webserver and call Spring Controllers directly. This avoids the cost of starting a webserver. + *

+ * If you need to test a Servlet (or something not a Spring Controller), you will NOT be able to use this class. + * Instead, please use the AbstractWebClientIntegrationTest in this same package. * * @author Tom Desair * @author Tim Donohue + * @see org.dspace.app.rest.test.AbstractWebClientIntegrationTest */ // Run tests with JUnit 4 and Spring TestContext Framework @RunWith(SpringRunner.class) @@ -56,8 +64,8 @@ import org.springframework.web.context.WebApplicationContext; // NOTE: By default, Spring caches and reuses ApplicationContext for each integration test (to speed up tests) // See: https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#integration-testing @SpringBootTest(classes = Application.class) -// Load DSpaceKernelInitializer in Spring ApplicationContext (to initialize DSpace Kernel) -@ContextConfiguration(initializers = DSpaceKernelInitializer.class) +// Load DSpace initializers in Spring ApplicationContext (to initialize DSpace Kernel & Configuration) +@ContextConfiguration(initializers = { DSpaceKernelInitializer.class, DSpaceConfigurationInitializer.class }) // Tell Spring to make ApplicationContext an instance of WebApplicationContext (for web-based tests) @WebAppConfiguration public class AbstractControllerIntegrationTest extends AbstractIntegrationTestWithDatabase { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java new file mode 100644 index 0000000000..29f81b4510 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java @@ -0,0 +1,93 @@ +/** + * 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.rest.test; + +import org.dspace.app.rest.Application; +import org.dspace.app.rest.utils.DSpaceConfigurationInitializer; +import org.dspace.app.rest.utils.DSpaceKernelInitializer; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.embedded.LocalServerPort; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Abstract web client integration test class that will initialize the Spring Boot test environment by starting up + * a full test webserver (on a random port). + *

+ * As running a test webserver is an expensive operation, this Abstract class is only necessary to perform + * Integration Tests on *Servlets*. If you are performing integration tests on a Spring Controller + * (@Controller annotation), you should use AbstractControllerIntegrationTest + *

+ * NOTE: The annotations on this class should be kept in sync with those on AbstractControllerIntegrationTest. + * The ONLY differences should be in the "webEnvironment" param passed to @SpringBootTest, and the removal + * of @WebAppConfiguration (which is only allowed in a mock environment) + * + * @author Tim Donohue + * @see org.dspace.app.rest.test.AbstractControllerIntegrationTest + */ +// Run tests with JUnit 4 and Spring TestContext Framework +@RunWith(SpringRunner.class) +// Specify main class to use to load Spring ApplicationContext +// ALSO tell Spring to start a web server on a random port +// NOTE: By default, Spring caches and reuses ApplicationContext for each integration test (to speed up tests) +// See: https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#integration-testing +@SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +// Load DSpace initializers in Spring ApplicationContext (to initialize DSpace Kernel & Configuration) +@ContextConfiguration(initializers = { DSpaceKernelInitializer.class, DSpaceConfigurationInitializer.class }) +public class AbstractWebClientIntegrationTest extends AbstractIntegrationTestWithDatabase { + // (Random) port chosen for test web server + @LocalServerPort + private int port; + + // RestTemplate class with access to test web server + @Autowired + private TestRestTemplate restTemplate; + + /** + * Get client TestRestTemplate for making HTTP requests to test webserver + * @return TestRestTemplate + */ + public TestRestTemplate getClient() { + return restTemplate; + } + + /** + * Return the full URL of a request at a specific path. + * (http://localhost:[port][path]) + * @param path Path (should start with a slash) + * @return full URL + */ + public String getURL(String path) { + return "http://localhost:" + port + path; + } + + /** + * Perform a GET request and return response as a String + * @param path path to perform GET against + * @return ResponseEntity with a String body + */ + public ResponseEntity getResponseAsString(String path) { + return getClient().getForEntity(getURL(path), String.class); + } + + /** + * Perform an authenticated (via Basic Auth) GET request and return response as a String + * @param path path to perform GET against + * @param username Username + * @param password Password + * @return ResponseEntity with a String body + */ + public ResponseEntity getResponseAsString(String path, String username, String password) { + return getClient().withBasicAuth(username, password).getForEntity(getURL(path), String.class); + } +} + diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java new file mode 100644 index 0000000000..81777148a8 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java @@ -0,0 +1,60 @@ +/** + * 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.sword; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; +import org.dspace.services.ConfigurationService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; + +/** + * Integration test to test the /sword endpoint which loads/embeds the SWORD webapp into the REST API. + * This is a AbstractWebClientIntegrationTest because testing the SWORD webapp requires + * running a web server (as the SWORD webapp makes use of Servlets, not Controllers). + * + * @author Tim Donohue + */ +// Ensure the SWORD SERVER IS ENABLED before any tests run. +// This annotation overrides default DSpace config settings loaded into Spring Context +@TestPropertySource(properties = {"sword-server.enabled = true"}) +public class Swordv1IT extends AbstractWebClientIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + + @Test + public void serviceDocumentUnauthorizedTest() throws Exception { + // Attempt to load the ServiceDocument without first authenticating + ResponseEntity response = getResponseAsString("/sword/servicedocument"); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + public void serviceDocumentTest() throws Exception { + // Before we can test the ServiceDocument, we must be sure the URL is configured properly + // If the configured URL doesn't match exactly, SWORD will respond with a 404, even if authentication succeeds + configurationService.setProperty("sword-server.servicedocument.url", getURL("/sword/servicedocument")); + + // Attempt to load the ServiceDocument as an Admin user. + ResponseEntity response = getResponseAsString("/sword/servicedocument", + admin.getEmail(), password); + // Expect a 200 response code, and an ATOM UTF-8 document + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + assertThat(response.getHeaders().getContentType().toString(), equalTo("application/atomsvc+xml;charset=UTF-8")); + } + +} + From 56f7cb11bc118257e1b907f13ab0d998dba1b857 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 31 Jan 2019 22:28:24 +0000 Subject: [PATCH 158/188] Remove maven-war-plugin from SWORD POM. It's not needed anymore --- dspace-sword/pom.xml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 5a07a60e4a..7c83e35552 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -25,28 +25,6 @@ ${basedir}/.. - - - - org.apache.maven.plugins - maven-war-plugin - - true - - WEB-INF/lib/*.jar - WEB-INF/lib/*.jar - - true - - - - prepare-package - - - - - - oracle-support From 6f51195e6cd1871badf970e2848800d82267506b Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 31 Jan 2019 22:28:52 +0000 Subject: [PATCH 159/188] Ensure SWORD integration tests only run if SWORDWebConfig is loaded --- dspace-spring-rest/pom.xml | 2 ++ .../test/AbstractWebClientIntegrationTest.java | 5 +++++ .../src/test/java/org/dspace/sword/Swordv1IT.java | 14 ++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index 611113d355..e06032ae3f 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -259,6 +259,8 @@ dspace-services + + org.dspace dspace-sword diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java index 29f81b4510..b4840161dc 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java @@ -15,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.context.ApplicationContext; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; @@ -52,6 +53,10 @@ public class AbstractWebClientIntegrationTest extends AbstractIntegrationTestWit @Autowired private TestRestTemplate restTemplate; + // Spring Application context + @Autowired + protected ApplicationContext applicationContext; + /** * Get client TestRestTemplate for making HTTP requests to test webserver * @return TestRestTemplate diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java index 81777148a8..066a25eb84 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java @@ -13,6 +13,8 @@ import static org.junit.Assert.assertThat; import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; import org.dspace.services.ConfigurationService; +import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -34,6 +36,18 @@ public class Swordv1IT extends AbstractWebClientIntegrationTest { @Autowired private ConfigurationService configurationService; + @Before + public void onlyRunIfConfigExists() { + // These integration tests REQUIRE that SWORDWebConfig is found/available (as this class deploys SWORD) + // If this class is not available, the below "Assume" will cause all tests to be SKIPPED + // NOTE: SWORDWebConfig is provided by the 'dspace-sword' module + try { + Class.forName("org.dspace.app.configuration.SWORDWebConfig"); + } catch (ClassNotFoundException ce) { + Assume.assumeNoException(ce); + } + } + @Test public void serviceDocumentUnauthorizedTest() throws Exception { // Attempt to load the ServiceDocument without first authenticating From 46a50aeded0d1cfc032f9a5b5e3afbff8c59faac Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 1 Feb 2019 18:46:19 +0000 Subject: [PATCH 160/188] Add basic validation tests for all SWORDv1 endpoints --- .../AbstractWebClientIntegrationTest.java | 20 +++++++ .../test/java/org/dspace/sword/Swordv1IT.java | 53 ++++++++++++++++--- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java index b4840161dc..26fa7f0ef7 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractWebClientIntegrationTest.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest.test; +import org.apache.commons.lang3.StringUtils; import org.dspace.app.rest.Application; import org.dspace.app.rest.utils.DSpaceConfigurationInitializer; import org.dspace.app.rest.utils.DSpaceKernelInitializer; @@ -16,6 +17,7 @@ import org.springframework.boot.context.embedded.LocalServerPort; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.context.ApplicationContext; +import org.springframework.http.HttpEntity; import org.springframework.http.ResponseEntity; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; @@ -94,5 +96,23 @@ public class AbstractWebClientIntegrationTest extends AbstractIntegrationTestWit public ResponseEntity getResponseAsString(String path, String username, String password) { return getClient().withBasicAuth(username, password).getForEntity(getURL(path), String.class); } + + /** + * Perform an authenticated (via Basic Auth) POST request and return response as a String. + * @param path path to perform GET against + * @param username Username (may be null to perform an unauthenticated POST) + * @param password Password + * @return ResponseEntity with a String body + */ + public ResponseEntity postResponseAsString(String path, String username, String password, + HttpEntity requestEntity) { + // If username is not empty, perform an authenticated POST. Else attempt without AuthN + if (StringUtils.isNotBlank(username)) { + return getClient().withBasicAuth(username, password).postForEntity(getURL(path), requestEntity, + String.class); + } else { + return getClient().postForEntity(getURL(path), requestEntity, String.class); + } + } } diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java index 066a25eb84..8e7b38a9af 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java @@ -8,6 +8,7 @@ package org.dspace.app.sword; +import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; @@ -15,6 +16,7 @@ import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; import org.dspace.services.ConfigurationService; import org.junit.Assume; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -36,6 +38,11 @@ public class Swordv1IT extends AbstractWebClientIntegrationTest { @Autowired private ConfigurationService configurationService; + // All SWORD paths that we test against + private final String SERVICE_DOC_PATH = "/sword/servicedocument"; + private final String DEPOSIT_PATH = "/sword/deposit"; + private final String MEDIA_LINK_PATH = "/sword/media-link"; + @Before public void onlyRunIfConfigExists() { // These integration tests REQUIRE that SWORDWebConfig is found/available (as this class deploys SWORD) @@ -46,29 +53,63 @@ public class Swordv1IT extends AbstractWebClientIntegrationTest { } catch (ClassNotFoundException ce) { Assume.assumeNoException(ce); } + + // Ensure SWORD URL configurations are set correctly (based on our integration test server's paths) + // SWORD validates requests against these configs, and throws a 404 if they don't match the request path + configurationService.setProperty("sword-server.servicedocument.url", getURL(SERVICE_DOC_PATH)); + configurationService.setProperty("sword-server.deposit.url", getURL(DEPOSIT_PATH)); + configurationService.setProperty("sword-server.media-link.url", getURL(MEDIA_LINK_PATH)); } @Test public void serviceDocumentUnauthorizedTest() throws Exception { // Attempt to load the ServiceDocument without first authenticating - ResponseEntity response = getResponseAsString("/sword/servicedocument"); + ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH); // Expect a 401 response code assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); } @Test public void serviceDocumentTest() throws Exception { - // Before we can test the ServiceDocument, we must be sure the URL is configured properly - // If the configured URL doesn't match exactly, SWORD will respond with a 404, even if authentication succeeds - configurationService.setProperty("sword-server.servicedocument.url", getURL("/sword/servicedocument")); - // Attempt to load the ServiceDocument as an Admin user. - ResponseEntity response = getResponseAsString("/sword/servicedocument", + ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH, admin.getEmail(), password); // Expect a 200 response code, and an ATOM UTF-8 document assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); assertThat(response.getHeaders().getContentType().toString(), equalTo("application/atomsvc+xml;charset=UTF-8")); + + // Check for SWORD version in response body + assertThat(response.getBody(), containsString("1.3")); } + @Test + public void depositUnauthorizedTest() throws Exception { + // Attempt to access /deposit endpoint without sending authentication information + ResponseEntity response = postResponseAsString(DEPOSIT_PATH, null, null, null); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void depositTest() throws Exception { + // TODO: Actually test a full deposit via SWORD. + // Currently, we are just ensuring the /deposit endpoint exists (see above) and isn't throwing a 404 + } + + @Test + public void mediaLinkUnauthorizedTest() throws Exception { + // Attempt to access /media-link endpoint without sending authentication information + ResponseEntity response = getResponseAsString(MEDIA_LINK_PATH); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void mediaLinkTest() throws Exception { + // TODO: Actually test a /media-link request. + // Currently, we are just ensuring the /media-link endpoint exists (see above) and isn't throwing a 404 + } } From ca5ac68e2d793d9c60a53eb11bde5ab174f7e496 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 1 Feb 2019 22:50:44 +0000 Subject: [PATCH 161/188] Embed SWORDv2 into Boot webapp. Add basic IT to prove it works. --- dspace-spring-rest/pom.xml | 5 +- .../java/org/dspace/sword2/Swordv2IT.java | 82 ++++++++++ dspace-sword/pom.xml | 6 +- .../app/configuration/SWORDWebConfig.java | 10 ++ dspace-swordv2/pom.xml | 60 +++---- .../app/configuration/SWORDv2WebConfig.java | 143 ++++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 154 ------------------ dspace/config/modules/swordv2-server.cfg | 38 +++++ dspace/modules/swordv2/pom.xml | 144 ---------------- .../swordv2/src/main/webapp/.gitignore | 0 dspace/pom.xml | 1 - pom.xml | 9 +- 12 files changed, 302 insertions(+), 350 deletions(-) create mode 100644 dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java create mode 100644 dspace-swordv2/src/main/java/org/dspace/app/configuration/SWORDv2WebConfig.java delete mode 100644 dspace-swordv2/src/main/webapp/WEB-INF/web.xml delete mode 100644 dspace/modules/swordv2/pom.xml delete mode 100644 dspace/modules/swordv2/src/main/webapp/.gitignore diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index e06032ae3f..d1ae820b42 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -28,7 +28,6 @@ @ org.dspace.app.rest.Application - 1.4.4.RELEASE 2.4.0 @@ -265,6 +264,10 @@ org.dspace dspace-sword + + org.dspace + dspace-swordv2 + org.apache.commons diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java b/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java new file mode 100644 index 0000000000..e9b11738d4 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java @@ -0,0 +1,82 @@ +/** + * 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.sword2; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; +import org.dspace.services.ConfigurationService; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; + +/** + * Integration test to test the /swordv2 endpoint which loads/embeds the SWORDv2 webapp into the REST API. + * This is a AbstractWebClientIntegrationTest because testing the SWORDv2 webapp requires + * running a web server (as the SWORDv2 webapp makes use of Servlets, not Controllers). + * + * @author Tim Donohue + */ +// Ensure the SWORDv2 SERVER IS ENABLED before any tests run. +// This annotation overrides default DSpace config settings loaded into Spring Context +@TestPropertySource(properties = {"swordv2-server.enabled = true"}) +public class Swordv2IT extends AbstractWebClientIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + + // All SWORD v2 paths that we test against + private final String SERVICE_DOC_PATH = "/swordv2/servicedocument"; + + @Before + public void onlyRunIfConfigExists() { + // These integration tests REQUIRE that SWORDv2WebConfig is found/available (as this class deploys SWORDv2) + // If this class is not available, the below "Assume" will cause all tests to be SKIPPED + // NOTE: SWORDv2WebConfig is provided by the 'dspace-swordv2' module + try { + Class.forName("org.dspace.app.configuration.SWORDv2WebConfig"); + } catch (ClassNotFoundException ce) { + Assume.assumeNoException(ce); + } + + // Ensure SWORDv2 URL configurations are set correctly (based on our integration test server's paths) + // SWORDv2 validates requests against these configs, and throws a 404 if they don't match the request path + configurationService.setProperty("swordv2-server.servicedocument.url", getURL(SERVICE_DOC_PATH)); + } + + @Test + public void serviceDocumentUnauthorizedTest() throws Exception { + // Attempt to load the ServiceDocument without first authenticating + ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + public void serviceDocumentTest() throws Exception { + // Attempt to load the ServiceDocument as an Admin user. + ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH, + admin.getEmail(), password); + // Expect a 200 response code, and an ATOM UTF-8 document + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + assertThat(response.getHeaders().getContentType().toString(), + equalTo("application/atomserv+xml;charset=UTF-8")); + + // Check for SWORD version in response body + assertThat(response.getBody(), + containsString("2.0")); + } +} + diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 7c83e35552..938e9dbb04 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -6,7 +6,7 @@ jar DSpace SWORD - DSpace SWORD Deposit Service Provider Web Application + DSpace SWORD Deposit Service Provider Extension + org.springframework.boot spring-boot-starter-web - 1.4.4.RELEASE + ${spring-boot.version} diff --git a/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java index 4d1578385b..37b6d651a8 100644 --- a/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java +++ b/dspace-sword/src/main/java/org/dspace/app/configuration/SWORDWebConfig.java @@ -40,6 +40,12 @@ public class SWORDWebConfig { @Value("${sword-server.authentication-method:Basic}") private String authenticationMethod; + /** + * Initialize all required Context Parameters (i.e. in web.xml), based on configurations above. + *

+ * This bean is only loaded when sword-server.enabled = true + * @return ServletContextInitializer which includes all required params + */ @Bean @ConditionalOnProperty("sword-server.enabled") public ServletContextInitializer swordv1ContextInitializer() { @@ -49,6 +55,10 @@ public class SWORDWebConfig { }; } + // Servlet Beans. All of the below bean definitions map servlets to respond to specific URL patterns + // These are the combined equivalent of and in web.xml + // All beans are only loaded when sword-server.enabled = true + @Bean @ConditionalOnProperty("sword-server.enabled") public ServletRegistrationBean swordv1ServiceDocumentBean() { diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 6ac1a15b5d..998ac3436b 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -3,9 +3,9 @@ 4.0.0 org.dspace dspace-swordv2 - war + jar DSpace SWORD v2 - DSpace SWORD v2 Deposit Service Provider Web Application + DSpace SWORD v2 Deposit Service Provider Extension - WEB-INF/lib/*.jar - WEB-INF/lib/*.jar - - true - - - - prepare-package - - - - - - - oracle-support @@ -84,6 +61,8 @@ javax.servlet-api provided + + org.swordapp sword2-server @@ -99,26 +78,30 @@ javax.servlet servlet-api - - log4j + + log4j log4j - - - org.slf4j - slf4j-log4j12 - + + + org.slf4j + slf4j-log4j12 + - - org.swordapp - sword2-server - 1.0 - war - + + org.dspace dspace-api + + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + org.apache.logging.log4j log4j-api @@ -135,7 +118,6 @@ org.apache.abdera abdera-client 1.1.3 - org.apache.ws.commons.axiom diff --git a/dspace-swordv2/src/main/java/org/dspace/app/configuration/SWORDv2WebConfig.java b/dspace-swordv2/src/main/java/org/dspace/app/configuration/SWORDv2WebConfig.java new file mode 100644 index 0000000000..ece5094a61 --- /dev/null +++ b/dspace-swordv2/src/main/java/org/dspace/app/configuration/SWORDv2WebConfig.java @@ -0,0 +1,143 @@ +/** + * 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.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.ServletContextInitializer; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * SWORDv2 webapp configuration. Replaces the old web.xml + *

+ * This @Configuration class is automatically discovered by Spring via a @ComponentScan. + *

+ * All SWORDv2 web configurations (beans) can be enabled or disabled by setting "swordv2-server.enabled" + * to true or false, respectively (in your DSpace configuration). Default is "false". + *

+ * All @Value annotated configurations below can also be overridden in your DSpace configuration. + * + * @author Tim Donohue + */ +@Configuration +public class SWORDv2WebConfig { + // Path where SWORDv2 should be deployed (when enabled). Defaults to "swordv2" + @Value("${swordv2-server.path:swordv2}") + private String swordv2Path; + + // ServiceDocumentManager server implementation class name (default: org.dspace.sword2.ServiceDocumentManagerDSpace) + @Value("${swordv2-server.service-document-impl:org.dspace.sword2.ServiceDocumentManagerDSpace}") + private String serviceDocImpl; + + // CollectionListManager server implementation class name (default: org.dspace.sword2.CollectionListManagerDSpace) + @Value("${swordv2-server.collection-list-impl:org.dspace.sword2.CollectionListManagerDSpace}") + private String collectionListImpl; + + // CollectionDepositManager server implementation class name + // (default: org.dspace.sword2.CollectionDepositManagerDSpace) + @Value("${swordv2-server.collection-deposit-impl:org.dspace.sword2.CollectionDepositManagerDSpace}") + private String collectionDepositImpl; + + // MediaResourceManager server implementation class name (default: org.dspace.sword2.MediaResourceManagerDSpace) + @Value("${swordv2-server.media-resource-impl:org.dspace.sword2.MediaResourceManagerDSpace}") + private String mediaResourceImpl; + + // ContainerManager server implementation class name (default: org.dspace.sword2.ContainerManagerDSpace) + @Value("${swordv2-server.container-impl:org.dspace.sword2.ContainerManagerDSpace}") + private String containerImpl; + + // StatementManager server implementation class name (default: org.dspace.sword2.StatementManagerDSpace) + @Value("${swordv2-server.statement-impl:org.dspace.sword2.StatementManagerDSpace}") + private String statementImpl; + + // SwordConfiguration server implementation class name (default: org.dspace.sword2.SwordConfigurationDSpace) + @Value("${swordv2-server.config-impl:org.dspace.sword2.SwordConfigurationDSpace}") + private String configImpl; + + // Authentication Method. Defaults to "Basic" + @Value("${swordv2-server.auth-type:Basic}") + private String authenticationMethod; + + /** + * Initialize all required Context Parameters (i.e. in web.xml), based on configurations above. + *

+ * This bean is only loaded when swordv2-server.enabled = true + * @return ServletContextInitializer which includes all required params + */ + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletContextInitializer swordv2ContextInitializer() { + return servletContext -> { + servletContext.setInitParameter("service-document-impl", serviceDocImpl); + servletContext.setInitParameter("collection-list-impl", collectionListImpl); + servletContext.setInitParameter("collection-deposit-impl", collectionDepositImpl); + servletContext.setInitParameter("media-resource-impl", mediaResourceImpl); + servletContext.setInitParameter("container-impl", containerImpl); + servletContext.setInitParameter("statement-impl", statementImpl); + servletContext.setInitParameter("config-impl", configImpl); + servletContext.setInitParameter("authentication-method", authenticationMethod); + }; + } + + // Servlet Beans. All of the below bean definitions map servlets to respond to specific URL patterns + // These are the combined equivalent of and in web.xml + // All beans are only loaded when swordv2-server.enabled = true + + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletRegistrationBean swordv2ServiceDocumentBean() { + ServletRegistrationBean bean = + new ServletRegistrationBean(new org.swordapp.server.servlets.ServiceDocumentServletDefault(), + "/" + swordv2Path + "/servicedocument/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletRegistrationBean swordv2CollectionBean() { + ServletRegistrationBean bean = + new ServletRegistrationBean( new org.swordapp.server.servlets.CollectionServletDefault(), + "/" + swordv2Path + "/collection/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletRegistrationBean swordv2MediaResourceBean() { + ServletRegistrationBean bean = + new ServletRegistrationBean( new org.swordapp.server.servlets.MediaResourceServletDefault(), + "/" + swordv2Path + "/edit-media/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletRegistrationBean swordv2ContainerBean() { + ServletRegistrationBean bean = + new ServletRegistrationBean( new org.swordapp.server.servlets.ContainerServletDefault(), + "/" + swordv2Path + "/edit/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + @ConditionalOnProperty("swordv2-server.enabled") + public ServletRegistrationBean swordv2StatementBean() { + ServletRegistrationBean bean = + new ServletRegistrationBean( new org.swordapp.server.servlets.StatementServletDefault(), + "/" + swordv2Path + "/statement/*"); + bean.setLoadOnStartup(1); + return bean; + } +} + diff --git a/dspace-swordv2/src/main/webapp/WEB-INF/web.xml b/dspace-swordv2/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index f7794795dd..0000000000 --- a/dspace-swordv2/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,154 +0,0 @@ - - - - - DSpace SWORD 2.0 Server - - - - The location of the DSpace home directory - dspace.dir - ${dspace.dir} - - - - - - The ServiceDocumentManager server implementation class name - service-document-impl - org.dspace.sword2.ServiceDocumentManagerDSpace - - - - log4jConfiguration - ${dspace.dir}/config/log4j2.xml - - The location of the Log4J configuration - - - - - - The CollectionListManager server implementation class name - collection-list-impl - org.dspace.sword2.CollectionListManagerDSpace - - - - The CollectionDepositManager server implementation class name - collection-deposit-impl - org.dspace.sword2.CollectionDepositManagerDSpace - - - - The MediaResourceManager server implementation class name - media-resource-impl - org.dspace.sword2.MediaResourceManagerDSpace - - - - The ContainerManager server implementation class name - container-impl - org.dspace.sword2.ContainerManagerDSpace - - - - The StatementManager server implementation class name - statement-impl - org.dspace.sword2.StatementManagerDSpace - - - - - The SwordConfiguration server implementation class name - config-impl - org.dspace.sword2.SwordConfigurationDSpace - - - - The type of authentication used : [Basic|None] - authentication-method - Basic - - - - - - org.dspace.app.util.DSpaceContextListener - - - - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - - - - - - servicedocument - org.swordapp.server.servlets.ServiceDocumentServletDefault - - - - collection - org.swordapp.server.servlets.CollectionServletDefault - - - - mediaresource - org.swordapp.server.servlets.MediaResourceServletDefault - - - - container - org.swordapp.server.servlets.ContainerServletDefault - - - - statement - org.swordapp.server.servlets.StatementServletDefault - - - - - - servicedocument - /servicedocument/* - - - - collection - /collection/* - - - - mediaresource - /edit-media/* - - - - container - /edit/* - - - - statement - /statement/* - - - diff --git a/dspace/config/modules/swordv2-server.cfg b/dspace/config/modules/swordv2-server.cfg index 6e6cfd1c39..200d100f8b 100644 --- a/dspace/config/modules/swordv2-server.cfg +++ b/dspace/config/modules/swordv2-server.cfg @@ -6,6 +6,18 @@ # SWORD 2.0 protocol) # #---------------------------------------------------------------# +# Whether or not to enable the SWORD v2 module +# When "true", the SWORD v2 module is accessible on ${swordv2-server.path} +# When "false" or commented out, SWORD v2 is disabled/inaccessible. +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#swordv2-server.enabled = true + + # Path where SWORD v2 module is available (in the Spring REST webapp) +# Defaults to "swordv2", which means the SWORD v2 module would be available +# at ${dspace.restURL}/swordv2/ +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#swordv2-server.path = swordv2 + # the base url of the sword 2.0 system # # the default if {dspace.url}/swordv2 @@ -194,6 +206,32 @@ swordv2-server.generator.version = 2.0 # Other valid values: 'None' swordv2-server.auth-type = Basic +# SWORD v2 server implementation classes +# These are the default implementation classes to use for SWORD functions. +# Uncomment if you wish to change the implementation class. +# (Requires reboot of servlet container, e.g. Tomcat, to reload these settings) +# +# ServiceDocumentManager server implementation +#swordv2-server.service-document-impl = org.dspace.sword2.ServiceDocumentManagerDSpace +# +# CollectionListManager server implementation class +#swordv2-server.collection-list-impl = org.dspace.sword2.CollectionListManagerDSpace +# +# CollectionDepositManager server implementation class +#swordv2-server.collection-deposit-impl = org.dspace.sword2.CollectionDepositManagerDSpace +# +# MediaResourceManager server implementation class +#swordv2-server.media-resource-impl = org.dspace.sword2.MediaResourceManagerDSpace +# +# ContainerManager server implementation class name +#swordv2-server.container-impl = org.dspace.sword2.ContainerManagerDSpace +# +# StatementManager server implementation class +#swordv2-server.statement-impl = org.dspace.sword2.StatementManagerDSpace +# +# SwordConfiguration server implementation class +#swordv2-server.config-impl = org.dspace.sword2.SwordConfigurationDSpace + # The location where uploaded files and packages are # stored while being processed swordv2-server.upload.tempdir = ${upload.temp.dir} diff --git a/dspace/modules/swordv2/pom.xml b/dspace/modules/swordv2/pom.xml deleted file mode 100644 index 11f0b684b5..0000000000 --- a/dspace/modules/swordv2/pom.xml +++ /dev/null @@ -1,144 +0,0 @@ - - 4.0.0 - org.dspace.modules - swordv2 - war - DSpace SWORD v2 :: Local Customizations - - This project allows you to overlay your own local SWORD v2 customizations - on top of the default SWORD v2 web application provided with DSpace. - - - - - org.dspace - modules - 7.0-SNAPSHOT - .. - - - - - ${basedir}/../../.. - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - prepare-package - - unpack-dependencies - - - org.dspace.modules - additions - - ${project.build.directory}/additions - META-INF/** - - - - - - org.apache.maven.plugins - maven-war-plugin - - false - - true - - - - ${project.build.directory}/additions - WEB-INF/classes - - - - - - prepare-package - - - - - - - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - - postgres-support - - - !db.name - - - - - org.postgresql - postgresql - - - - - - - - - org.dspace.modules - additions - - - - - org.dspace - dspace-swordv2 - war - - - - - org.dspace - dspace-swordv2 - jar - classes - - - - javax.servlet - javax.servlet-api - provided - - - - - diff --git a/dspace/modules/swordv2/src/main/webapp/.gitignore b/dspace/modules/swordv2/src/main/webapp/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/dspace/pom.xml b/dspace/pom.xml index 8b4427a508..da6059b897 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -232,7 +232,6 @@ org.dspace dspace-swordv2 - classes compile diff --git a/pom.xml b/pom.xml index c46616e5da..528b196e2b 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ https://issues.apache.org/jira/browse/SOLR-12858 --> 7.3.1 4.3.6.RELEASE + 1.4.4.RELEASE ${basedir} @@ -946,14 +947,6 @@ org.dspace dspace-swordv2 7.0-SNAPSHOT - jar - classes - - - org.dspace - dspace-swordv2 - 7.0-SNAPSHOT - war org.dspace From 06f8a2a6e28fc0161ef2d5aa8bc2141a971e5c63 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 8 Feb 2019 21:59:03 +0000 Subject: [PATCH 162/188] More ITs for SWORDv2. Ensure all SWORDv2 endpoints have a sanity test. --- .../java/org/dspace/sword2/Swordv2IT.java | 71 ++++++++++++++++++- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java b/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java index e9b11738d4..cc672df9fc 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java @@ -16,6 +16,7 @@ import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; import org.dspace.services.ConfigurationService; import org.junit.Assume; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -39,6 +40,10 @@ public class Swordv2IT extends AbstractWebClientIntegrationTest { // All SWORD v2 paths that we test against private final String SERVICE_DOC_PATH = "/swordv2/servicedocument"; + private final String COLLECTION_PATH = "/swordv2/collection"; + private final String MEDIA_RESOURCE_PATH = "/swordv2/edit-media"; + private final String CONTAINER_PATH = "/swordv2/edit"; + private final String STATEMENT_PATH = "/swordv2/statement"; @Before public void onlyRunIfConfigExists() { @@ -58,7 +63,7 @@ public class Swordv2IT extends AbstractWebClientIntegrationTest { @Test public void serviceDocumentUnauthorizedTest() throws Exception { - // Attempt to load the ServiceDocument without first authenticating + // Attempt to GET the ServiceDocument without first authenticating ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH); // Expect a 401 response code assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); @@ -66,7 +71,7 @@ public class Swordv2IT extends AbstractWebClientIntegrationTest { @Test public void serviceDocumentTest() throws Exception { - // Attempt to load the ServiceDocument as an Admin user. + // Attempt to GET the ServiceDocument as an Admin user. ResponseEntity response = getResponseAsString(SERVICE_DOC_PATH, admin.getEmail(), password); // Expect a 200 response code, and an ATOM UTF-8 document @@ -74,9 +79,69 @@ public class Swordv2IT extends AbstractWebClientIntegrationTest { assertThat(response.getHeaders().getContentType().toString(), equalTo("application/atomserv+xml;charset=UTF-8")); - // Check for SWORD version in response body + // Check for correct SWORD version in response body assertThat(response.getBody(), containsString("2.0")); } + + @Test + public void collectionUnauthorizedTest() throws Exception { + // Attempt to POST to /collection endpoint without sending authentication information + ResponseEntity response = postResponseAsString(COLLECTION_PATH, null, null, null); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void collectionTest() throws Exception { + // TODO: Actually test collection endpoint via SWORDv2. + // Currently, we are just ensuring the /collection endpoint exists (see above) and isn't throwing a 404 + } + + @Test + public void mediaResourceUnauthorizedTest() throws Exception { + // Attempt to POST to /mediaresource endpoint without sending authentication information + ResponseEntity response = postResponseAsString(MEDIA_RESOURCE_PATH, null, null, null); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void mediaResourceTest() throws Exception { + // TODO: Actually test this endpoint via SWORDv2. + // Currently, we are just ensuring the /mediaresource endpoint exists (see above) and isn't throwing a 404 + } + + @Test + public void containerUnauthorizedTest() throws Exception { + // Attempt to POST to /container endpoint without sending authentication information + ResponseEntity response = postResponseAsString(CONTAINER_PATH, null, null, null); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void containerTest() throws Exception { + // TODO: Actually test this endpoint via SWORDv2. + // Currently, we are just ensuring the /container endpoint exists (see above) and isn't throwing a 404 + } + + @Test + public void statementUnauthorizedTest() throws Exception { + // Attempt to GET /statement endpoint without sending authentication information + ResponseEntity response = getResponseAsString(STATEMENT_PATH); + // Expect a 401 response code + assertThat(response.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED)); + } + + @Test + @Ignore + public void statementTest() throws Exception { + // TODO: Actually test this endpoint via SWORDv2. + // Currently, we are just ensuring the /statement endpoint exists (see above) and isn't throwing a 404 + } } From 27512ad382a8823cc011daa93d57d667b3a07213 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 13 Feb 2019 21:49:07 +0000 Subject: [PATCH 163/188] Correct location of SWORD ITs --- .../src/test/java/org/dspace/{ => app}/sword/Swordv1IT.java | 0 .../src/test/java/org/dspace/{ => app}/sword2/Swordv2IT.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename dspace-spring-rest/src/test/java/org/dspace/{ => app}/sword/Swordv1IT.java (100%) rename dspace-spring-rest/src/test/java/org/dspace/{ => app}/sword2/Swordv2IT.java (100%) diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java b/dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java similarity index 100% rename from dspace-spring-rest/src/test/java/org/dspace/sword/Swordv1IT.java rename to dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java diff --git a/dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java b/dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java similarity index 100% rename from dspace-spring-rest/src/test/java/org/dspace/sword2/Swordv2IT.java rename to dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java From cb86effb382e24de4076bb1ccb74ade0c60e450d Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 13 Feb 2019 22:04:16 +0000 Subject: [PATCH 164/188] Correct comments to be more accurate --- .../src/test/java/org/dspace/app/sword/Swordv1IT.java | 8 +++++--- .../src/test/java/org/dspace/app/sword2/Swordv2IT.java | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java b/dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java index 8e7b38a9af..24244e1773 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/sword/Swordv1IT.java @@ -24,9 +24,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.TestPropertySource; /** - * Integration test to test the /sword endpoint which loads/embeds the SWORD webapp into the REST API. - * This is a AbstractWebClientIntegrationTest because testing the SWORD webapp requires - * running a web server (as the SWORD webapp makes use of Servlets, not Controllers). + * Integration test to verify that the /sword endpoint is responding as a valid SWORD endpoint. + * This tests that our dspace-sword module is running at this endpoint. + *

+ * This is a AbstractWebClientIntegrationTest because testing dspace-sword requires + * running a web server (as dspace-sword makes use of Servlets, not Controllers). * * @author Tim Donohue */ diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java b/dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java index cc672df9fc..95ec762514 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/sword2/Swordv2IT.java @@ -24,9 +24,11 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.TestPropertySource; /** - * Integration test to test the /swordv2 endpoint which loads/embeds the SWORDv2 webapp into the REST API. - * This is a AbstractWebClientIntegrationTest because testing the SWORDv2 webapp requires - * running a web server (as the SWORDv2 webapp makes use of Servlets, not Controllers). + * Integration test to verify the /swordv2 endpoint is responding as a valid SWORDv2 endpoint. + * This tests that our dspace-swordv2 module is running at this endpoint. + *

+ * This is a AbstractWebClientIntegrationTest because testing dspace-swordv2 requires + * running a web server (as dspace-swordv2 makes use of Servlets, not Controllers). * * @author Tim Donohue */ From 89400609aa48b11c3bc23025a4664afb2ab533b9 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 15 Feb 2019 22:21:44 +0000 Subject: [PATCH 165/188] Embed OAI-PMH into Boot webapp. Add basic ITs to prove it works. --- dspace-oai/pom.xml | 91 +++------- .../configuration/OAIWebConfig.java} | 26 ++- .../controller/DSpaceOAIDataProvider.java | 5 + .../WEB-INF/spring/applicationContext.xml | 60 ------- dspace-oai/src/main/webapp/WEB-INF/web.xml | 83 --------- dspace-spring-rest/pom.xml | 4 + .../java/org/dspace/app/oai/OAIpmhIT.java | 86 +++++++++ dspace/modules/oai/pom.xml | 169 ------------------ dspace/modules/oai/src/main/webapp/.gitignore | 0 dspace/pom.xml | 3 - pom.xml | 8 - 11 files changed, 134 insertions(+), 401 deletions(-) rename dspace-oai/src/main/java/org/dspace/{xoai/app/DSpaceWebappConfiguration.java => app/configuration/OAIWebConfig.java} (77%) delete mode 100644 dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml delete mode 100644 dspace-oai/src/main/webapp/WEB-INF/web.xml create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java delete mode 100644 dspace/modules/oai/pom.xml delete mode 100644 dspace/modules/oai/src/main/webapp/.gitignore diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 885c045227..716f222461 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -2,9 +2,9 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 dspace-oai - war + jar DSpace OAI-PMH - DSpace OAI-PMH Web Application and API + DSpace OAI-PMH Extension dspace-parent @@ -22,28 +22,12 @@ - - org.apache.maven.plugins - maven-war-plugin - - true - - WEB-INF/lib/*.jar - WEB-INF/lib/*.jar - - true - - - - prepare-package - - - com.mycila license-maven-plugin + src/main/webapp/** **/*.xsl @@ -107,42 +91,27 @@ org.apache.commons commons-lang3 - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - + + log4j + log4j + + + org.slf4j + slf4j-log4j12 + + + + org.codehaus.woodstox + wstx-asl + - + - javax.inject - javax.inject - 1 - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-beans - ${spring.version} - - - org.springframework - spring-context - ${spring.version} - - - org.springframework - spring-web - ${spring.version} + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} @@ -294,24 +263,4 @@ test - - - - DSpace @ Lyncode - dspace@lyncode.com - Lyncode - http://www.lyncode.com - - - helix84 - Ivan Másar - helix84@centrum.sk - - - Ariel J. Lira - arieljlira@gmail.com - SeDiCI - http://sedici.unlp.edu.ar - - diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java b/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java similarity index 77% rename from dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java rename to dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java index 8ad41abb65..c4b4bc7ace 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/app/DSpaceWebappConfiguration.java +++ b/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java @@ -5,11 +5,11 @@ * * http://www.dspace.org/license/ */ -package org.dspace.xoai.app; - +package org.dspace.app.configuration; import static java.lang.Integer.MAX_VALUE; import com.lyncode.jtwig.mvc.JtwigViewResolver; +import org.dspace.xoai.app.BasicConfiguration; import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; import org.dspace.xoai.services.impl.xoai.DSpaceItemRepositoryResolver; import org.springframework.context.annotation.Bean; @@ -22,13 +22,25 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -@Import( { - BasicConfiguration.class -}) +/** + * OAI-PMH webapp configuration. Replaces the old web.xml + *

+ * This @Configuration class is automatically discovered by Spring Boot via a @ComponentScan + * on the org.dspace.app.configuration package. + *

+ * + * + * @author Tim Donohue + */ @Configuration +// Import WebMVC configuration (and allow us to extend WebMvcConfigurerAdapter) @EnableWebMvc +// Import additional configuration and beans from BasicConfiguration +@Import(BasicConfiguration.class) +// Scan for controllers in this package @ComponentScan("org.dspace.xoai.controller") -public class DSpaceWebappConfiguration extends WebMvcConfigurerAdapter { +public class OAIWebConfig extends WebMvcConfigurerAdapter { + private static final String TWIG_HTML_EXTENSION = ".twig.html"; private static final String VIEWS_LOCATION = "/WEB-INF/views/"; @@ -58,5 +70,5 @@ public class DSpaceWebappConfiguration extends WebMvcConfigurerAdapter { public ItemRepositoryResolver xoaiItemRepositoryResolver() { return new DSpaceItemRepositoryResolver(); } - } + diff --git a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java index 96e82d8eae..6f33331a1d 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java @@ -40,6 +40,7 @@ import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; import org.dspace.xoai.services.api.xoai.SetRepositoryResolver; import org.dspace.xoai.services.impl.xoai.DSpaceResumptionTokenFormatter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; @@ -49,6 +50,10 @@ import org.springframework.web.bind.annotation.RequestMapping; * @author Lyncode Development Team (dspace at lyncode dot com) */ @Controller +// Use the configured "oai.path" for all requests, or "/oai" by default +@RequestMapping("/${oai.path:oai}") +// Only enable this controller if "oai.enabled=true" +@ConditionalOnProperty("oai.enabled") public class DSpaceOAIDataProvider { private static final Logger log = getLogger(DSpaceOAIDataProvider.class); diff --git a/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml b/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml deleted file mode 100644 index 0b6f2cde61..0000000000 --- a/dspace-oai/src/main/webapp/WEB-INF/spring/applicationContext.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/dspace-oai/src/main/webapp/WEB-INF/web.xml b/dspace-oai/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index d731a0c659..0000000000 --- a/dspace-oai/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - XOAI Data Provider - - - The location of the DSpace home directory - dspace.dir - ${dspace.dir} - - - - log4jConfiguration - ${dspace.dir}/config/log4j2.xml - The location of the Log4J configuration - - - - - - contextConfigLocation - /WEB-INF/spring/*.xml - - - - - org.dspace.app.util.DSpaceContextListener - - - - - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - - - - - org.dspace.app.util.DSpaceWebappListener - - - - - org.springframework.web.context.ContextLoaderListener - - - - oai - org.springframework.web.servlet.DispatcherServlet - - - contextClass - - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - - - - contextConfigLocation - org.dspace.xoai.app.DSpaceWebappConfiguration - - - - - - oai - /* - - - diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index d1ae820b42..581c86062e 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -260,6 +260,10 @@ + + org.dspace + dspace-oai + org.dspace dspace-sword diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java new file mode 100644 index 0000000000..4c343bf518 --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java @@ -0,0 +1,86 @@ +/** + * 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.oai; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath; + +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.services.ConfigurationService; +import org.junit.Assume; +import org.junit.Before; +//import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.TestPropertySource; + +/** + * Integration test to verify the /oai endpoint is responding as a valid OAI-PMH endpoint. + * This tests that our dspace-oai module is running at this endpoint. + *

+ * This is an AbstractControllerIntegrationTest because dspace-oai makes use of Controllers. + * + * @author Tim Donohue + */ +// Ensure the OAI SERVER IS ENABLED before any tests run. +// This annotation overrides default DSpace config settings loaded into Spring Context +@TestPropertySource(properties = {"oai.enabled = true"}) +public class OAIpmhIT extends AbstractControllerIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + + // All OAI-PMH paths that we test against + private final String ROOT_PATH = "/oai"; + private final String ROOT_REQUEST = "/oai/request"; + + @Before + public void onlyRunIfConfigExists() { + // These integration tests REQUIRE that OAIWebConfig is found/available (as this class deploys OAI) + // If this class is not available, the below "Assume" will cause all tests to be SKIPPED + // NOTE: OAIWebConfig is provided by the 'dspace-oai' module + try { + Class.forName("org.dspace.app.configuration.OAIWebConfig"); + } catch (ClassNotFoundException ce) { + Assume.assumeNoException(ce); + } + } + + @Test + public void oaiRootTest() throws Exception { + // Attempt to call the root endpoint + getClient().perform(get(ROOT_PATH)) + // Expect a 400 response code (OAI requires a context) + .andExpect(status().isOk()) + ; + } + + + @Test + public void oaiRootIdentifyTest() throws Exception { + // Attempt to make an Identify request to root context + getClient().perform(get(ROOT_REQUEST).param("verb", "Identify")) + // Expect a 200 response code + .andExpect(status().isOk()) + // Expect the content type to be "text/xml" + .andExpect(content().contentType("text/xml")) + // Expect oai + .andExpect(xpath("OAI-PMH/Identify/description/oai-identifier/scheme").string("oai")) + // Expect protocol version 2.0 + .andExpect(xpath("OAI-PMH/Identify/protocolVersion").string("2.0")) + // Expect repositoryName to be the same as "dspace.name" config + .andExpect(xpath("OAI-PMH/Identify/repositoryName") + .string(configurationService.getProperty("dspace.name"))) + ; + } + +} + diff --git a/dspace/modules/oai/pom.xml b/dspace/modules/oai/pom.xml deleted file mode 100644 index e36adfafcc..0000000000 --- a/dspace/modules/oai/pom.xml +++ /dev/null @@ -1,169 +0,0 @@ - - 4.0.0 - org.dspace.modules - oai - war - DSpace OAI-PMH :: Local Customizations - - This project allows you to overlay your own local OAI customizations - on top of the default OAI-PMH web application provided with DSpace. - - - - modules - org.dspace - 7.0-SNAPSHOT - .. - - - - - ${basedir}/../../.. - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - prepare-package - - unpack-dependencies - - - org.dspace.modules - additions - - ${project.build.directory}/additions - META-INF/** - - - - - - org.apache.maven.plugins - maven-war-plugin - - false - - true - - - - ${project.build.directory}/additions - WEB-INF/classes - - - - - - prepare-package - - - - - - - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - - - - - org.dspace.modules - additions - - - com.lyncode - builder-commons - - - - - org.dspace - dspace-oai - war - - - org.dspace - dspace-oai - jar - classes - - - com.lyncode - builder-commons - - - com.google.guava - guava - - - - - javax.servlet - javax.servlet-api - provided - - - - - com.lyncode - builder-commons - 1.0.2 - - - com.google.guava - guava - - - - - - - - org.hamcrest - hamcrest-all - compile - - - - - - lyncode - dspace@lyncode.com - DSpace @ Lyncode - http://www.lyncode.com - - - diff --git a/dspace/modules/oai/src/main/webapp/.gitignore b/dspace/modules/oai/src/main/webapp/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/dspace/pom.xml b/dspace/pom.xml index da6059b897..0c6ea85f78 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -198,7 +198,6 @@ org.dspace dspace-oai - classes compile @@ -288,8 +287,6 @@ org.dspace dspace-oai - jar - classes com.lyncode diff --git a/pom.xml b/pom.xml index 528b196e2b..4bf4365de5 100644 --- a/pom.xml +++ b/pom.xml @@ -952,14 +952,6 @@ org.dspace dspace-oai 7.0-SNAPSHOT - jar - classes - - - org.dspace - dspace-oai - 7.0-SNAPSHOT - war org.dspace From 7c83a58a204228587d1ba162d32c34a27a3cc7a8 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 15 Feb 2019 22:22:31 +0000 Subject: [PATCH 166/188] Minor bug fix to OAI-PMH found via ITs in previous commit --- .../services/impl/DSpaceEarliestDateResolver.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java index de8dc0d4ad..ba51c62d1b 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/DSpaceEarliestDateResolver.java @@ -10,6 +10,8 @@ package org.dspace.xoai.services.impl; import java.sql.SQLException; import java.util.Date; +import javax.persistence.NoResultException; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.dspace.content.MetadataValue; @@ -30,11 +32,16 @@ public class DSpaceEarliestDateResolver implements EarliestDateResolver { @Override public Date getEarliestDate(Context context) throws InvalidMetadataFieldException, SQLException { - String query = "SELECT MIN(text_value) as value FROM metadatavalue WHERE metadata_field_id = ?"; - MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService(); - MetadataValue minimum = metadataValueService.getMinimum(context, - fieldResolver.getFieldID(context, "dc.date.available")); + MetadataValue minimum = null; + try { + minimum = metadataValueService.getMinimum(context, + fieldResolver.getFieldID(context, "dc.date.available")); + } catch (NoResultException e) { + // This error only occurs if no metadataFields of this type exist (i.e. no minimum exists) + // It can be safely ignored in this scenario, as it implies the DSpace is empty. + } + if (null != minimum) { String str = minimum.getValue(); try { From f782a1ca3e45ce9fc5319ef9e36e7bfa878ab044 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 19 Feb 2019 17:19:47 +0000 Subject: [PATCH 167/188] OAI fixes: Update JTwig for compatibility with Spring Boot. Ensure static files are loaded properly --- dspace-oai/pom.xml | 38 +++++++--------- .../app/configuration/OAIWebConfig.java | 41 +++++++++--------- .../controller/DSpaceOAIDataProvider.java | 2 +- .../static/css/bootstrap-theme.css | 0 .../static/css/bootstrap-theme.min.css | 0 .../static/css/bootstrap.css | 0 .../static/css/bootstrap.min.css | 0 .../static/css/style.css | 0 .../fonts/glyphicons-halflings-regular.eot | Bin .../fonts/glyphicons-halflings-regular.svg | 0 .../fonts/glyphicons-halflings-regular.ttf | Bin .../fonts/glyphicons-halflings-regular.woff | Bin .../static/img/lyncode.png | Bin .../static/js/bootstrap.js | 0 .../static/js/bootstrap.min.js | 0 .../{webapp => resources}/static/js/jquery.js | 0 .../{webapp => resources}/static/lyncode.png | Bin .../{webapp => resources}/static/style.xsl | 0 .../templates}/index.twig.html | 30 ++++++++----- .../java/org/dspace/app/oai/OAIpmhIT.java | 2 +- 20 files changed, 56 insertions(+), 57 deletions(-) rename dspace-oai/src/main/{webapp => resources}/static/css/bootstrap-theme.css (100%) rename dspace-oai/src/main/{webapp => resources}/static/css/bootstrap-theme.min.css (100%) rename dspace-oai/src/main/{webapp => resources}/static/css/bootstrap.css (100%) rename dspace-oai/src/main/{webapp => resources}/static/css/bootstrap.min.css (100%) rename dspace-oai/src/main/{webapp => resources}/static/css/style.css (100%) rename dspace-oai/src/main/{webapp => resources}/static/fonts/glyphicons-halflings-regular.eot (100%) rename dspace-oai/src/main/{webapp => resources}/static/fonts/glyphicons-halflings-regular.svg (100%) rename dspace-oai/src/main/{webapp => resources}/static/fonts/glyphicons-halflings-regular.ttf (100%) rename dspace-oai/src/main/{webapp => resources}/static/fonts/glyphicons-halflings-regular.woff (100%) rename dspace-oai/src/main/{webapp => resources}/static/img/lyncode.png (100%) rename dspace-oai/src/main/{webapp => resources}/static/js/bootstrap.js (100%) rename dspace-oai/src/main/{webapp => resources}/static/js/bootstrap.min.js (100%) rename dspace-oai/src/main/{webapp => resources}/static/js/jquery.js (100%) rename dspace-oai/src/main/{webapp => resources}/static/lyncode.png (100%) rename dspace-oai/src/main/{webapp => resources}/static/style.xsl (100%) rename dspace-oai/src/main/{webapp/WEB-INF/views => resources/templates}/index.twig.html (74%) diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 716f222461..fd813b2e9c 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -17,7 +17,8 @@ ${basedir}/.. 3.2.10 - 2.0.1 + + 5.86.1.RELEASE @@ -28,7 +29,7 @@ - src/main/webapp/** + src/main/resources/** **/*.xsl @@ -116,34 +117,25 @@ - com.lyncode - jtwig-spring + org.jtwig + jtwig-spring-boot-starter ${jtwig.version} + - com.google.guava - guava + org.springframework.boot + spring-boot-starter-web + - org.javassist - javassist + org.ow2.asm + asm + - org.apache.commons - commons-lang3 + org.springframework.boot + spring-boot-configuration-processor - - javax.servlet - servlet-api - - - log4j - log4j - - - org.slf4j - slf4j-log4j12 - @@ -253,7 +245,7 @@ org.parboiled parboiled-core - 1.1.6 + 1.1.7 test diff --git a/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java b/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java index c4b4bc7ace..806ecf9d07 100644 --- a/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java +++ b/dspace-oai/src/main/java/org/dspace/app/configuration/OAIWebConfig.java @@ -8,17 +8,16 @@ package org.dspace.app.configuration; import static java.lang.Integer.MAX_VALUE; -import com.lyncode.jtwig.mvc.JtwigViewResolver; import org.dspace.xoai.app.BasicConfiguration; import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; import org.dspace.xoai.services.impl.xoai.DSpaceItemRepositoryResolver; +import org.jtwig.spring.JtwigViewResolver; +import org.jtwig.spring.boot.config.JtwigViewResolverConfigurer; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @@ -33,37 +32,39 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter * @author Tim Donohue */ @Configuration -// Import WebMVC configuration (and allow us to extend WebMvcConfigurerAdapter) -@EnableWebMvc // Import additional configuration and beans from BasicConfiguration @Import(BasicConfiguration.class) // Scan for controllers in this package @ComponentScan("org.dspace.xoai.controller") -public class OAIWebConfig extends WebMvcConfigurerAdapter { +public class OAIWebConfig extends WebMvcConfigurerAdapter implements JtwigViewResolverConfigurer { + + // Path where OAI is deployed. Defaults to "oai" + // NOTE: deployment on this path is handled by org.dspace.xoai.controller.DSpaceOAIDataProvider + @Value("${oai.path:oai}") + private String oaiPath; private static final String TWIG_HTML_EXTENSION = ".twig.html"; - private static final String VIEWS_LOCATION = "/WEB-INF/views/"; + private static final String VIEWS_LOCATION = "classpath:/templates/"; + /** + * Ensure all resources under src/main/resources/static/ directory are available + * off the /{oai.path}/static subpath + **/ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/static/**") - .addResourceLocations("/static/") + registry.addResourceHandler("/" + oaiPath + "/static/**") + .addResourceLocations("classpath:/static/") .setCachePeriod(MAX_VALUE); } + /** + * Configure the Jtwig template engine for Spring Boot + * Ensures Jtwig looks for templates in proper location with proper extension + **/ @Override - public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { - configurer.enable(); - } - - @Bean - public ViewResolver viewResolver() { - JtwigViewResolver viewResolver = new JtwigViewResolver(); + public void configure(JtwigViewResolver viewResolver) { viewResolver.setPrefix(VIEWS_LOCATION); viewResolver.setSuffix(TWIG_HTML_EXTENSION); - viewResolver.setCached(false); - - return viewResolver; } @Bean diff --git a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java index 6f33331a1d..212f1e3406 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/controller/DSpaceOAIDataProvider.java @@ -72,7 +72,7 @@ public class DSpaceOAIDataProvider { private DSpaceResumptionTokenFormatter resumptionTokenFormat = new DSpaceResumptionTokenFormatter(); - @RequestMapping("/") + @RequestMapping({"", "/"}) public String indexAction(HttpServletResponse response, Model model) throws ServletException { try { XOAIManager manager = xoaiManagerResolver.getManager(); diff --git a/dspace-oai/src/main/webapp/static/css/bootstrap-theme.css b/dspace-oai/src/main/resources/static/css/bootstrap-theme.css similarity index 100% rename from dspace-oai/src/main/webapp/static/css/bootstrap-theme.css rename to dspace-oai/src/main/resources/static/css/bootstrap-theme.css diff --git a/dspace-oai/src/main/webapp/static/css/bootstrap-theme.min.css b/dspace-oai/src/main/resources/static/css/bootstrap-theme.min.css similarity index 100% rename from dspace-oai/src/main/webapp/static/css/bootstrap-theme.min.css rename to dspace-oai/src/main/resources/static/css/bootstrap-theme.min.css diff --git a/dspace-oai/src/main/webapp/static/css/bootstrap.css b/dspace-oai/src/main/resources/static/css/bootstrap.css similarity index 100% rename from dspace-oai/src/main/webapp/static/css/bootstrap.css rename to dspace-oai/src/main/resources/static/css/bootstrap.css diff --git a/dspace-oai/src/main/webapp/static/css/bootstrap.min.css b/dspace-oai/src/main/resources/static/css/bootstrap.min.css similarity index 100% rename from dspace-oai/src/main/webapp/static/css/bootstrap.min.css rename to dspace-oai/src/main/resources/static/css/bootstrap.min.css diff --git a/dspace-oai/src/main/webapp/static/css/style.css b/dspace-oai/src/main/resources/static/css/style.css similarity index 100% rename from dspace-oai/src/main/webapp/static/css/style.css rename to dspace-oai/src/main/resources/static/css/style.css diff --git a/dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.eot b/dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.eot similarity index 100% rename from dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.eot rename to dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.eot diff --git a/dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.svg b/dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.svg similarity index 100% rename from dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.svg rename to dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.svg diff --git a/dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.ttf b/dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf similarity index 100% rename from dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.ttf rename to dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.ttf diff --git a/dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.woff b/dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.woff similarity index 100% rename from dspace-oai/src/main/webapp/static/fonts/glyphicons-halflings-regular.woff rename to dspace-oai/src/main/resources/static/fonts/glyphicons-halflings-regular.woff diff --git a/dspace-oai/src/main/webapp/static/img/lyncode.png b/dspace-oai/src/main/resources/static/img/lyncode.png similarity index 100% rename from dspace-oai/src/main/webapp/static/img/lyncode.png rename to dspace-oai/src/main/resources/static/img/lyncode.png diff --git a/dspace-oai/src/main/webapp/static/js/bootstrap.js b/dspace-oai/src/main/resources/static/js/bootstrap.js similarity index 100% rename from dspace-oai/src/main/webapp/static/js/bootstrap.js rename to dspace-oai/src/main/resources/static/js/bootstrap.js diff --git a/dspace-oai/src/main/webapp/static/js/bootstrap.min.js b/dspace-oai/src/main/resources/static/js/bootstrap.min.js similarity index 100% rename from dspace-oai/src/main/webapp/static/js/bootstrap.min.js rename to dspace-oai/src/main/resources/static/js/bootstrap.min.js diff --git a/dspace-oai/src/main/webapp/static/js/jquery.js b/dspace-oai/src/main/resources/static/js/jquery.js similarity index 100% rename from dspace-oai/src/main/webapp/static/js/jquery.js rename to dspace-oai/src/main/resources/static/js/jquery.js diff --git a/dspace-oai/src/main/webapp/static/lyncode.png b/dspace-oai/src/main/resources/static/lyncode.png similarity index 100% rename from dspace-oai/src/main/webapp/static/lyncode.png rename to dspace-oai/src/main/resources/static/lyncode.png diff --git a/dspace-oai/src/main/webapp/static/style.xsl b/dspace-oai/src/main/resources/static/style.xsl similarity index 100% rename from dspace-oai/src/main/webapp/static/style.xsl rename to dspace-oai/src/main/resources/static/style.xsl diff --git a/dspace-oai/src/main/webapp/WEB-INF/views/index.twig.html b/dspace-oai/src/main/resources/templates/index.twig.html similarity index 74% rename from dspace-oai/src/main/webapp/WEB-INF/views/index.twig.html rename to dspace-oai/src/main/resources/templates/index.twig.html index fc530902a3..0045d8f5e5 100644 --- a/dspace-oai/src/main/webapp/WEB-INF/views/index.twig.html +++ b/dspace-oai/src/main/resources/templates/index.twig.html @@ -6,6 +6,12 @@ http://www.dspace.org/license/ +#} +{# + + DSpace OAI default index template. To override this template, place a customized version in + the [webapp]/WEB-INF/classes/templates/ folder, and reboot your servlet engine. + #} @@ -13,8 +19,8 @@ DSpace OAI-PMH Data Provider - - + + @@ -24,9 +30,9 @@ - - - + + + @@ -56,11 +62,11 @@

@@ -73,11 +79,11 @@

Design by Lyncode

- Lyncode + Lyncode

- \ No newline at end of file + diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java index 4c343bf518..1ddc5eb1c0 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java @@ -59,7 +59,7 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { // Attempt to call the root endpoint getClient().perform(get(ROOT_PATH)) // Expect a 400 response code (OAI requires a context) - .andExpect(status().isOk()) + .andExpect(status().isBadRequest()) ; } From 805e35743b1befb2b31f91470aed50a52bc917e1 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 22 Feb 2019 15:19:09 +0000 Subject: [PATCH 168/188] Enhance inline comments in application.properties --- .../src/main/resources/application.properties | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/dspace-spring-rest/src/main/resources/application.properties b/dspace-spring-rest/src/main/resources/application.properties index fd395f38f5..7a5e5a0193 100644 --- a/dspace-spring-rest/src/main/resources/application.properties +++ b/dspace-spring-rest/src/main/resources/application.properties @@ -7,10 +7,19 @@ # # -# Spring Boot application.properties -# Docs (including info on how to override these default settings) +# Spring Boot's application.properties +# +# This properties file is used by Spring Boot to initialize its ApplicationContext and configure +# default Spring beans. It also uses the "dspace.dir" custom setting to locate your DSpace installation, +# and load all DSpace services and configurations. +# +# WARNING: Because this properties file initializes Spring Boot, it loads *before* any DSpace specific +# configurations/settings. Therefore settings in this file CANNOT depend on any DSpace configurations. +# The *only* DSpace configuration allowed in this file is "dspace.dir", which is documented below. +# +# Docs (including info on how to override these default settings) # http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html -# For common settings see: +# For common settings see: # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html # @@ -20,6 +29,8 @@ # DSpace home/installation directory # REQUIRED to be specified in this application.properties file, as it is used to locate and initialize # the DSpace Kernel and all Services (including configuration). See org.dspace.app.rest.Application.getDSpaceHome() +# NOTE: this configuration is filled out by Apache Ant during the DSpace install/update process. It does NOT +# interact with or read its configuration from dspace.cfg. dspace.dir=${dspace.dir} ######################## @@ -71,8 +82,8 @@ server.error.include-stacktrace = always # # DISABLE a few autoconfiguration scripts, as DSpace initializes/configures these already # * DataSourceAutoConfiguration (DB connection / datasource) +# * HibernateJpaAutoConfiguration (Hibernate ORM) # * FlywayAutoConfiguration (Flyway migrations) -# * HibernateJpaAutoConfiguration (Hibernate) # * SolrAutoConfiguration (Solr) # # TODO: At some point we may want to investigate whether we can re-enable these and remove the custom DSpace init code From 379968d12c04e76c1ed5158c99ac3fbe98fa8094 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 25 Feb 2019 22:55:52 +0000 Subject: [PATCH 169/188] Migrate existing OAI IntegrationTests to OAIpmhIT class in Spring Boot. Disable existing ITs (will be removed) --- .../tests/integration/xoai/IdentifyTest.java | 2 + .../tests/integration/xoai/ListSetsTest.java | 2 + .../integration/xoai/OAIContextTest.java | 2 + .../java/org/dspace/app/oai/OAIpmhIT.java | 205 +++++++++++++++++- .../AbstractIntegrationTestWithDatabase.java | 3 + 5 files changed, 207 insertions(+), 7 deletions(-) diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java index f49e4e07e2..173a118f73 100644 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java +++ b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java @@ -15,8 +15,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.util.Date; +import org.junit.Ignore; import org.junit.Test; +@Ignore public class IdentifyTest extends AbstractDSpaceTest { public static final Date EARLIEST_DATE = new Date(); diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java index 282d6a6c9d..d0bcd75c03 100644 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java +++ b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java @@ -14,8 +14,10 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.Ignore; import org.junit.Test; +@Ignore public class ListSetsTest extends AbstractDSpaceTest { @Test public void listSetsWithLessSetsThenMaxSetsPerPage() throws Exception { diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java index ef875e1896..c96445ac0d 100644 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java +++ b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java @@ -12,8 +12,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultHandlers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.Ignore; import org.junit.Test; +@Ignore public class OAIContextTest extends AbstractDSpaceTest { public static final String ROOT_URL = "/"; diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java index 1ddc5eb1c0..3869baefab 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java @@ -8,18 +8,42 @@ package org.dspace.app.oai; +import static org.hamcrest.Matchers.startsWith; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath; +import java.util.Date; + +import com.lyncode.xoai.dataprovider.core.XOAIManager; +import com.lyncode.xoai.dataprovider.exceptions.ConfigurationException; +import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; +import com.lyncode.xoai.dataprovider.services.impl.BaseDateProvider; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration; +import com.lyncode.xoai.dataprovider.xml.xoaiconfig.ContextConfiguration; + +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Community; import org.dspace.services.ConfigurationService; +import org.dspace.xoai.services.api.EarliestDateResolver; +import org.dspace.xoai.services.api.cache.XOAICacheService; +import org.dspace.xoai.services.api.config.XOAIManagerResolver; +import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; + import org.junit.Assume; import org.junit.Before; -//import org.junit.Ignore; import org.junit.Test; +import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.TestPropertySource; /** @@ -40,7 +64,30 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { // All OAI-PMH paths that we test against private final String ROOT_PATH = "/oai"; - private final String ROOT_REQUEST = "/oai/request"; + private final String DEFAULT_CONTEXT_PATH = "request"; + private final String DEFAULT_CONTEXT = ROOT_PATH + "/" + DEFAULT_CONTEXT_PATH; + + // Mock to ensure XOAI caching is disabled for all tests (see @Before method) + @MockBean + private XOAICacheService xoaiCacheService; + + // Mock for date-based testing below + @Mock + private EarliestDateResolver earliestDateResolver; + // XOAI's BaseDateProvider (used for date-based testing below) + private static BaseDateProvider baseDateProvider = new BaseDateProvider(); + + // Spy on the current XOAIManagerResolver, to allow us to change behavior of XOAIManager in tests + // See also: createMockXOAIManager() method + @SpyBean + private XOAIManagerResolver xoaiManagerResolver; + + // Beans required by createMockXOAIManager() + @Autowired + private ResourceResolver resourceResolver; + @Autowired + private DSpaceFilterResolver filterResolver; + @Before public void onlyRunIfConfigExists() { @@ -52,22 +99,55 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { } catch (ClassNotFoundException ce) { Assume.assumeNoException(ce); } + + // Disable XOAI Caching for ALL tests + when(xoaiCacheService.isActive()).thenReturn(false); + when(xoaiCacheService.hasCache(anyString())).thenReturn(false); } @Test - public void oaiRootTest() throws Exception { + public void requestToRootShouldGiveListOfContextsWithBadRequestError() throws Exception { // Attempt to call the root endpoint getClient().perform(get(ROOT_PATH)) - // Expect a 400 response code (OAI requires a context) + // Expect a 400 response code (OAI requires a context) .andExpect(status().isBadRequest()) + // Expect that a list of valid contexts is returned + .andExpect(model().attributeExists("contexts")) ; } + @Test + public void requestForUnknownContextShouldGiveListOfContextsWithBadRequestError() throws Exception { + // Attempt to call an nonexistent OAI-PMH context + getClient().perform(get(ROOT_PATH + "/nonexistentContext")) + // Expect a 400 response code (OAI requires a context) + .andExpect(status().isBadRequest()) + // Expect that a list of valid contexts is returned + .andExpect(model().attributeExists("contexts")) + ; + } @Test - public void oaiRootIdentifyTest() throws Exception { + public void requestForIdentifyWithoutRequiredConfigShouldFail() throws Exception { + // Clear out the required "mail.admin" configuration + configurationService.setProperty("mail.admin", null); + // Attempt to make an Identify request to root context - getClient().perform(get(ROOT_REQUEST).param("verb", "Identify")) + getClient().perform(get(DEFAULT_CONTEXT).param("verb", "Identify")) + // Expect a 500 response code (mail.admin MUST be set) + .andExpect(status().isInternalServerError()) + ; + } + + @Test + public void requestForIdentifyShouldReturnTheConfiguredValues() throws Exception { + + // Mock EarliestDateResolver to return now for getEarliestDate() + Date now = new Date(); + when(earliestDateResolver.getEarliestDate(context)).thenReturn(now); + + // Attempt to make an Identify request to root context + getClient().perform(get(DEFAULT_CONTEXT).param("verb", "Identify")) // Expect a 200 response code .andExpect(status().isOk()) // Expect the content type to be "text/xml" @@ -79,8 +159,119 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { // Expect repositoryName to be the same as "dspace.name" config .andExpect(xpath("OAI-PMH/Identify/repositoryName") .string(configurationService.getProperty("dspace.name"))) + // Expect adminEmail to be the same as "mail.admin" config + .andExpect(xpath("OAI-PMH/Identify/adminEmail") + .string(configurationService.getProperty("mail.admin"))) + // Expect earliestDatestamp to be "now", i.e. current date, (as mocked above) + .andExpect(xpath("OAI-PMH/Identify/earliestDatestamp") + .string(baseDateProvider.format(now))) ; } -} + @Test + public void listSetsWithLessSetsThenMaxSetsPerPage() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + // Create a Community & a Collection + Community parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + CollectionBuilder.createCollection(context, parentCommunity) + .withName("Child Collection") + .build(); + context.restoreAuthSystemState(); + + // Call ListSets verb, and verify both Collection & Community are listed as sets + getClient().perform(get(DEFAULT_CONTEXT).param("verb", "ListSets")) + // Expect 200 response, with valid response date and verb=ListSets + .andExpect(status().isOk()) + .andExpect(xpath("OAI-PMH/responseDate").exists()) + .andExpect(xpath("OAI-PMH/request/@verb").string("ListSets")) + // Expect two Sets to be returned + .andExpect(xpath("//set").nodeCount(2)) + // First setSpec should start with "com_" (Community) + .andExpect(xpath("(//set/setSpec)[1]").string(startsWith("com_"))) + // First set name should be Community name + .andExpect(xpath("(//set/setName)[1]").string("Parent Community")) + // Second setSpec should start with "col_" (Collection) + .andExpect(xpath("(//set/setSpec)[2]").string(startsWith("col_"))) + // Second set name should be Collection name + .andExpect(xpath("(//set/setName)[2]").string("Child Collection")) + // No resumption token should be returned + .andExpect(xpath("//resumptionToken").doesNotExist()) + ; + } + + @Test + public void listSetsWithMoreSetsThenMaxSetsPerPage() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + + // Create 3 Communities (1 as a subcommunity) & 2 Collections + Community firstCommunity = CommunityBuilder.createCommunity(context) + .withName("First Community") + .build(); + Community secondCommunity = CommunityBuilder.createSubCommunity(context, firstCommunity) + .withName("Second Community") + .build(); + CommunityBuilder.createCommunity(context) + .withName("Third Community") + .build(); + CollectionBuilder.createCollection(context, firstCommunity) + .withName("First Collection") + .build(); + CollectionBuilder.createCollection(context, secondCommunity) + .withName("Second Collection") + .build(); + context.restoreAuthSystemState(); + + + // Create a custom XOAI configuration, with maxListSetsSize = 3 for DEFAULT_CONTEXT requests + // (This limits the number of sets returned in a single response) + Configuration xoaiConfig = + new Configuration().withMaxListSetsSize(3) + .withContextConfigurations(new ContextConfiguration(DEFAULT_CONTEXT_PATH)); + // When xoaiManagerResolver.getManager() is called, return a MockXOAIManager based on the above configuration + doReturn(createMockXOAIManager(xoaiConfig)).when(xoaiManagerResolver).getManager(); + + // Call ListSets verb, and verify all 5 Collections/Communities are listed as sets + getClient().perform(get(DEFAULT_CONTEXT).param("verb", "ListSets")) + // Expect 200 response, with valid response date and verb=ListSets + .andExpect(status().isOk()) + .andExpect(xpath("OAI-PMH/responseDate").exists()) + .andExpect(xpath("OAI-PMH/request/@verb").string("ListSets")) + // Expect ONLY 3 (of 5) Sets to be returned + .andExpect(xpath("//set").nodeCount(3)) + // Expect resumption token to exist and be equal to "////3" + .andExpect(xpath("//resumptionToken").string("////3")) + // Expect resumption token to have completeListSize=5 + .andExpect(xpath("//resumptionToken/@completeListSize").number(Double.valueOf(5))) + ; + + // Call ListSets verb, and verify all 5 Collections/Communities are listed as sets + getClient().perform(get(DEFAULT_CONTEXT).param("verb", "ListSets")) + // Expect 200 response, with valid response date and verb=ListSets + .andExpect(status().isOk()) + .andExpect(xpath("OAI-PMH/responseDate").exists()) + .andExpect(xpath("OAI-PMH/request/@verb").string("ListSets")) + // Expect ONLY 3 (of 5) Sets to be returned + .andExpect(xpath("//set").nodeCount(3)) + // Expect resumption token to exist and be equal to "////3" + .andExpect(xpath("//resumptionToken").string("////3")) + // Expect resumption token to have completeListSize=5 + .andExpect(xpath("//resumptionToken/@completeListSize").number(Double.valueOf(5))) + ; + } + + /** + * Create a fake/mock XOAIManager class based on the given xoaiConfig. May be used by above tests + * to provide custom configurations to XOAI (overriding defaults in xoai.xml) + * @param xoaiConfig XOAI Configuration + * @return new XOAIManager initialized with the given Configuration + * @throws ConfigurationException + */ + private XOAIManager createMockXOAIManager(Configuration xoaiConfig) throws ConfigurationException { + return new XOAIManager(filterResolver, resourceResolver, xoaiConfig); + } +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java index 2aae82f96c..b655cb8e23 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/AbstractIntegrationTestWithDatabase.java @@ -184,6 +184,9 @@ public class AbstractIntegrationTestWithDatabase extends AbstractDSpaceIntegrati .getServiceByName(SearchService.class.getName(), MockSolrServiceImpl.class); searchService.reset(); + // Reload our ConfigurationService (to reset configs to defaults again) + DSpaceServicesFactory.getInstance().getConfigurationService().reloadConfig(); + // NOTE: we explicitly do NOT destroy our default eperson & admin as they // are cached and reused for all tests. This speeds up all tests. } catch (Exception e) { From 8c05914c04fa3ea55aeb479d732cafea57726cb5 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Wed, 27 Feb 2019 17:11:51 +0000 Subject: [PATCH 170/188] Fix CommunityRestRepositoryIT tests that were not cleaning up after themselves --- .../app/rest/CommunityRestRepositoryIT.java | 117 +++++++++++------- .../app/rest/builder/CommunityBuilder.java | 23 ++++ 2 files changed, 96 insertions(+), 44 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java index 3b3c12c720..bbbfe44a30 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java @@ -7,6 +7,7 @@ */ package org.dspace.app.rest; +import static com.jayway.jsonpath.JsonPath.read; import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata; import static org.hamcrest.Matchers.empty; @@ -21,6 +22,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.databind.ObjectMapper; @@ -37,6 +39,7 @@ import org.dspace.app.rest.test.MetadataPatchSuite; import org.dspace.authorize.service.AuthorizeService; import org.dspace.content.Collection; import org.dspace.content.Community; +import org.dspace.content.service.CommunityService; import org.dspace.core.Constants; import org.dspace.eperson.EPerson; import org.hamcrest.Matchers; @@ -44,18 +47,22 @@ import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; +/** + * Integration Tests against the /api/core/communities endpoint (including any subpaths) + */ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest { @Autowired CommunityConverter communityConverter; + @Autowired + CommunityService communityService; + @Autowired AuthorizeService authorizeService; @Test public void createTest() throws Exception { - context.turnOffAuthorisationSystem(); - ObjectMapper mapper = new ObjectMapper(); CommunityRest comm = new CommunityRest(); // We send a name but the created community should set this to the title @@ -86,41 +93,54 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest comm.setMetadata(metadataRest); String authToken = getAuthToken(admin.getEmail(), password); - getClient(authToken).perform(post("/api/core/communities") + + // Capture the UUID of the created Community (see andDo() below) + AtomicReference idRef = new AtomicReference(); + try { + getClient(authToken).perform(post("/api/core/communities") .content(mapper.writeValueAsBytes(comm)) .contentType(contentType)) - .andExpect(status().isCreated()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$", Matchers.allOf( - hasJsonPath("$.id", not(empty())), - hasJsonPath("$.uuid", not(empty())), - hasJsonPath("$.name", is("Title Text")), - hasJsonPath("$.handle", not(empty())), - hasJsonPath("$.type", is("community")), - hasJsonPath("$._links.collections.href", not(empty())), - hasJsonPath("$._links.logo.href", not(empty())), - hasJsonPath("$._links.subcommunities.href", not(empty())), - hasJsonPath("$._links.self.href", not(empty())), - hasJsonPath("$.metadata", Matchers.allOf( - matchMetadata("dc.description", "

Some cool HTML code here

"), - matchMetadata("dc.description.abstract", + .andExpect(status().isCreated()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.id", not(empty())), + hasJsonPath("$.uuid", not(empty())), + hasJsonPath("$.name", is("Title Text")), + hasJsonPath("$.handle", not(empty())), + hasJsonPath("$.type", is("community")), + hasJsonPath("$._links.collections.href", not(empty())), + hasJsonPath("$._links.logo.href", not(empty())), + hasJsonPath("$._links.subcommunities.href", not(empty())), + hasJsonPath("$._links.self.href", not(empty())), + hasJsonPath("$.metadata", Matchers.allOf( + matchMetadata("dc.description", "

Some cool HTML code here

"), + matchMetadata("dc.description.abstract", "Sample top-level community created via the REST API"), - matchMetadata("dc.description.tableofcontents", "

HTML News

"), - matchMetadata("dc.rights", "Custom Copyright Text"), - matchMetadata("dc.title", "Title Text") - ))))); + matchMetadata("dc.description.tableofcontents", "

HTML News

"), + matchMetadata("dc.rights", "Custom Copyright Text"), + matchMetadata("dc.title", "Title Text") + ) + ) + ))) + // capture "id" returned in JSON response + .andDo(result -> idRef + .set(UUID.fromString(read(result.getResponse().getContentAsString(), "$.id")))); + } finally { + // Delete the created community (cleanup after ourselves!) + CommunityBuilder.deleteCommunity(idRef.get()); + } } + @Test public void createWithParentTest() throws Exception { - context.turnOffAuthorisationSystem(); //We turn off the authorization system in order to create the structure as defined below context.turnOffAuthorisationSystem(); - //** GIVEN ** - //1. A community-collection structure with one parent community with sub-community and one collection. + // Create a parent community to POST a new sub-community to parentCommunity = CommunityBuilder.createCommunity(context) .withName("Parent Community") .build(); + context.restoreAuthSystemState(); ObjectMapper mapper = new ObjectMapper(); CommunityRest comm = new CommunityRest(); @@ -140,23 +160,26 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest new MetadataValueRest("Title Text"))); String authToken = getAuthToken(admin.getEmail(), password); - getClient(authToken).perform(post("/api/core/communities") + // Capture the UUID of the created Community (see andDo() below) + AtomicReference idRef = new AtomicReference(); + try { + getClient(authToken).perform(post("/api/core/communities") .content(mapper.writeValueAsBytes(comm)) .param("parent", parentCommunity.getID().toString()) .contentType(contentType)) - .andExpect(status().isCreated()) - .andExpect(content().contentType(contentType)) - .andExpect(jsonPath("$", Matchers.allOf( - hasJsonPath("$.id", not(empty())), - hasJsonPath("$.uuid", not(empty())), - hasJsonPath("$.name", is("Title Text")), - hasJsonPath("$.handle", not(empty())), - hasJsonPath("$.type", is("community")), - hasJsonPath("$._links.collections.href", not(empty())), - hasJsonPath("$._links.logo.href", not(empty())), - hasJsonPath("$._links.subcommunities.href", not(empty())), - hasJsonPath("$._links.self.href", not(empty())), - hasJsonPath("$.metadata", Matchers.allOf( + .andExpect(status().isCreated()) + .andExpect(content().contentType(contentType)) + .andExpect(jsonPath("$", Matchers.allOf( + hasJsonPath("$.id", not(empty())), + hasJsonPath("$.uuid", not(empty())), + hasJsonPath("$.name", is("Title Text")), + hasJsonPath("$.handle", not(empty())), + hasJsonPath("$.type", is("community")), + hasJsonPath("$._links.collections.href", not(empty())), + hasJsonPath("$._links.logo.href", not(empty())), + hasJsonPath("$._links.subcommunities.href", not(empty())), + hasJsonPath("$._links.self.href", not(empty())), + hasJsonPath("$.metadata", Matchers.allOf( MetadataMatcher.matchMetadata("dc.description", "

Some cool HTML code here

"), MetadataMatcher.matchMetadata("dc.description.abstract", @@ -167,13 +190,18 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest "Custom Copyright Text"), MetadataMatcher.matchMetadata("dc.title", "Title Text") - ))))); - - - + ) + ) + ))) + // capture "id" returned in JSON response + .andDo(result -> idRef + .set(UUID.fromString(read(result.getResponse().getContentAsString(), "$.id")))); + } finally { + // Delete the created community (cleanup after ourselves!) + CommunityBuilder.deleteCommunity(idRef.get()); + } } - @Test public void createUnauthorizedTest() throws Exception { context.turnOffAuthorisationSystem(); @@ -854,6 +882,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest } + @Test public void patchCommunityMetadataAuthorized() throws Exception { runPatchMetadataTests(admin, 200); } diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java index 420e614e0b..befa1daad3 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/CommunityBuilder.java @@ -10,6 +10,7 @@ package org.dspace.app.rest.builder; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; +import java.util.UUID; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.CharEncoding; @@ -92,4 +93,26 @@ public class CommunityBuilder extends AbstractDSpaceObjectBuilder { protected DSpaceObjectService getService() { return communityService; } + + /** + * Delete the Test Community referred to by the given UUID + * @param uuid UUID of Test Community to delete + * @throws SQLException + * @throws IOException + */ + public static void deleteCommunity(UUID uuid) throws SQLException, IOException { + try (Context c = new Context()) { + c.turnOffAuthorisationSystem(); + Community community = communityService.find(c, uuid); + if (community != null) { + try { + communityService.delete(c, community); + } catch (AuthorizeException e) { + // cannot occur, just wrap it to make the compiler happy + throw new RuntimeException(e.getMessage(), e); + } + } + c.complete(); + } + } } From 20e4da56d322f8d8d9ce9edaa10d3c67a926d2c5 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 1 Mar 2019 21:51:03 +0000 Subject: [PATCH 171/188] Remove OAI Integration Tests, framework & stubs. These ITs were moved to Spring Boot in previous commit. --- .../tests/DSpaceBasicTestConfiguration.java | 10 - .../xoai/tests/DSpaceTestConfiguration.java | 123 ------------ .../tests/helpers/HttpRequestBuilder.java | 37 ---- .../xoai/tests/helpers/SyntacticSugar.java | 28 --- .../helpers/stubs/ItemRepositoryBuilder.java | 183 ----------------- .../stubs/StubbedConfigurationService.java | 63 ------ .../stubs/StubbedEarliestDateResolver.java | 29 --- .../stubs/StubbedResourceResolver.java | 44 ----- .../helpers/stubs/StubbedSetRepository.java | 74 ------- .../stubs/StubbedXOAIManagerResolver.java | 39 ---- .../integration/xoai/AbstractDSpaceTest.java | 186 ------------------ .../tests/integration/xoai/IdentifyTest.java | 52 ----- .../tests/integration/xoai/ListSetsTest.java | 67 ------- .../integration/xoai/OAIContextTest.java | 37 ---- 14 files changed, 972 deletions(-) delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceTestConfiguration.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/HttpRequestBuilder.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/SyntacticSugar.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/ItemRepositoryBuilder.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedConfigurationService.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedEarliestDateResolver.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedResourceResolver.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedSetRepository.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedXOAIManagerResolver.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/AbstractDSpaceTest.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java delete mode 100644 dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceBasicTestConfiguration.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceBasicTestConfiguration.java index e50f2f969d..7b81468a8e 100644 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceBasicTestConfiguration.java +++ b/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceBasicTestConfiguration.java @@ -10,11 +10,9 @@ package org.dspace.xoai.tests; import static org.mockito.Mockito.mock; import org.dspace.xoai.services.api.FieldResolver; -import org.dspace.xoai.services.api.config.ConfigurationService; import org.dspace.xoai.services.api.context.ContextService; import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.dspace.xoai.services.impl.xoai.BaseDSpaceFilterResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedConfigurationService; import org.dspace.xoai.tests.helpers.stubs.StubbedFieldResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -29,14 +27,6 @@ public class DSpaceBasicTestConfiguration { return new BaseDSpaceFilterResolver(); } - - private StubbedConfigurationService configurationService = new StubbedConfigurationService(); - - @Bean - public ConfigurationService configurationService() { - return configurationService; - } - @Bean public ContextService contextService() { return mock(ContextService.class); diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceTestConfiguration.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceTestConfiguration.java deleted file mode 100644 index bc526cdf53..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/DSpaceTestConfiguration.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * 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.xoai.tests; - -import com.lyncode.xoai.dataprovider.services.api.ItemRepository; -import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; -import com.lyncode.xoai.dataprovider.services.api.SetRepository; -import org.dspace.core.Context; -import org.dspace.xoai.services.api.EarliestDateResolver; -import org.dspace.xoai.services.api.cache.XOAICacheService; -import org.dspace.xoai.services.api.config.XOAIManagerResolver; -import org.dspace.xoai.services.api.context.ContextService; -import org.dspace.xoai.services.api.context.ContextServiceException; -import org.dspace.xoai.services.api.xoai.IdentifyResolver; -import org.dspace.xoai.services.api.xoai.ItemRepositoryResolver; -import org.dspace.xoai.services.api.xoai.SetRepositoryResolver; -import org.dspace.xoai.services.impl.cache.DSpaceEmptyCacheService; -import org.dspace.xoai.services.impl.xoai.DSpaceIdentifyResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedEarliestDateResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedResourceResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedSetRepository; -import org.dspace.xoai.tests.helpers.stubs.StubbedXOAIManagerResolver; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import org.springframework.web.servlet.view.InternalResourceViewResolver; - -@Import(DSpaceBasicTestConfiguration.class) -@Configuration -@EnableWebMvc -public class DSpaceTestConfiguration extends WebMvcConfigurerAdapter { - private static final String TWIG_HTML_EXTENSION = ".twig.html"; - private static final String VIEWS_LOCATION = "/WEB-INF/views/"; - - - @Bean - public ContextService contextService() { - return new ContextService() { - @Override - public Context getContext() throws ContextServiceException { - return null; - } - }; - } - - private StubbedResourceResolver resourceResolver = new StubbedResourceResolver(); - - @Bean - public ResourceResolver resourceResolver() { - return resourceResolver; - } - - @Bean - public ViewResolver viewResolver() { - InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); - viewResolver.setPrefix(VIEWS_LOCATION); - viewResolver.setSuffix(TWIG_HTML_EXTENSION); -// viewResolver.setCached(true); -// viewResolver.setTheme(null); - - return viewResolver; - } - - - @Bean - public XOAIManagerResolver xoaiManagerResolver() { - return new StubbedXOAIManagerResolver(); - } - - @Bean - public XOAICacheService xoaiCacheService() { - return new DSpaceEmptyCacheService(); - } - - private StubbedSetRepository setRepository = new StubbedSetRepository(); - - @Bean - StubbedSetRepository setRepository() { - return setRepository; - } - - @Bean - public ItemRepositoryResolver itemRepositoryResolver() { - return new ItemRepositoryResolver() { - @Override - public ItemRepository getItemRepository() throws ContextServiceException { - try { - return null; - } catch (Exception e) { - throw new ContextServiceException(e); - } - } - }; - } - - @Bean - public SetRepositoryResolver setRepositoryResolver() { - return new SetRepositoryResolver() { - @Override - public SetRepository getSetRepository() throws ContextServiceException { - return setRepository; - } - }; - } - - @Bean - public IdentifyResolver identifyResolver() { - return new DSpaceIdentifyResolver(); - } - - @Bean - public EarliestDateResolver earliestDateResolver() { - return new StubbedEarliestDateResolver(); - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/HttpRequestBuilder.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/HttpRequestBuilder.java deleted file mode 100644 index 153b05576e..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/HttpRequestBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * 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.xoai.tests.helpers; - -import java.net.URI; -import java.net.URISyntaxException; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.mock.web.MockHttpServletRequest; - -public class HttpRequestBuilder { - private MockHttpServletRequest request = new MockHttpServletRequest(); - - public HttpRequestBuilder withUrl(String url) { - try { - URI uri = new URI(url); - } catch (URISyntaxException e) { - // ASD - } - return this; - } - - public HttpRequestBuilder usingGetMethod() { - request.setMethod("GET"); - return this; - } - - public HttpServletRequest build() { - - return request; - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/SyntacticSugar.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/SyntacticSugar.java deleted file mode 100644 index a6cd3a3249..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/SyntacticSugar.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * 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.xoai.tests.helpers; - -public class SyntacticSugar { - - /** - * Default constructor - */ - private SyntacticSugar() { } - - public static T given(T elem) { - return elem; - } - - public static T the(T elem) { - return elem; - } - - public static T and(T elem) { - return elem; - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/ItemRepositoryBuilder.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/ItemRepositoryBuilder.java deleted file mode 100644 index c01580e990..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/ItemRepositoryBuilder.java +++ /dev/null @@ -1,183 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import static com.lyncode.xoai.dataprovider.core.Granularity.Second; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.sql.SQLException; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import javax.xml.stream.XMLStreamException; - -import com.lyncode.xoai.builders.dataprovider.ElementBuilder; -import com.lyncode.xoai.builders.dataprovider.MetadataBuilder; -import com.lyncode.xoai.dataprovider.exceptions.MetadataBindException; -import com.lyncode.xoai.dataprovider.exceptions.WritingXmlException; -import com.lyncode.xoai.dataprovider.xml.XmlOutputContext; -import com.lyncode.xoai.dataprovider.xml.xoai.Metadata; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.common.SolrInputDocument; - -public class ItemRepositoryBuilder { - private final SolrClient solrServer; - - public ItemRepositoryBuilder(SolrClient solrServer) { - this.solrServer = solrServer; - } - - public ItemRepositoryBuilder withItem(DSpaceItemBuilder builder) { - try { - solrServer.add(index(builder)); - solrServer.commit(); - } catch (MetadataBindException | WritingXmlException | IOException - | SQLException | ParseException | XMLStreamException - | SolrServerException e) { - throw new RuntimeException(e); - } - return this; - } - - - private SolrInputDocument index(DSpaceItemBuilder item) - throws SQLException, MetadataBindException, ParseException, XMLStreamException, WritingXmlException { - SolrInputDocument doc = new SolrInputDocument(); - - doc.addField("item.id", item.getId()); - doc.addField("item.public", item.isPublic()); - doc.addField("item.lastmodified", item.getLastModifiedDate()); - doc.addField("item.submitter", item.getSubmitter()); - doc.addField("item.handle", item.getHandle()); - doc.addField("item.deleted", item.isDeleted()); - - for (String col : item.getCollections()) { - doc.addField("item.collections", col); - } - - for (String col : item.getCommunities()) { - doc.addField("item.communities", col); - } - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - XmlOutputContext context = XmlOutputContext.emptyContext(out, Second); - item.getMetadata().write(context); - context.getWriter().flush(); - context.getWriter().close(); - doc.addField("item.compile", out.toString()); - - return doc; - } - - public static class DSpaceItemBuilder { - private final List collections = new ArrayList<>(); - private final List communities = new ArrayList<>(); - private final MetadataBuilder metadataBuilder = new MetadataBuilder(); - private String handle; - private int id; - private String submitter; - private Date lastModifiedDate; - private boolean deleted; - private boolean aPublic = true; - - - public DSpaceItemBuilder withLastModifiedDate(Date lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - return this; - } - - public DSpaceItemBuilder withCollection(String colName) { - collections.add(colName); - return this; - } - - public DSpaceItemBuilder withCommunity(String comName) { - communities.add(comName); - return this; - } - - public DSpaceItemBuilder whichSsPublic() { - aPublic = true; - return this; - } - - public DSpaceItemBuilder whichSsPrivate() { - aPublic = false; - return this; - } - - public DSpaceItemBuilder whichIsDeleted() { - this.deleted = true; - return this; - } - - public DSpaceItemBuilder whichIsNotDeleted() { - this.deleted = false; - return this; - } - - public DSpaceItemBuilder withMetadata(String schema, String element, String value) { - metadataBuilder.withElement(new ElementBuilder().withName(schema).withField(element, value).build()); - return this; - } - - public String getHandle() { - return handle; - } - - public DSpaceItemBuilder withHandle(String handle) { - this.handle = handle; - return this; - } - - public DSpaceItemBuilder withSubmitter(String submitter) { - this.submitter = submitter; - return this; - } - - public DSpaceItemBuilder withId(int id) { - this.id = id; - return this; - } - - public int getId() { - return id; - } - - public String getSubmitter() { - return submitter; - } - - public Date getLastModifiedDate() { - return lastModifiedDate; - } - - public List getCollections() { - return collections; - } - - public List getCommunities() { - return communities; - } - - public Metadata getMetadata() { - return metadataBuilder.build(); - } - - public boolean isDeleted() { - return deleted; - } - - public boolean isPublic() { - return aPublic; - } - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedConfigurationService.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedConfigurationService.java deleted file mode 100644 index c6e7a3cc99..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedConfigurationService.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import java.util.HashMap; -import java.util.Map; - -import org.dspace.xoai.services.api.config.ConfigurationService; - -public class StubbedConfigurationService implements ConfigurationService { - private Map values = new HashMap(); - - - public StubbedConfigurationService hasBooleanProperty(String key, boolean value) { - values.put(key, value); - return this; - } - - public StubbedConfigurationService hasBooleanProperty(String module, String key, boolean value) { - values.put(module + "." + key, value); - return this; - } - - public StubbedConfigurationService hasProperty(String key, String value) { - values.put(key, value); - return this; - } - - public StubbedConfigurationService withoutProperty(String key) { - values.remove(key); - return this; - } - - public StubbedConfigurationService hasProperty(String module, String key, String value) { - values.put(module + "." + key, value); - return this; - } - - @Override - public String getProperty(String key) { - return (String) values.get(key); - } - - @Override - public String getProperty(String module, String key) { - return (String) values.get(module + "." + key); - } - - @Override - public boolean getBooleanProperty(String module, String key, boolean defaultValue) { - Boolean value = (Boolean) values.get(module + "." + key); - if (value == null) { - return defaultValue; - } else { - return value; - } - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedEarliestDateResolver.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedEarliestDateResolver.java deleted file mode 100644 index a585e1427e..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedEarliestDateResolver.java +++ /dev/null @@ -1,29 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import java.sql.SQLException; -import java.util.Date; - -import org.dspace.core.Context; -import org.dspace.xoai.exceptions.InvalidMetadataFieldException; -import org.dspace.xoai.services.api.EarliestDateResolver; - -public class StubbedEarliestDateResolver implements EarliestDateResolver { - private Date date = new Date(); - - public StubbedEarliestDateResolver is(Date date) { - this.date = date; - return this; - } - - @Override - public Date getEarliestDate(Context context) throws InvalidMetadataFieldException, SQLException { - return date; - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedResourceResolver.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedResourceResolver.java deleted file mode 100644 index 464f8fc487..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedResourceResolver.java +++ /dev/null @@ -1,44 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerFactory; - -import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; - -public class StubbedResourceResolver implements ResourceResolver { - private static TransformerFactory factory = TransformerFactory.newInstance(); - - private Map inputStreamMap = new HashMap(); - private Map transformerMap = new HashMap(); - - @Override - public InputStream getResource(String path) throws IOException { - return inputStreamMap.get(path); - } - - @Override - public Transformer getTransformer(String path) throws IOException, TransformerConfigurationException { - return transformerMap.get(path); - } - - public StubbedResourceResolver hasIdentityTransformerFor(String path) { - try { - transformerMap.put(path, factory.newTransformer()); - } catch (TransformerConfigurationException e) { - throw new RuntimeException(e); - } - return this; - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedSetRepository.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedSetRepository.java deleted file mode 100644 index 8432633e7b..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedSetRepository.java +++ /dev/null @@ -1,74 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import static java.lang.Math.min; -import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic; - -import java.util.ArrayList; -import java.util.List; - -import com.lyncode.xoai.dataprovider.core.ListSetsResult; -import com.lyncode.xoai.dataprovider.core.Set; -import com.lyncode.xoai.dataprovider.services.api.SetRepository; - -public class StubbedSetRepository implements SetRepository { - private List sets = new ArrayList(); - private boolean supports = false; - - @Override - public boolean supportSets() { - return supports; - } - - @Override - public ListSetsResult retrieveSets(int offset, int length) { - if (offset > sets.size()) { - return new ListSetsResult(false, new ArrayList(), sets.size()); - } - return new ListSetsResult(offset + length < sets.size(), - sets.subList(offset, min(offset + length, sets.size())), sets.size()); - } - - @Override - public boolean exists(String setSpec) { - for (Set set : sets) { - if (set.getSetSpec().equals(setSpec)) { - return true; - } - } - - return false; - } - - public StubbedSetRepository doesSupportSets() { - this.supports = true; - return this; - } - - public StubbedSetRepository doesNotSupportSets() { - this.supports = false; - return this; - } - - public StubbedSetRepository withSet(String name, String spec) { - this.sets.add(new Set(spec, name)); - return this; - } - - public StubbedSetRepository withRandomlyGeneratedSets(int number) { - for (int i = 0; i < number; i++) { - this.sets.add(new Set(randomAlphabetic(10), randomAlphabetic(10))); - } - return this; - } - - public void clear() { - this.sets.clear(); - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedXOAIManagerResolver.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedXOAIManagerResolver.java deleted file mode 100644 index f0d3275f74..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/helpers/stubs/StubbedXOAIManagerResolver.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * 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.xoai.tests.helpers.stubs; - -import com.lyncode.xoai.dataprovider.core.XOAIManager; -import com.lyncode.xoai.dataprovider.exceptions.ConfigurationException; -import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration; -import org.dspace.xoai.services.api.config.XOAIManagerResolver; -import org.dspace.xoai.services.api.config.XOAIManagerResolverException; -import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; -import org.springframework.beans.factory.annotation.Autowired; - -public class StubbedXOAIManagerResolver implements XOAIManagerResolver { - @Autowired - ResourceResolver resourceResolver; - @Autowired - DSpaceFilterResolver filterResolver; - - private Configuration builder = new Configuration(); - - public Configuration configuration() { - return builder; - } - - @Override - public XOAIManager getManager() throws XOAIManagerResolverException { - try { - return new XOAIManager(filterResolver, resourceResolver, builder); - } catch (ConfigurationException e) { - throw new XOAIManagerResolverException(e); - } - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/AbstractDSpaceTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/AbstractDSpaceTest.java deleted file mode 100644 index d9824d8c53..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/AbstractDSpaceTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/** - * 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.xoai.tests.integration.xoai; - -import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; - -import java.util.Date; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.xml.xpath.XPathExpressionException; - -import com.lyncode.builder.MapBuilder; -import com.lyncode.xoai.dataprovider.services.api.ResourceResolver; -import com.lyncode.xoai.dataprovider.services.impl.BaseDateProvider; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.Configuration; -import com.lyncode.xoai.dataprovider.xml.xoaiconfig.FormatConfiguration; -import org.apache.solr.client.solrj.SolrClient; -import org.dspace.xoai.controller.DSpaceOAIDataProvider; -import org.dspace.xoai.services.api.EarliestDateResolver; -import org.dspace.xoai.services.api.FieldResolver; -import org.dspace.xoai.services.api.config.ConfigurationService; -import org.dspace.xoai.services.api.config.XOAIManagerResolver; -import org.dspace.xoai.tests.DSpaceTestConfiguration; -import org.dspace.xoai.tests.helpers.stubs.ItemRepositoryBuilder; -import org.dspace.xoai.tests.helpers.stubs.StubbedConfigurationService; -import org.dspace.xoai.tests.helpers.stubs.StubbedEarliestDateResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedFieldResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedResourceResolver; -import org.dspace.xoai.tests.helpers.stubs.StubbedSetRepository; -import org.dspace.xoai.tests.helpers.stubs.StubbedXOAIManagerResolver; -import org.junit.After; -import org.junit.Before; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.test.context.web.WebAppConfiguration; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.ResultMatcher; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; -import org.springframework.test.web.servlet.result.XpathResultMatchers; -import org.springframework.web.context.WebApplicationContext; - - -@RunWith(SpringJUnit4ClassRunner.class) -@WebAppConfiguration -@ContextConfiguration(classes = {DSpaceTestConfiguration.class, DSpaceOAIDataProvider.class}) -public abstract class AbstractDSpaceTest { - private static final BaseDateProvider baseDateProvider = new BaseDateProvider(); - @Autowired - WebApplicationContext wac; - private MockMvc mockMvc; - - private StubbedXOAIManagerResolver xoaiManagerResolver; - private StubbedConfigurationService configurationService; - private StubbedFieldResolver databaseService; - private StubbedEarliestDateResolver earliestDateResolver; - private StubbedSetRepository setRepository; - private StubbedResourceResolver resourceResolver; - private SolrClient solrServer; - - @Before - public void setup() { - xoaiManagerResolver = (StubbedXOAIManagerResolver) this.wac.getBean(XOAIManagerResolver.class); - configurationService = (StubbedConfigurationService) this.wac.getBean(ConfigurationService.class); - databaseService = (StubbedFieldResolver) this.wac.getBean(FieldResolver.class); - earliestDateResolver = (StubbedEarliestDateResolver) this.wac.getBean(EarliestDateResolver.class); - setRepository = this.wac.getBean(StubbedSetRepository.class); - setRepository.clear(); -// solrServer = this.wac.getBean(SolrServer.class); - resourceResolver = (StubbedResourceResolver) this.wac.getBean(ResourceResolver.class); - xoaiManagerResolver.configuration(); - } - - @After - public void teardown() { - // Nullify all resources so that JUnit will clean them up - xoaiManagerResolver = null; - configurationService = null; - databaseService = null; - earliestDateResolver = null; - setRepository = null; - resourceResolver = null; - mockMvc = null; - solrServer = null; - } - - protected MockMvc againstTheDataProvider() { - if (this.mockMvc == null) { - this.mockMvc = webAppContextSetup(this.wac).build(); - } - return this.mockMvc; - } - - protected Configuration theConfiguration() { - return xoaiManagerResolver.configuration(); - } - - protected StubbedConfigurationService theDSpaceConfiguration() { - return configurationService; - } - - protected StubbedFieldResolver theDatabase() { - return databaseService; - } - - protected StubbedEarliestDateResolver theEarlistEarliestDate() { - return earliestDateResolver; - } - - protected XpathResultMatchers oaiXPath(String xpath) throws XPathExpressionException { - return MockMvcResultMatchers.xpath(this.replaceXpath(xpath), new MapBuilder() - .withPair("o", "http://www.openarchives.org/OAI/2.0/") - .build()); - } - - private String replaceXpath(String xpath) { - int offset = 0; - String newXpath = ""; - Pattern pattern = Pattern.compile("/[^/]+"); - Matcher matcher = pattern.matcher(xpath); - while (matcher.find()) { - if (matcher.start() > offset) { - newXpath += xpath.substring(offset, matcher.start()); - } - if (!matcher.group().contains(":") && !matcher.group().startsWith("/@")) { - newXpath += "/o:" + matcher.group().substring(1); - } else { - newXpath += matcher.group(); - } - offset = matcher.end() + 1; - } - - return newXpath; - } - - protected String representationOfDate(Date date) { - return baseDateProvider.format(date); - } - - protected StubbedSetRepository theSetRepository() { - return setRepository; - } - - protected com.lyncode.xoai.dataprovider.xml.xoaiconfig.ContextConfiguration aContext(String baseUrl) { - return new com.lyncode.xoai.dataprovider.xml.xoaiconfig.ContextConfiguration(baseUrl); - } - - protected XpathResultMatchers responseDate() throws XPathExpressionException { - return oaiXPath("/OAI-PMH/responseDate"); - } - - protected ResultMatcher verb(org.hamcrest.Matcher matcher) throws XPathExpressionException { - return oaiXPath("/OAI-PMH/request/@verb").string(matcher); - } - - protected XpathResultMatchers resumptionToken() throws XPathExpressionException { - return oaiXPath("//resumptionToken"); - } - - protected StubbedResourceResolver theResourseResolver() { - return resourceResolver; - } - - protected FormatConfiguration aFormat(String id) { - return new FormatConfiguration(id); - } - - protected ItemRepositoryBuilder.DSpaceItemBuilder anItem() { - return new ItemRepositoryBuilder.DSpaceItemBuilder(); - } - - private ItemRepositoryBuilder itemRepositoryBuilder; - - public ItemRepositoryBuilder theItemRepository() { - if (itemRepositoryBuilder == null) { - itemRepositoryBuilder = new ItemRepositoryBuilder(solrServer); - } - return itemRepositoryBuilder; - } -} \ No newline at end of file diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java deleted file mode 100644 index 173a118f73..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/IdentifyTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/** - * 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.xoai.tests.integration.xoai; - -import static org.dspace.xoai.tests.helpers.SyntacticSugar.and; -import static org.dspace.xoai.tests.helpers.SyntacticSugar.given; -import static org.hamcrest.core.Is.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import java.util.Date; - -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class IdentifyTest extends AbstractDSpaceTest { - - public static final Date EARLIEST_DATE = new Date(); - - @Test - public void requestForIdentifyWithoutRequiredConfigurationAdminEmailSetShouldFail() throws Exception { - given(theDSpaceConfiguration() - .withoutProperty("mail.admin")); - and(given(theConfiguration().withContextConfigurations(aContext("request")))); - - againstTheDataProvider().perform(get("/request?verb=Identify")) - .andExpect(status().isInternalServerError()); - } - - @Test - public void requestForIdentifyShouldReturnTheConfiguredValues() throws Exception { - given(theDSpaceConfiguration() - .hasProperty("dspace.name", "Test") - .hasProperty("mail.admin", "test@test.com")); - - and(given(theEarlistEarliestDate().is(EARLIEST_DATE))); - and(given(theConfiguration().withContextConfigurations(aContext("request")))); - - againstTheDataProvider().perform(get("/request?verb=Identify")) - .andExpect(status().isOk()) - .andExpect(oaiXPath("//repositoryName").string("Test")) - .andExpect(oaiXPath("//adminEmail").string("test@test.com")) - .andExpect( - oaiXPath("//earliestDatestamp").string(is(representationOfDate(EARLIEST_DATE)))); - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java deleted file mode 100644 index d0bcd75c03..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/ListSetsTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/** - * 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.xoai.tests.integration.xoai; - -import static org.dspace.xoai.tests.helpers.SyntacticSugar.and; -import static org.dspace.xoai.tests.helpers.SyntacticSugar.given; -import static org.hamcrest.core.Is.is; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class ListSetsTest extends AbstractDSpaceTest { - @Test - public void listSetsWithLessSetsThenMaxSetsPerPage() throws Exception { - given(theConfiguration() - .withMaxListSetsSize(100) - .withContextConfigurations(aContext("request"))); - and(given(theSetRepository() - .doesSupportSets() - .withSet("name", "spec"))); - - againstTheDataProvider().perform(get("/request?verb=ListSets")) - .andExpect(status().isOk()) - .andDo(print()) - .andExpect(responseDate().exists()) - .andExpect(verb(is("ListSets"))) - .andExpect(oaiXPath("//set").nodeCount(1)) - .andExpect(oaiXPath("//set/setSpec").string("spec")) - .andExpect(oaiXPath("//set/setName").string("name")) - .andExpect(resumptionToken().doesNotExist()); - } - - @Test - public void listSetsWithMoreSetsThenMaxSetsPerPage() throws Exception { - given(theConfiguration() - .withMaxListSetsSize(10) - .withContextConfigurations(aContext("request"))); - - and(given(theSetRepository() - .doesSupportSets() - .withRandomlyGeneratedSets(20))); - - againstTheDataProvider().perform(get("/request?verb=ListSets")) - .andExpect(status().isOk()) - .andExpect(responseDate().exists()) - .andExpect(verb(is("ListSets"))) - .andExpect(oaiXPath("//set").nodeCount(10)) - .andExpect(resumptionToken().string("////10")) - .andExpect(oaiXPath("//resumptionToken/@completeListSize").number(Double.valueOf(20))); - - and(againstTheDataProvider().perform(get("/request?verb=ListSets&resumptionToken=////10")) - .andExpect(status().isOk()) - .andExpect(responseDate().exists()) - .andExpect(verb(is("ListSets"))) - .andExpect(oaiXPath("//set").nodeCount(10)) - .andExpect(resumptionToken().string(""))); - } -} diff --git a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java b/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java deleted file mode 100644 index c96445ac0d..0000000000 --- a/dspace-oai/src/test/java/org/dspace/xoai/tests/integration/xoai/OAIContextTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * 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.xoai.tests.integration.xoai; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -import org.junit.Ignore; -import org.junit.Test; - -@Ignore -public class OAIContextTest extends AbstractDSpaceTest { - public static final String ROOT_URL = "/"; - - @Test - public void requestToRootShouldGiveListOfContextsWithBadRequestError() throws Exception { - againstTheDataProvider().perform(get(ROOT_URL)) - .andDo(print()) - .andExpect(status().isBadRequest()) - .andExpect(model().attributeExists("contexts")); - } - - @Test - public void requestForUnknownContextShouldGiveListOfContextsWithBadRequestError() throws Exception { - againstTheDataProvider().perform(get("/unexistentContext")) - .andDo(print()) - .andExpect(status().isBadRequest()) - .andExpect(model().attributeExists("contexts")); - } -} From ea4e05d8b8ca73735d934fca6c2f6ca704d17e15 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 5 Mar 2019 21:44:07 +0000 Subject: [PATCH 172/188] Embed RDF into Boot webapp. Add basic ITs to prove it works. --- dspace-rdf/pom.xml | 15 +- .../app/configuration/RDFWebConfig.java | 56 +++++++ dspace-rdf/src/main/webapp/WEB-INF/web.xml | 71 --------- dspace-spring-rest/pom.xml | 4 + .../test/java/org/dspace/app/rdf/RdfIT.java | 146 ++++++++++++++++++ dspace/config/modules/rdf.cfg | 25 ++- dspace/modules/rdf/pom.xml | 112 -------------- dspace/modules/rdf/src/main/webapp/.gitignore | 0 dspace/pom.xml | 1 - pom.xml | 1 - 10 files changed, 238 insertions(+), 193 deletions(-) create mode 100644 dspace-rdf/src/main/java/org/dspace/app/configuration/RDFWebConfig.java delete mode 100644 dspace-rdf/src/main/webapp/WEB-INF/web.xml create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rdf/RdfIT.java delete mode 100644 dspace/modules/rdf/pom.xml delete mode 100644 dspace/modules/rdf/src/main/webapp/.gitignore diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 9c6c154ddc..080045de03 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -3,9 +3,9 @@ 4.0.0 org.dspace dspace-rdf - war + jar DSpace RDF - Parent project for the RDF API and Webapp + DSpace RDF (Linked Data) Extension org.dspace @@ -58,8 +58,15 @@ dspace-services - + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + + javax.servlet diff --git a/dspace-rdf/src/main/java/org/dspace/app/configuration/RDFWebConfig.java b/dspace-rdf/src/main/java/org/dspace/app/configuration/RDFWebConfig.java new file mode 100644 index 0000000000..15b991af0a --- /dev/null +++ b/dspace-rdf/src/main/java/org/dspace/app/configuration/RDFWebConfig.java @@ -0,0 +1,56 @@ +/** + * 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.configuration; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * RDF webapp configuration. Replaces the old web.xml + *

+ * This @Configuration class is automatically discovered by Spring via a @ComponentScan. + *

+ * All RDF web configurations (beans) can be enabled or disabled by setting "rdf.enabled" + * to true or false, respectively (in your DSpace configuration). Default is "false". + *

+ * All @Value annotated configurations below can also be overridden in your DSpace configuration. + * + * @author Tim Donohue + */ +@Configuration +public class RDFWebConfig { + // Path where RDF should be deployed (when enabled). Defaults to "rdf" + @Value("${rdf.path:rdf}") + private String rdfPath; + + // Servlet Beans. All of the below bean definitions map servlets to respond to specific URL patterns + // These are the combined equivalent of and in web.xml + // All beans are only loaded when rdf.enabled = true + + @Bean + @ConditionalOnProperty("rdf.enabled") + public ServletRegistrationBean rdfSerializationBean() { + ServletRegistrationBean bean = new ServletRegistrationBean( new org.dspace.rdf.providing.DataProviderServlet(), + "/" + rdfPath + "/handle/*"); + bean.setLoadOnStartup(1); + return bean; + } + + @Bean + @ConditionalOnProperty("rdf.enabled") + public ServletRegistrationBean rdfLocalURIRedirectionBean() { + ServletRegistrationBean bean = new ServletRegistrationBean( + new org.dspace.rdf.providing.LocalURIRedirectionServlet(), "/" + rdfPath + "/resource/*"); + bean.setLoadOnStartup(1); + return bean; + } +} + diff --git a/dspace-rdf/src/main/webapp/WEB-INF/web.xml b/dspace-rdf/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index c15ec675f3..0000000000 --- a/dspace-rdf/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - RDF Data Provider - - - - The location of the DSpace home directory - - dspace.dir - ${dspace.dir} - - - - log4jConfiguration - ${dspace.dir}/config/log4j2.xml - - The location of the Log4J configuration - - - - - dspace.request - org.dspace.utils.servlet.DSpaceWebappServletFilter - - - - dspace.request - /* - - - - org.dspace.app.util.DSpaceContextListener - - - - org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener - - - - rdf-serialization - org.dspace.rdf.providing.DataProviderServlet - - - - local-uri-redirection - org.dspace.rdf.providing.LocalURIRedirectionServlet - - - - - rdf-serialization - /handle/* - - - - local-uri-redirection - /resource/* - - diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index 581c86062e..b1c6b243ab 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -264,6 +264,10 @@ org.dspace dspace-oai + + org.dspace + dspace-rdf + org.dspace dspace-sword diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rdf/RdfIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rdf/RdfIT.java new file mode 100644 index 0000000000..9cc731ad9c --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rdf/RdfIT.java @@ -0,0 +1,146 @@ +/** + * 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.rdf; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.doReturn; + +import java.net.URI; + +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.test.AbstractWebClientIntegrationTest; +import org.dspace.content.Community; +import org.dspace.content.service.SiteService; +import org.dspace.rdf.RDFUtil; +import org.dspace.rdf.conversion.RDFConverter; +import org.dspace.rdf.factory.RDFFactoryImpl; +import org.dspace.rdf.storage.RDFStorage; +import org.dspace.rdf.storage.RDFStorageImpl; +import org.dspace.services.ConfigurationService; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Spy; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.TestPropertySource; + +/** + * Integration test to verify that the /rdf endpoint is responding as a valid RDF endpoint. + * This tests that our dspace-rdf module is running at this endpoint. + *

+ * This is a AbstractWebClientIntegrationTest because testing dspace-rdf requires + * running a web server (as dspace-rdf makes use of Servlets, not Controllers). + *

+ * NOTE: At this time, these ITs do NOT run against a real RDF triplestore. Instead, + * individual tests are expected to mock triplestore responses via a spy-able RDFStorage. + * + * @author Tim Donohue + */ +// Ensure the RDF endpoint IS ENABLED before any tests run. +// This annotation overrides default DSpace config settings loaded into Spring Context +@TestPropertySource(properties = {"rdf.enabled = true"}) +public class RdfIT extends AbstractWebClientIntegrationTest { + + @Autowired + private ConfigurationService configurationService; + + @Autowired + private SiteService siteService; + + @Autowired + private RDFConverter rdfConverter; + + @Autowired + private RDFFactoryImpl rdfFactory; + + // Create a new spy-able instance of RDFStorage. We will use this instance in all below tests (see @Before) + // so that we can fake a triplestore backend. No triplestore is used in these tests. + @Spy + RDFStorage rdfStorage = new RDFStorageImpl(); + + // All RDF paths that we test against + private final String SERIALIZE_PATH = "/rdf/handle"; + private final String REDIRECTION_PATH = "/rdf/resource"; + + @Before + public void onlyRunIfConfigExists() { + // These integration tests REQUIRE that RDFWebConfig is found/available (as this class deploys RDF) + // If this class is not available, the below "Assume" will cause all tests to be SKIPPED + // NOTE: RDFWebConfig is provided by the 'dspace-rdf' module + try { + Class.forName("org.dspace.app.configuration.RDFWebConfig"); + } catch (ClassNotFoundException ce) { + Assume.assumeNoException(ce); + } + + // Change the running RDFFactory to use our spy-able, default instance of RDFStorage + // Again, this lets us fake a triplestore backend in individual tests below. + rdfFactory.setStorage(rdfStorage); + } + + @Test + public void serializationTest() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + + // Create a Community + Community community = CommunityBuilder.createCommunity(context) + .withName("Test Community") + .build(); + // Ensure Community is written to test DB immediately + context.commit(); + context.restoreAuthSystemState(); + + // Get the RDF identifiers for this new Community & our Site object + String communityIdentifier = RDFUtil.generateIdentifier(context, community); + String siteIdentifier = RDFUtil.generateIdentifier(context, siteService.findSite(context)); + + // Mock an RDF triplestore's response by returning the RDF conversion of our Community + // when rdfStorage.load() is called with the RDF identifier for this Community + doReturn(rdfConverter.convert(context, community)).when(rdfStorage).load(communityIdentifier); + + // Perform a GET request on the RDF /handle path, using our new Community's Handle + ResponseEntity response = getResponseAsString(SERIALIZE_PATH + "/" + community.getHandle()); + // Expect a 200 response code, and text/turtle (RDF Turtle syntax) response + assertThat(response.getStatusCode(), equalTo(HttpStatus.OK)); + assertThat(response.getHeaders().getContentType().toString(), equalTo("text/turtle;charset=UTF-8")); + + // Turtle response should include the RDF identifier of Community + assertThat(response.getBody(), containsString(communityIdentifier)); + // Turtle response should also note that this Community is part of our Site object + assertThat(response.getBody(), containsString("dspace:isPartOfRepository <" + siteIdentifier + "> ;")); + } + + @Test + public void redirectionTest() throws Exception { + //Turn off the authorization system, otherwise we can't make the objects + context.turnOffAuthorisationSystem(); + + // Create a Community + Community community = CommunityBuilder.createCommunity(context) + .withName("Test Community") + .build(); + // Ensure Community is written to test DB immediately (so that a lookup via handle will succeed below) + context.commit(); + context.restoreAuthSystemState(); + + String communityHandle = community.getHandle(); + + // Perform a GET request on the RDF /resource path, using this Community's Handle + ResponseEntity response = getResponseAsString(REDIRECTION_PATH + "/" + communityHandle); + // Expect a 303 (See Other) response code, redirecting us to the HTTP URI of the Community + assertThat(response.getStatusCode(), equalTo(HttpStatus.SEE_OTHER)); + // Expect location of redirection to be [dspace.url]/handle/[community_handle] + assertThat(response.getHeaders().getLocation(), equalTo( + URI.create(configurationService.getProperty("dspace.url") + "/handle/" + communityHandle + "/"))); + } +} diff --git a/dspace/config/modules/rdf.cfg b/dspace/config/modules/rdf.cfg index 355d9f65c0..f33a320360 100644 --- a/dspace/config/modules/rdf.cfg +++ b/dspace/config/modules/rdf.cfg @@ -1,12 +1,29 @@ -# These configs are used by dspace-rdf and the buildin Linked Data export (rdfizer) +#---------------------------------------------------------------# +#----------------RDF (LINKED DATA) CONFIGURATIONS---------------# +#---------------------------------------------------------------# +# These configs are only used by the RDF (Linked Data) # +# interface (provided by dspace-rdf and the built-in Linked # +# Data export (rdfizer)). +#---------------------------------------------------------------# + +# Whether or not to enable the RDF module +# When "true", the RDF module is accessible on ${rdf.path} +# When "false" or commented out, RDF is disabled/inaccessible. +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#rdf.enabled = true + +# Path where RDF module is available (in the Spring REST webapp) +# Defaults to "rdf", which means the RDF module would be available +# at ${dspace.restURL}/rdf/ +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +rdf.path = rdf # Configure if content negotiation should be enabled rdf.contentNegotiation.enable = false -# Set the url of the dspace-rdf module here. This is necessary to use content +# Set the url of the RDF module here. This is necessary to use content # negotiation -rdf.contextPath = ${dspace.baseUrl}/rdf - +rdf.contextPath = ${dspace.baseUrl}/${rdf.path} # Address of the public SPARQL endpoint diff --git a/dspace/modules/rdf/pom.xml b/dspace/modules/rdf/pom.xml deleted file mode 100644 index 297d165a6d..0000000000 --- a/dspace/modules/rdf/pom.xml +++ /dev/null @@ -1,112 +0,0 @@ - - 4.0.0 - org.dspace.modules - rdf - war - DSpace RDF :: Local Customizations - - Overlay RDF customizations - - - - modules - org.dspace - 7.0-SNAPSHOT - .. - - - - - ${basedir}/../../.. - - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - unpack - prepare-package - - unpack-dependencies - - - org.dspace.modules - additions - - ${project.build.directory}/additions - META-INF/** - - - - - - org.apache.maven.plugins - maven-war-plugin - - false - - true - - - - ${project.build.directory}/additions - WEB-INF/classes - - - - - - prepare-package - - - - - - - - - oracle-support - - - db.name - oracle - - - - - com.oracle - ojdbc6 - - - - - - - - org.dspace.modules - additions - - - org.dspace - dspace-rdf - war - - - javax.servlet - javax.servlet-api - provided - - - - diff --git a/dspace/modules/rdf/src/main/webapp/.gitignore b/dspace/modules/rdf/src/main/webapp/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/dspace/pom.xml b/dspace/pom.xml index 0c6ea85f78..bf46f313bf 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -203,7 +203,6 @@ org.dspace dspace-rdf - war compile diff --git a/pom.xml b/pom.xml index 4bf4365de5..2a2905b9f2 100644 --- a/pom.xml +++ b/pom.xml @@ -962,7 +962,6 @@ org.dspace dspace-rdf 7.0-SNAPSHOT - war org.dspace From 4fd0044ff84bddfe8d20c005770bf1d397fc0696 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 21 Mar 2019 18:24:46 +0000 Subject: [PATCH 173/188] Bug Fix. Ensure proper "baseUrl" is reported from each OAI context. Add IT to prove it works --- .../impl/xoai/DSpaceRepositoryConfiguration.java | 16 ++++++++++++++-- .../test/java/org/dspace/app/oai/OAIpmhIT.java | 3 +++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java index 979520c199..fe7fbdbfd0 100644 --- a/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java +++ b/dspace-oai/src/main/java/org/dspace/xoai/services/impl/xoai/DSpaceRepositoryConfiguration.java @@ -27,6 +27,8 @@ import org.dspace.xoai.services.api.EarliestDateResolver; import org.dspace.xoai.services.api.config.ConfigurationService; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.springframework.web.util.UriComponentsBuilder; /** * @author Lyncode Development Team (dspace at lyncode dot com) @@ -68,17 +70,27 @@ public class DSpaceRepositoryConfiguration implements RepositoryConfiguration { public String getBaseUrl() { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()) .getRequest(); + + // Parse the current OAI "context" path out of the last HTTP request. + // (e.g. for "http://mydspace.edu/oai/request", the oaiContextPath is "request") + UriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequest(request); + List pathSegments = builder.buildAndExpand().getPathSegments(); + String oaiContextPath = pathSegments.get(pathSegments.size() - 1); + if (baseUrl == null) { baseUrl = configurationService.getProperty("oai.url"); if (baseUrl == null) { log.warn( "{ OAI 2.0 :: DSpace } Not able to retrieve the oai.url property from oai.cfg. Falling back to " + "request address"); + // initialize baseUrl to a fallback "oai.url" which is the current request with OAI context removed. baseUrl = request.getRequestURL().toString() - .replace(request.getPathInfo(), ""); + .replace(oaiContextPath, ""); } } - return baseUrl + request.getPathInfo(); + + // BaseURL is the path of OAI with the current OAI context appended + return baseUrl + "/" + oaiContextPath; } @Override diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java index 3869baefab..57590f8166 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java @@ -162,6 +162,9 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { // Expect adminEmail to be the same as "mail.admin" config .andExpect(xpath("OAI-PMH/Identify/adminEmail") .string(configurationService.getProperty("mail.admin"))) + // Expect baseURL to be the same as our "oai.url" with the DEFAULT_CONTEXT_PATH appended + .andExpect(xpath("OAI-PMH/Identify/baseURL") + .string(configurationService.getProperty("oai.url") + "/" + DEFAULT_CONTEXT_PATH)) // Expect earliestDatestamp to be "now", i.e. current date, (as mocked above) .andExpect(xpath("OAI-PMH/Identify/earliestDatestamp") .string(baseDateProvider.format(now))) From 4938eb7f42ac7362657bc9737f0e063d97814b97 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 21 Mar 2019 18:25:37 +0000 Subject: [PATCH 174/188] Configuration fixes. Add missing oai.cfg properties. Default dspace.baseUrl to single webapp path. --- dspace/config/dspace.cfg | 4 ++-- dspace/config/modules/oai.cfg | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index a290d7f36e..6b2581a497 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -26,7 +26,7 @@ dspace.dir = /dspace dspace.hostname = localhost # DSpace base host URL. Include port number etc. -dspace.baseUrl = http://localhost:8080 +dspace.baseUrl = http://localhost:8080/spring-rest # 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. @@ -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 will typically be followed by /api to determine the root endpoints. -dspace.restUrl = ${dspace.baseUrl}/spring-rest +dspace.restUrl = ${dspace.baseUrl} # Optional: DSpace URL for mobile access # This diff --git a/dspace/config/modules/oai.cfg b/dspace/config/modules/oai.cfg index 493eb2510e..0765331c58 100644 --- a/dspace/config/modules/oai.cfg +++ b/dspace/config/modules/oai.cfg @@ -4,12 +4,24 @@ # These configs are used by the OAI-PMH interface # #---------------------------------------------------------------# +# Whether or not to enable the OAI module +# When "true", the OAI module is accessible on ${oai.path} +# When "false" or commented out, OAI is disabled/inaccessible. +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +#oai.enabled = true + +# Path where OAI module is available +# Defaults to "oai", which means the OAI module would be available +# at ${dspace.restURL}/oai/ +# (Requires reboot of servlet container, e.g. Tomcat, to reload) +oai.path = oai + # Storage: solr | database (solr is recommended) oai.storage=solr # The base URL of the OAI webapp (do not include the context e.g. /request, /openaire, etc). # Note: Comment out if you want to fallback to the request's URL. -oai.url = ${dspace.baseUrl}/oai +oai.url = ${dspace.baseUrl}/${oai.path} # Base solr index oai.solr.url=${solr.server}/oai From f89eebc71425f50c98c4bbe0f43a6f182b172107 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 21 Mar 2019 20:15:30 +0000 Subject: [PATCH 175/188] Dependency bug fix. Avoid pulling in Spring Boot logging & other unnecessary dependencies --- dspace-oai/pom.xml | 10 ++++++++-- dspace-rdf/pom.xml | 24 +++++++----------------- dspace-sword/pom.xml | 8 +++++++- dspace-swordv2/pom.xml | 8 +++++++- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index fd813b2e9c..8bbc89e0b8 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -111,8 +111,14 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + @@ -121,7 +127,7 @@ jtwig-spring-boot-starter ${jtwig.version} - + org.springframework.boot spring-boot-starter-web diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 080045de03..bcfd0ecb2f 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -61,26 +61,16 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + - - - javax.servlet javax.servlet-api diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 938e9dbb04..f9607c4a7f 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -77,8 +77,14 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 998ac3436b..4d457f2904 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -98,8 +98,14 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter ${spring-boot.version} + + + org.springframework.boot + spring-boot-starter-logging + + From efea77fb7d780480f3f9dc73b72079a432c45a97 Mon Sep 17 00:00:00 2001 From: Terry Brady Date: Wed, 27 Mar 2019 12:44:09 -0700 Subject: [PATCH 176/188] simplify dockerfile for onewebapp --- Dockerfile.jdk8 | 9 +- Dockerfile.jdk8-test | 13 +- Dockerfile.onewebapp.jdk8 | 57 ++++++ dspace/src/main/docker/test/solr_web.xml | 219 ----------------------- 4 files changed, 62 insertions(+), 236 deletions(-) create mode 100644 Dockerfile.onewebapp.jdk8 delete mode 100644 dspace/src/main/docker/test/solr_web.xml diff --git a/Dockerfile.jdk8 b/Dockerfile.jdk8 index afe2285f49..da07864c72 100644 --- a/Dockerfile.jdk8 +++ b/Dockerfile.jdk8 @@ -54,10 +54,5 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \ - ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ - ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \ - ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \ - ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \ - ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \ - ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2 +RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ + ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest diff --git a/Dockerfile.jdk8-test b/Dockerfile.jdk8-test index 01697a045c..0e3d0b7c8c 100644 --- a/Dockerfile.jdk8-test +++ b/Dockerfile.jdk8-test @@ -54,16 +54,9 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \ - ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ - ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \ - ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \ - ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \ - ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \ - ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2 +RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ + ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest -COPY dspace/src/main/docker/test/solr_web.xml $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml -RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml && \ - sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml +RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml diff --git a/Dockerfile.onewebapp.jdk8 b/Dockerfile.onewebapp.jdk8 new file mode 100644 index 0000000000..6cf44fafb2 --- /dev/null +++ b/Dockerfile.onewebapp.jdk8 @@ -0,0 +1,57 @@ +# This image will be published as dspace/dspace +# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details +# +# This version is JDK8 compatible +# - tomcat:8-jre8 +# - ANT 1.10.5 +# - maven:3-jdk-8 +# - note: +# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8 + +# Step 1 - Run Maven Build +FROM dspace/dspace-dependencies:dspace-7_x as build +ARG TARGET_DIR=dspace-installer +WORKDIR /app + +# The dspace-install directory will be written to /install +RUN mkdir /install \ + && chown -Rv dspace: /install \ + && chown -Rv dspace: /app + +USER dspace + +# Copy the DSpace source code into the workdir (excluding .dockerignore contents) +ADD --chown=dspace . /app/ +COPY dspace/src/main/docker/local.cfg /app/local.cfg + +# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small +RUN mvn package && \ + mv /app/dspace/target/${TARGET_DIR}/* /install && \ + mvn clean + +# Step 2 - Run Ant Deploy +FROM tomcat:8-jre8 as ant_build +ARG TARGET_DIR=dspace-installer +COPY --from=build /install /dspace-src +WORKDIR /dspace-src + +# Create the initial install deployment using ANT +ENV ANT_VERSION 1.10.5 +ENV ANT_HOME /tmp/ant-$ANT_VERSION +ENV PATH $ANT_HOME/bin:$PATH + +RUN mkdir $ANT_HOME && \ + wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME + +RUN ant init_installation update_configs update_code update_webapps update_solr_indexes + +# Step 3 - Run tomcat +# Create a new tomcat image that does not retain the the build directory contents +FROM tomcat:8-jre8 +ENV DSPACE_INSTALL=/dspace +COPY --from=ant_build /dspace $DSPACE_INSTALL +EXPOSE 8080 8009 + +ENV JAVA_OPTS=-Xmx2000m + +RUN ln -s $DSPACE_INSTALL/webapps/ROOT /usr/local/tomcat/webapps/spring-rest \ No newline at end of file diff --git a/dspace/src/main/docker/test/solr_web.xml b/dspace/src/main/docker/test/solr_web.xml deleted file mode 100644 index 50a8bd5b9a..0000000000 --- a/dspace/src/main/docker/test/solr_web.xml +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - Solr home: configuration, cores etc. - solr/home - ${dspace.dir}/solr - java.lang.String - - - - - - - URL locating a Log4J configuration file (properties or XML). - - log4jConfiguration - ${dspace.dir}/config/log4j-solr.xml - - - - org.apache.logging.log4j.web.Log4jServletContextListener - - - - Activate logging - log4jServletFilter - org.apache.logging.log4j.web.Log4jServletFilter - - - - - LocalHostRestrictionFilter - org.dspace.solr.filters.LocalHostRestrictionFilter - - - - - SolrRequestFilter - org.apache.solr.servlet.SolrDispatchFilter - - - - - - log4jServletFilter - /* - REQUEST - FORWARD - INCLUDE - ERROR - - - - - - - SolrRequestFilter - /* - - - - - - Zookeeper - org.apache.solr.servlet.ZookeeperInfoServlet - - - - LoadAdminUI - org.apache.solr.servlet.LoadAdminUiServlet - - - - - - RedirectOldAdminUI - org.apache.solr.servlet.RedirectServlet - - destination - ${context}/#/ - - - - - RedirectOldZookeeper - org.apache.solr.servlet.RedirectServlet - - destination - ${context}/zookeeper - - - - - RedirectLogging - org.apache.solr.servlet.RedirectServlet - - destination - ${context}/#/~logging - - - - - SolrRestApi - org.restlet.ext.servlet.ServerServlet - - org.restlet.application - org.apache.solr.rest.SolrRestApi - - - - - RedirectOldAdminUI - /admin/ - - - RedirectOldAdminUI - /admin - - - RedirectOldZookeeper - /zookeeper.jsp - - - RedirectLogging - /logging - - - - - Zookeeper - /zookeeper - - - - LoadAdminUI - /admin.html - - - - SolrRestApi - /schema/* - - - - .xsl - - application/xslt+xml - - - - admin.html - - - From 07029b9cafe53b5de8dab88e2e09a83a65417868 Mon Sep 17 00:00:00 2001 From: Terry Brady Date: Wed, 27 Mar 2019 14:19:16 -0700 Subject: [PATCH 177/188] fix ROOT ref --- Dockerfile.onewebapp.jdk8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.onewebapp.jdk8 b/Dockerfile.onewebapp.jdk8 index 6cf44fafb2..21ec706b50 100644 --- a/Dockerfile.onewebapp.jdk8 +++ b/Dockerfile.onewebapp.jdk8 @@ -54,4 +54,4 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/ROOT /usr/local/tomcat/webapps/spring-rest \ No newline at end of file +RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT \ No newline at end of file From 10b25af15830dce04ed8d4b026ce12908592fffb Mon Sep 17 00:00:00 2001 From: Terry Brady Date: Wed, 27 Mar 2019 16:09:09 -0700 Subject: [PATCH 178/188] handle root --- Dockerfile.onewebapp.jdk8 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile.onewebapp.jdk8 b/Dockerfile.onewebapp.jdk8 index 21ec706b50..096094fdc0 100644 --- a/Dockerfile.onewebapp.jdk8 +++ b/Dockerfile.onewebapp.jdk8 @@ -54,4 +54,5 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT \ No newline at end of file +RUN mv /usr/local/tomcat/ROOT /usr/local/tomcat/ROOT.bk && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT \ No newline at end of file From 4b942086765cc1284b40fa5ee7b896677e0ce1c2 Mon Sep 17 00:00:00 2001 From: Terry Brady Date: Wed, 27 Mar 2019 16:39:46 -0700 Subject: [PATCH 179/188] fix ROOT --- Dockerfile.onewebapp.jdk8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.onewebapp.jdk8 b/Dockerfile.onewebapp.jdk8 index 096094fdc0..5098525c61 100644 --- a/Dockerfile.onewebapp.jdk8 +++ b/Dockerfile.onewebapp.jdk8 @@ -54,5 +54,5 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN mv /usr/local/tomcat/ROOT /usr/local/tomcat/ROOT.bk && \ +RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \ ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT \ No newline at end of file From 7bf2d45d146d12c3e702d88108a447c0f349174e Mon Sep 17 00:00:00 2001 From: Terry Brady Date: Thu, 28 Mar 2019 11:47:00 -0700 Subject: [PATCH 180/188] simplify dockerfile overrides --- Dockerfile.jdk8 | 4 ++- Dockerfile.jdk8-test | 4 ++- Dockerfile.onewebapp.jdk8 | 58 --------------------------------------- 3 files changed, 6 insertions(+), 60 deletions(-) delete mode 100644 Dockerfile.onewebapp.jdk8 diff --git a/Dockerfile.jdk8 b/Dockerfile.jdk8 index da07864c72..b5c108d129 100644 --- a/Dockerfile.jdk8 +++ b/Dockerfile.jdk8 @@ -54,5 +54,7 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ +RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest diff --git a/Dockerfile.jdk8-test b/Dockerfile.jdk8-test index 0e3d0b7c8c..54ef4d105f 100644 --- a/Dockerfile.jdk8-test +++ b/Dockerfile.jdk8-test @@ -54,7 +54,9 @@ EXPOSE 8080 8009 ENV JAVA_OPTS=-Xmx2000m -RUN ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ +RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT && \ + ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \ ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml diff --git a/Dockerfile.onewebapp.jdk8 b/Dockerfile.onewebapp.jdk8 deleted file mode 100644 index 5098525c61..0000000000 --- a/Dockerfile.onewebapp.jdk8 +++ /dev/null @@ -1,58 +0,0 @@ -# This image will be published as dspace/dspace -# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details -# -# This version is JDK8 compatible -# - tomcat:8-jre8 -# - ANT 1.10.5 -# - maven:3-jdk-8 -# - note: -# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8 - -# Step 1 - Run Maven Build -FROM dspace/dspace-dependencies:dspace-7_x as build -ARG TARGET_DIR=dspace-installer -WORKDIR /app - -# The dspace-install directory will be written to /install -RUN mkdir /install \ - && chown -Rv dspace: /install \ - && chown -Rv dspace: /app - -USER dspace - -# Copy the DSpace source code into the workdir (excluding .dockerignore contents) -ADD --chown=dspace . /app/ -COPY dspace/src/main/docker/local.cfg /app/local.cfg - -# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small -RUN mvn package && \ - mv /app/dspace/target/${TARGET_DIR}/* /install && \ - mvn clean - -# Step 2 - Run Ant Deploy -FROM tomcat:8-jre8 as ant_build -ARG TARGET_DIR=dspace-installer -COPY --from=build /install /dspace-src -WORKDIR /dspace-src - -# Create the initial install deployment using ANT -ENV ANT_VERSION 1.10.5 -ENV ANT_HOME /tmp/ant-$ANT_VERSION -ENV PATH $ANT_HOME/bin:$PATH - -RUN mkdir $ANT_HOME && \ - wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME - -RUN ant init_installation update_configs update_code update_webapps update_solr_indexes - -# Step 3 - Run tomcat -# Create a new tomcat image that does not retain the the build directory contents -FROM tomcat:8-jre8 -ENV DSPACE_INSTALL=/dspace -COPY --from=ant_build /dspace $DSPACE_INSTALL -EXPOSE 8080 8009 - -ENV JAVA_OPTS=-Xmx2000m - -RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \ - ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/ROOT \ No newline at end of file From 11842b5485d7363e185d02315c4a361b308ce206 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 18 Apr 2019 15:20:01 -0500 Subject: [PATCH 181/188] Restore dependency that was accidentally removed --- dspace-oai/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 8bbc89e0b8..7771d37411 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -108,6 +108,13 @@ + + + javax.inject + javax.inject + 1 + + org.springframework.boot From 4d35e0fe286ded50621c3954628e3e7dbc84b7c4 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Thu, 9 May 2019 17:05:38 -0500 Subject: [PATCH 182/188] Exclude old version of Jena from SWORDv2 to resolve conflicts with RDF. Add note about upgrading Jena for future. --- dspace-swordv2/pom.xml | 5 +++++ pom.xml | 2 ++ 2 files changed, 7 insertions(+) diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 4d457f2904..d2896bed21 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -86,6 +86,11 @@ org.slf4j slf4j-log4j12 + + + com.hp.hpl.jena + jena + diff --git a/pom.xml b/pom.xml index 2a2905b9f2..fe79dd3ccc 100644 --- a/pom.xml +++ b/pom.xml @@ -26,6 +26,8 @@ 1.8 3.17 42.2.1 + 2.13.0 2.6.2 1.7.22 From 43444c84b74850b6f9f52a9e8e6ab66e3dd908e8 Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" Date: Wed, 15 May 2019 11:10:09 -0400 Subject: [PATCH 183/188] [DS-3658] Accept abollini's fix to configuration comments, with minor adjustments. --- dspace/config/modules/discovery.cfg | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/dspace/config/modules/discovery.cfg b/dspace/config/modules/discovery.cfg index 7ca1292069..aa38f4e1b2 100644 --- a/dspace/config/modules/discovery.cfg +++ b/dspace/config/modules/discovery.cfg @@ -18,14 +18,16 @@ discovery.search.server = ${solr.server}/search # index.ignore-authority = false discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued -# ONLY-FOR-JSPUI: -# 1) you need to set the DiscoverySearchRequestProcessor in the dspace.cfg +# ONLY-FOR-JSPUI: +# 1) you need to set the DiscoverySearchRequestProcessor in the dspace.cfg # 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection # Processors plugin in the dspace.cfg -# Allow auto-reindexing -# When enabled, if any database migrations are applied to your database (via Flyway), then a reindex flag -# is written to [dspace]/solr/search/conf/reindex.flag. Whenever the DSpace webapp is (re)started, it checks -# for the existence of that file. If found, a background reindex of all content is triggered in Discovery. +# Allow auto-reindexing. +# If any database migrations are applied to your database (via Flyway), then a +# reindex flag is always written to '[dspace]/solr/search/conf/reindex.flag'. +# Whenever the DSpace webapp is (re)started, it checks whether the autoReindex +# property is enabled AND that such a file exists. If the two conditions are +# satisfied, a background reindex of all content is triggered in Discovery. # Defaults to true: auto-reindexing is enabled. #discovery.autoReindex = true From d48aae5baad2b59c96215f08d85b3ebac3e1b3c3 Mon Sep 17 00:00:00 2001 From: "Mark H. Wood" Date: Wed, 15 May 2019 11:41:22 -0400 Subject: [PATCH 184/188] [DS-3658] Remove JSPUI comment mistakenly reintroduced by comment fix. --- dspace/config/modules/discovery.cfg | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/dspace/config/modules/discovery.cfg b/dspace/config/modules/discovery.cfg index 72ef59b2a7..a310182f10 100644 --- a/dspace/config/modules/discovery.cfg +++ b/dspace/config/modules/discovery.cfg @@ -18,11 +18,6 @@ discovery.search.server = ${solr.server}/search # discovery.index.ignore-authority = false discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued -# ONLY-FOR-JSPUI: -# 1) you need to set the DiscoverySearchRequestProcessor in the dspace.cfg -# 2) to show facet on Site/Community/etc. you need to add a Site/Community/Collection -# Processors plugin in the dspace.cfg - # Allow auto-reindexing. # If any database migrations are applied to your database (via Flyway), then a # reindex flag is always written to '[dspace]/solr/search/conf/reindex.flag'. @@ -34,9 +29,9 @@ discovery.index.projection=dc.title,dc.contributor.*,dc.date.issued # Value used for the namedresourcetype facet used by the mydspace # \n|||\n### -# the separator between the sort-value and the display-value \n|||\n must +# the separator between the sort-value and the display-value \n|||\n must # match the value of the discovery.solr.facets.split.char defined above -# the sort-value can be used to force a fixed order for the facet if it is +# the sort-value can be used to force a fixed order for the facet if it is # configured in the discovery.xml to be sorted by value discovery.facet.namedtype.item = 000item\n|||\nArchived###item discovery.facet.namedtype.workspace = 001workspace\n|||\nWorkspace###workspace From 7238f42cf4eb1851c8105e9f4451e005c272d497 Mon Sep 17 00:00:00 2001 From: Chris Wilper Date: Thu, 16 May 2019 16:35:30 -0400 Subject: [PATCH 185/188] DS-4253 Avoid oom during discovery reindex --- .../src/main/java/org/dspace/discovery/SolrServiceImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java index f0e26238ef..d22a0b1539 100644 --- a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java +++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceImpl.java @@ -34,8 +34,6 @@ import java.util.TimeZone; import java.util.UUID; import java.util.Vector; -import com.google.common.collect.ImmutableList; - import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.Transformer; @@ -473,7 +471,8 @@ public class SolrServiceImpl implements SearchService, IndexingService { switch (type) { case Constants.ITEM: Iterator items = itemService.findAllUnfiltered(context); - for (Item item : ImmutableList.copyOf(items)) { + while (items.hasNext()) { + Item item = items.next(); indexContent(context, item, force); //To prevent memory issues, discard an object from the cache after processing context.uncacheEntity(item); From 44e7b3aca63df351bbf3ec79068537f42a3baea4 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 17 May 2019 15:34:04 -0500 Subject: [PATCH 186/188] [maven-release-plugin] prepare release dspace-7.0-preview-1 --- dspace-api/pom.xml | 5 ++--- dspace-oai/pom.xml | 5 ++--- dspace-rdf/pom.xml | 5 ++--- dspace-rest/pom.xml | 7 +++---- dspace-services/pom.xml | 5 ++--- dspace-spring-rest/pom.xml | 5 ++--- dspace-sword/pom.xml | 5 ++--- dspace-swordv2/pom.xml | 5 ++--- dspace/modules/additions/pom.xml | 2 +- dspace/modules/oai/pom.xml | 2 +- dspace/modules/pom.xml | 2 +- dspace/modules/rdf/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/spring-rest/pom.xml | 2 +- dspace/modules/sword/pom.xml | 2 +- dspace/modules/swordv2/pom.xml | 2 +- dspace/pom.xml | 2 +- pom.xml | 30 +++++++++++++++--------------- 18 files changed, 41 insertions(+), 49 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 1a7326fa75..a4ac4c7db0 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 org.dspace dspace-api @@ -13,7 +12,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index 885c045227..e0f8f110b5 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 dspace-oai war @@ -9,7 +8,7 @@ dspace-parent org.dspace - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 9c6c154ddc..95dc7689a0 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 org.dspace dspace-rdf @@ -10,7 +9,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index 6d012d246a..1ccd8236d9 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -1,10 +1,9 @@ - + 4.0.0 org.dspace dspace-rest war - 7.0-SNAPSHOT + 7.0-preview-1 DSpace REST :: API and Implementation DSpace RESTful Web Services API http://demo.dspace.org @@ -12,7 +11,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index e402bed92b..eaefb118ad 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 org.dspace dspace-services @@ -10,7 +9,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index 0c904bfe60..e9df667fd6 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 org.dspace dspace-spring-rest @@ -16,7 +15,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 63f149e01f..16b1a5a042 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 org.dspace dspace-sword @@ -16,7 +15,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 6ac1a15b5d..1aa26c2edc 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -1,5 +1,4 @@ - + 4.0.0 org.dspace dspace-swordv2 @@ -14,7 +13,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index d02b33a8b9..1d5b9edd02 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/oai/pom.xml b/dspace/modules/oai/pom.xml index e36adfafcc..efffe569d1 100644 --- a/dspace/modules/oai/pom.xml +++ b/dspace/modules/oai/pom.xml @@ -12,7 +12,7 @@ modules org.dspace - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index 0b28d4e62a..948f91bb07 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 ../../pom.xml diff --git a/dspace/modules/rdf/pom.xml b/dspace/modules/rdf/pom.xml index 297d165a6d..3f9d33a865 100644 --- a/dspace/modules/rdf/pom.xml +++ b/dspace/modules/rdf/pom.xml @@ -11,7 +11,7 @@ modules org.dspace - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index 4b9c4a2a24..01b75046f6 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -12,7 +12,7 @@ org.dspace modules - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/spring-rest/pom.xml b/dspace/modules/spring-rest/pom.xml index b8d834a3f8..7482950fa8 100644 --- a/dspace/modules/spring-rest/pom.xml +++ b/dspace/modules/spring-rest/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/sword/pom.xml b/dspace/modules/sword/pom.xml index a8498483ce..470047c363 100644 --- a/dspace/modules/sword/pom.xml +++ b/dspace/modules/sword/pom.xml @@ -16,7 +16,7 @@ org.dspace modules - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/modules/swordv2/pom.xml b/dspace/modules/swordv2/pom.xml index 11f0b684b5..015718bf5f 100644 --- a/dspace/modules/swordv2/pom.xml +++ b/dspace/modules/swordv2/pom.xml @@ -16,7 +16,7 @@ org.dspace modules - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/dspace/pom.xml b/dspace/pom.xml index 5961bf9a1c..55f8051949 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.0-SNAPSHOT + 7.0-preview-1 .. diff --git a/pom.xml b/pom.xml index a06a94dfa6..748becdeab 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.0-SNAPSHOT + 7.0-preview-1 DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -929,81 +929,81 @@ org.dspace dspace-api - 7.0-SNAPSHOT + 7.0-preview-1 org.dspace.modules additions - 7.0-SNAPSHOT + 7.0-preview-1 org.dspace dspace-sword - 7.0-SNAPSHOT + 7.0-preview-1 jar classes org.dspace dspace-sword - 7.0-SNAPSHOT + 7.0-preview-1 war org.dspace dspace-swordv2 - 7.0-SNAPSHOT + 7.0-preview-1 jar classes org.dspace dspace-swordv2 - 7.0-SNAPSHOT + 7.0-preview-1 war org.dspace dspace-oai - 7.0-SNAPSHOT + 7.0-preview-1 jar classes org.dspace dspace-oai - 7.0-SNAPSHOT + 7.0-preview-1 war org.dspace dspace-services - 7.0-SNAPSHOT + 7.0-preview-1 org.dspace dspace-rdf - 7.0-SNAPSHOT + 7.0-preview-1 war org.dspace dspace-rest - 7.0-SNAPSHOT + 7.0-preview-1 jar classes org.dspace dspace-rest - 7.0-SNAPSHOT + 7.0-preview-1 war org.dspace dspace-spring-rest - 7.0-SNAPSHOT + 7.0-preview-1 war @@ -1677,7 +1677,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - HEAD + dspace-7.0-preview-1 From aebd0f9ce6e0e92c41d0327407cbf8f33508c7de Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 17 May 2019 15:34:13 -0500 Subject: [PATCH 187/188] [maven-release-plugin] prepare for next development iteration --- dspace-api/pom.xml | 2 +- dspace-oai/pom.xml | 2 +- dspace-rdf/pom.xml | 2 +- dspace-rest/pom.xml | 4 ++-- dspace-services/pom.xml | 2 +- dspace-spring-rest/pom.xml | 2 +- dspace-sword/pom.xml | 2 +- dspace-swordv2/pom.xml | 2 +- dspace/modules/additions/pom.xml | 2 +- dspace/modules/oai/pom.xml | 2 +- dspace/modules/pom.xml | 2 +- dspace/modules/rdf/pom.xml | 2 +- dspace/modules/rest/pom.xml | 2 +- dspace/modules/spring-rest/pom.xml | 2 +- dspace/modules/sword/pom.xml | 2 +- dspace/modules/swordv2/pom.xml | 2 +- dspace/pom.xml | 2 +- pom.xml | 30 +++++++++++++++--------------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index a4ac4c7db0..4298cfd21e 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -12,7 +12,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-oai/pom.xml b/dspace-oai/pom.xml index e0f8f110b5..1fa6631274 100644 --- a/dspace-oai/pom.xml +++ b/dspace-oai/pom.xml @@ -8,7 +8,7 @@ dspace-parent org.dspace - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-rdf/pom.xml b/dspace-rdf/pom.xml index 95dc7689a0..1d5c68ab91 100644 --- a/dspace-rdf/pom.xml +++ b/dspace-rdf/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml index 1ccd8236d9..4e5f898032 100644 --- a/dspace-rest/pom.xml +++ b/dspace-rest/pom.xml @@ -3,7 +3,7 @@ org.dspace dspace-rest war - 7.0-preview-1 + 7.0-SNAPSHOT DSpace REST :: API and Implementation DSpace RESTful Web Services API http://demo.dspace.org @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-services/pom.xml b/dspace-services/pom.xml index eaefb118ad..f85d9d3e29 100644 --- a/dspace-services/pom.xml +++ b/dspace-services/pom.xml @@ -9,7 +9,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml index e9df667fd6..5862b50a8e 100644 --- a/dspace-spring-rest/pom.xml +++ b/dspace-spring-rest/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-sword/pom.xml b/dspace-sword/pom.xml index 16b1a5a042..b784452af6 100644 --- a/dspace-sword/pom.xml +++ b/dspace-sword/pom.xml @@ -15,7 +15,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace-swordv2/pom.xml b/dspace-swordv2/pom.xml index 1aa26c2edc..8957b9a49d 100644 --- a/dspace-swordv2/pom.xml +++ b/dspace-swordv2/pom.xml @@ -13,7 +13,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/additions/pom.xml b/dspace/modules/additions/pom.xml index 1d5b9edd02..d02b33a8b9 100644 --- a/dspace/modules/additions/pom.xml +++ b/dspace/modules/additions/pom.xml @@ -17,7 +17,7 @@ org.dspace modules - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/oai/pom.xml b/dspace/modules/oai/pom.xml index efffe569d1..e36adfafcc 100644 --- a/dspace/modules/oai/pom.xml +++ b/dspace/modules/oai/pom.xml @@ -12,7 +12,7 @@ modules org.dspace - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/pom.xml b/dspace/modules/pom.xml index 948f91bb07..0b28d4e62a 100644 --- a/dspace/modules/pom.xml +++ b/dspace/modules/pom.xml @@ -11,7 +11,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT ../../pom.xml diff --git a/dspace/modules/rdf/pom.xml b/dspace/modules/rdf/pom.xml index 3f9d33a865..297d165a6d 100644 --- a/dspace/modules/rdf/pom.xml +++ b/dspace/modules/rdf/pom.xml @@ -11,7 +11,7 @@ modules org.dspace - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/rest/pom.xml b/dspace/modules/rest/pom.xml index 01b75046f6..4b9c4a2a24 100644 --- a/dspace/modules/rest/pom.xml +++ b/dspace/modules/rest/pom.xml @@ -12,7 +12,7 @@ org.dspace modules - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/spring-rest/pom.xml b/dspace/modules/spring-rest/pom.xml index 7482950fa8..b8d834a3f8 100644 --- a/dspace/modules/spring-rest/pom.xml +++ b/dspace/modules/spring-rest/pom.xml @@ -13,7 +13,7 @@ just adding new jar in the classloader modules org.dspace - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/sword/pom.xml b/dspace/modules/sword/pom.xml index 470047c363..a8498483ce 100644 --- a/dspace/modules/sword/pom.xml +++ b/dspace/modules/sword/pom.xml @@ -16,7 +16,7 @@ org.dspace modules - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/modules/swordv2/pom.xml b/dspace/modules/swordv2/pom.xml index 015718bf5f..11f0b684b5 100644 --- a/dspace/modules/swordv2/pom.xml +++ b/dspace/modules/swordv2/pom.xml @@ -16,7 +16,7 @@ org.dspace modules - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/dspace/pom.xml b/dspace/pom.xml index 55f8051949..5961bf9a1c 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -16,7 +16,7 @@ org.dspace dspace-parent - 7.0-preview-1 + 7.0-SNAPSHOT .. diff --git a/pom.xml b/pom.xml index 748becdeab..a06a94dfa6 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.dspace dspace-parent pom - 7.0-preview-1 + 7.0-SNAPSHOT DSpace Parent Project DSpace open source software is a turnkey institutional repository application. @@ -929,81 +929,81 @@ org.dspace dspace-api - 7.0-preview-1 + 7.0-SNAPSHOT org.dspace.modules additions - 7.0-preview-1 + 7.0-SNAPSHOT org.dspace dspace-sword - 7.0-preview-1 + 7.0-SNAPSHOT jar classes org.dspace dspace-sword - 7.0-preview-1 + 7.0-SNAPSHOT war org.dspace dspace-swordv2 - 7.0-preview-1 + 7.0-SNAPSHOT jar classes org.dspace dspace-swordv2 - 7.0-preview-1 + 7.0-SNAPSHOT war org.dspace dspace-oai - 7.0-preview-1 + 7.0-SNAPSHOT jar classes org.dspace dspace-oai - 7.0-preview-1 + 7.0-SNAPSHOT war org.dspace dspace-services - 7.0-preview-1 + 7.0-SNAPSHOT org.dspace dspace-rdf - 7.0-preview-1 + 7.0-SNAPSHOT war org.dspace dspace-rest - 7.0-preview-1 + 7.0-SNAPSHOT jar classes org.dspace dspace-rest - 7.0-preview-1 + 7.0-SNAPSHOT war org.dspace dspace-spring-rest - 7.0-preview-1 + 7.0-SNAPSHOT war @@ -1677,7 +1677,7 @@ scm:git:git@github.com:DSpace/DSpace.git scm:git:git@github.com:DSpace/DSpace.git git@github.com:DSpace/DSpace.git - dspace-7.0-preview-1 + HEAD From 81040975ed67b8a594b2b33a4e003a2090f7e15f Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 21 May 2019 12:15:37 -0500 Subject: [PATCH 188/188] Convert Mock into a Spy of currently loaded bean --- .../src/test/java/org/dspace/app/oai/OAIpmhIT.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java index 57590f8166..3975d072ce 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/oai/OAIpmhIT.java @@ -40,7 +40,6 @@ import org.dspace.xoai.services.api.xoai.DSpaceFilterResolver; import org.junit.Assume; import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; @@ -71,13 +70,14 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { @MockBean private XOAICacheService xoaiCacheService; - // Mock for date-based testing below - @Mock + // Spy on the current EarliestDateResolver bean, to allow us to change behavior in tests below + @SpyBean private EarliestDateResolver earliestDateResolver; + // XOAI's BaseDateProvider (used for date-based testing below) private static BaseDateProvider baseDateProvider = new BaseDateProvider(); - // Spy on the current XOAIManagerResolver, to allow us to change behavior of XOAIManager in tests + // Spy on the current XOAIManagerResolver bean, to allow us to change behavior of XOAIManager in tests // See also: createMockXOAIManager() method @SpyBean private XOAIManagerResolver xoaiManagerResolver; @@ -142,9 +142,10 @@ public class OAIpmhIT extends AbstractControllerIntegrationTest { @Test public void requestForIdentifyShouldReturnTheConfiguredValues() throws Exception { - // Mock EarliestDateResolver to return now for getEarliestDate() + // Get current date/time and store as "now" Date now = new Date(); - when(earliestDateResolver.getEarliestDate(context)).thenReturn(now); + // Return "now" when "getEarliestDate()" is called for the currently loaded EarliestDateResolver bean + doReturn(now).when(earliestDateResolver).getEarliestDate(context); // Attempt to make an Identify request to root context getClient().perform(get(DEFAULT_CONTEXT).param("verb", "Identify"))