From d77dd7fa4f3e06463ae8e7b1590997091e8b10f5 Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Wed, 21 Nov 2018 15:20:32 +0100
Subject: [PATCH 01/68] Added support for the CRUD operations on the Collection
and Community REST endpoints
---
.../app/rest/RestResourceController.java | 26 ++
.../rest/converter/CollectionConverter.java | 5 +
.../rest/converter/CommunityConverter.java | 8 +-
.../dspace/app/rest/model/CollectionRest.java | 13 +
.../dspace/app/rest/model/CommunityRest.java | 10 +
.../repository/CollectionRestRepository.java | 115 +++++++
.../repository/CommunityRestRepository.java | 67 ++++-
.../rest/repository/DSpaceRestRepository.java | 16 +
.../app/rest/utils/DSpaceObjectUtils.java | 43 +++
.../app/rest/CollectionRestRepositoryIT.java | 283 +++++++++++++++++-
.../app/rest/CommunityRestRepositoryIT.java | 253 ++++++++++++++++
.../rest/WorkspaceItemRestRepositoryIT.java | 41 +--
.../app/rest/matcher/CollectionMatcher.java | 10 +-
.../app/rest/matcher/CommunityMatcher.java | 8 +-
14 files changed, 859 insertions(+), 39 deletions(-)
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectUtils.java
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 9e5c339455..74775a9314 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,30 @@ public class RestResourceController implements InitializingBean {
repository.delete(id);
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
}
+
+
+
+ @RequestMapping(method = RequestMethod.PUT, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
+ public DSpaceResource put(HttpServletRequest request,
+ @PathVariable String apiCategory, @PathVariable String model,
+ @PathVariable UUID uuid,
+ @RequestBody(required = true) JsonNode jsonNode) {
+ return putOneInternal(request, apiCategory, model, uuid, jsonNode);
+ }
+
+ private DSpaceResource putOneInternal(HttpServletRequest request,
+ String apiCategory,
+ String model, ID uuid,
+ JsonNode jsonNode) {
+ checkModelPluralForm(apiCategory, model);
+ DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model);
+ RestAddressableModel modelObject = null;
+ modelObject = repository.put(request, apiCategory, model, uuid, jsonNode);
+ if (modelObject == null) {
+ throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " 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/CollectionConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
index a4c368d2b4..d3d641510f 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
@@ -66,6 +66,11 @@ public class CollectionConverter
col.setDefaultAccessConditions(getDefaultBitstreamPoliciesForCollection(obj.getID()));
+ try {
+ col.setOwningCommunity(obj.getCommunities().get(0).getID().toString());
+ } catch (SQLException e) {
+ log.error(e.getMessage(), e);
+ }
return col;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
index b1883ccff0..edb4528482 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
@@ -64,7 +64,13 @@ public class CommunityConverter
}
}
com.setSubCommunities(communityRest);
-
+ List parentCommunities = obj.getParentCommunities();
+ if (parentCommunities.size() > 0) {
+ Community parentCommunity = parentCommunities.get(0);
+ if (parentCommunity != null) {
+ com.setOwningCommunity(parentCommunity.getID().toString());
+ }
+ }
return com;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
index f5dde2c043..cc55ef3f55 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
@@ -10,6 +10,7 @@ package org.dspace.app.rest.model;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
/**
* The Collection REST Resource
@@ -28,6 +29,8 @@ public class CollectionRest extends DSpaceObjectRest {
@JsonIgnore
private BitstreamRest logo;
+ private String owningCommunity;
+
@JsonIgnore
private List defaultAccessConditions;
@@ -45,6 +48,7 @@ public class CollectionRest extends DSpaceObjectRest {
}
@Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
@@ -58,4 +62,13 @@ public class CollectionRest extends DSpaceObjectRest {
public void setDefaultAccessConditions(List defaultAccessConditions) {
this.defaultAccessConditions = defaultAccessConditions;
}
+
+ public String getOwningCommunity() {
+ return owningCommunity;
+ }
+
+ public void setOwningCommunity(String owningCommunity) {
+ this.owningCommunity = owningCommunity;
+ }
+
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
index 19d3decaee..53b9f1333c 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
@@ -24,6 +24,16 @@ public class CommunityRest extends DSpaceObjectRest {
@JsonIgnore
private BitstreamRest logo;
+ private String owningCommunity;
+
+ public String getOwningCommunity() {
+ return owningCommunity;
+ }
+
+ public void setOwningCommunity(String owningCommunity) {
+ this.owningCommunity = owningCommunity;
+ }
+
private List collections;
@LinkRest(linkClass = CollectionRest.class)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 66474c6029..2c0b9bf44a 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -7,23 +7,38 @@
*/
package org.dspace.app.rest.repository;
+import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.BadRequestException;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.CollectionConverter;
+import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
+import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.CommunityRest;
+import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
+import org.dspace.app.rest.utils.DSpaceObjectUtils;
+import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
+import org.dspace.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -41,6 +56,8 @@ import org.springframework.stereotype.Component;
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
public class CollectionRestRepository extends DSpaceRestRepository {
+ private static final Logger log = Logger.getLogger(CollectionRestRepository.class);
+
@Autowired
CommunityService communityService;
@@ -50,6 +67,9 @@ public class CollectionRestRepository extends DSpaceRestRepository metadataEntryRestList = collectionRest.getMetadata();
+ collection = (Collection) dspaceObjectUtils.replaceMetadataValues(context,
+ collection,
+ metadataEntryRestList);
+ } else {
+ throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
+ + id + ", "
+ + collectionRest.getId());
+ }
+ return converter.fromModel(collection);
+ }
+ @Override
+ @PreAuthorize("hasAuthority('ADMIN')")
+ protected void delete(Context context, UUID id) throws AuthorizeException {
+ Collection collection = null;
+ try {
+ collection = cs.find(context, id);
+ if (collection == null) {
+ throw new ResourceNotFoundException(
+ CollectionRest.CATEGORY + "." + CollectionRest.NAME + " with id: " + id + " not found");
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ try {
+ cs.delete(context, collection);
+ } catch (SQLException | IOException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
index dc20cd945f..f81630ae9f 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
@@ -15,19 +15,26 @@ import java.util.UUID;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.BadRequestException;
+import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.CommunityConverter;
+import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CommunityResource;
+import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
+import org.dspace.util.UUIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
@@ -51,6 +58,9 @@ public class CommunityRestRepository extends DSpaceRestRepository metadataEntryRestList = communityRest.getMetadata();
+ community = (Community) dspaceObjectUtils.replaceMetadataValues(context, community, metadataEntryRestList);
+ } else {
+ throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
+ + id + ", "
+ + communityRest.getId());
+ }
+ return converter.fromModel(community);
+ }
+ @Override
+ @PreAuthorize("hasAuthority('ADMIN')")
+ protected void delete(Context context, UUID id) throws AuthorizeException {
+ Community community = null;
+ try {
+ community = cs.find(context, id);
+ if (community == null) {
+ throw new ResourceNotFoundException(
+ CommunityRest.CATEGORY + "." + CommunityRest.NAME + " with id: " + id + " not found");
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ try {
+ cs.delete(context, community);
+ } catch (SQLException | IOException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
}
\ 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 5248cf024f..4be7596ad4 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.logging.log4j.Logger;
import org.dspace.app.rest.exception.PatchBadRequestException;
import org.dspace.app.rest.exception.RESTAuthorizationException;
@@ -406,5 +407,20 @@ public abstract class DSpaceRestRepository metadataEntryRestList)
+ throws SQLException, AuthorizeException {
+ DSpaceObjectService dSpaceObjectService = contentServiceFactory.getDSpaceObjectService(dSpaceObject);
+ dSpaceObjectService.clearMetadata(context, dSpaceObject, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
+ for (MetadataEntryRest mer : metadataEntryRestList) {
+ String[] metadatakey = mer.getKey().split("\\.");
+ dSpaceObjectService.addMetadata(context, dSpaceObject, metadatakey[0], metadatakey[1],
+ metadatakey.length == 3 ? metadatakey[2] : null, mer.getLanguage(), mer.getValue());
+ }
+ dSpaceObjectService.update(context, dSpaceObject);
+ return dSpaceObject;
+ }
+}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index e9de5c69d6..d9f17406e5 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -7,22 +7,34 @@
*/
package org.dspace.app.rest;
+import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+import java.util.Arrays;
import java.util.UUID;
+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.matcher.CollectionMatcher;
+import org.dspace.app.rest.matcher.CommunityMetadataMatcher;
+import org.dspace.app.rest.model.CollectionRest;
+import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.hamcrest.Matchers;
import org.junit.Test;
+import org.springframework.http.MediaType;
public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTest {
@@ -51,8 +63,10 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.containsInAnyOrder(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()),
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID()),
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col2.getCommunities().get(0).getID())
)));
}
@@ -81,11 +95,13 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
)))
.andExpect(jsonPath("$._embedded.collections", Matchers.not(
Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col1.getCommunities().get(0).getID())
)
)));
@@ -95,11 +111,13 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col2.getCommunities().get(0).getID())
)))
.andExpect(jsonPath("$._embedded.collections", Matchers.not(
Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
)
)));
}
@@ -129,11 +147,13 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
)))
.andExpect(jsonPath("$", Matchers.not(
is(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col1.getCommunities().get(0).getID())
))));
}
@@ -161,11 +181,13 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
)))
.andExpect(jsonPath("$", Matchers.not(
is(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col1.getCommunities().get(0).getID())
)))
)
;
@@ -276,4 +298,245 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isNotFound());
}
+ @Test
+ public void findCollectionWithOwningCommunity() throws Exception {
+
+ //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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .build();
+ Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community")
+ .build();
+ Community child2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community Two")
+ .build();
+ Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build();
+ Collection col2 = CollectionBuilder.createCollection(context, child2).withName("Collection 2").build();
+
+ getClient().perform(get("/api/core/collections/" + col1.getID()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", is(
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
+ )))
+ .andExpect(jsonPath("$", Matchers.not(
+ is(
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
+ col1.getCommunities().get(0).getID())
+ ))));
+ }
+
+ @Test
+ public void updateTest() throws Exception {
+ //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.
+ 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();
+
+ getClient().perform(get("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
+ )))
+ .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/collections")))
+ ;
+
+ String token = getAuthToken(admin.getEmail(), password);
+
+ getClient(token).perform(put("/api/core/collections/" + col1.getID().toString())
+ .contentType(MediaType.APPLICATION_JSON).content(
+ "{\"id\": \"" + col1.getID() + "\",\"uuid\": " +
+ "\"" + col1.getID() + "\",\"name\": \"Electronic theses and " +
+ "dissertations (ETD)\",\"handle\": \"" + col1.getHandle() + "\",\"metadata\": " +
+ "[{\"key\": \"dc.description.abstract\",\"value\": \"\",\"language\": null}," +
+ "{\"key\": \"dc.title\",\"value\": \"Electronic theses and dissertations " +
+ "(ETD)\",\"language\": null}], \"owningCommunity\": \"" +
+ child1.getID() + "\",\"type\": \"collection\"}"
+ ))
+ .andExpect(status().isOk())
+ ;
+
+ getClient().perform(get("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CollectionMatcher.matchCollectionEntry("Electronic theses and dissertations (ETD)",
+ col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
+ )))
+ .andExpect(jsonPath("$._links.self.href",
+ Matchers.containsString("/api/core/collections")))
+ ;
+ }
+
+ @Test
+ public void deleteTest() throws Exception {
+ //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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .withLogo("ThisIsSomeDummyText")
+ .build();
+
+ Community parentCommunity2 = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community 2")
+ .withLogo("SomeTest")
+ .build();
+
+ Community parentCommunityChild1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community")
+ .build();
+
+ Collection col1 = CollectionBuilder.createCollection(context, parentCommunityChild1)
+ .withName("Collection 1")
+ .build();
+
+ String token = getAuthToken(admin.getEmail(), password);
+
+ getClient(token).perform(get("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
+ )))
+ .andExpect(jsonPath("$._links.self.href",
+ Matchers.containsString("/api/core/collections"))) ;
+ getClient(token).perform(delete("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isNoContent())
+ ;
+ getClient(token).perform(get("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isNotFound())
+ ;
+ }
+
+ @Test
+ public void deleteTestUnAuthorized() throws Exception {
+ //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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .withLogo("ThisIsSomeDummyText")
+ .build();
+
+ Community parentCommunity2 = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community 2")
+ .withLogo("SomeTest")
+ .build();
+
+ Community parentCommunityChild1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community")
+ .build();
+
+ Collection col1 = CollectionBuilder.createCollection(context, parentCommunityChild1)
+ .withName("Collection 1")
+ .build();
+
+ getClient().perform(get("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID())
+ )))
+ .andExpect(jsonPath("$._links.self.href",
+ Matchers.containsString("/api/core/collections"))) ;
+ getClient().perform(delete("/api/core/collections/" + col1.getID().toString()))
+ .andExpect(status().isUnauthorized())
+ ;
+ }
+
+ @Test
+ public void createTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+
+ //** GIVEN **
+ //1. A community-collection structure with one parent community with sub-community and one collection.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .withLogo("ThisIsSomeDummyText")
+ .build();
+
+ ObjectMapper mapper = new ObjectMapper();
+ CollectionRest collectionRest = new CollectionRest();
+ // We send a name but the created collection should set this to the title
+ collectionRest.setName("Collection");
+ collectionRest.setOwningCommunity(parentCommunity.getID().toString());
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample top-level community created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ collectionRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+
+ String authToken = getAuthToken(admin.getEmail(), password);
+ getClient(authToken).perform(post("/api/core/collections")
+ .content(mapper.writeValueAsBytes(collectionRest))
+ .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("$.owningCommunity", is(collectionRest.getOwningCommunity())),
+ hasJsonPath("$.type", is("collection")),
+ hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
+ CommunityMetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ CommunityMetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample top-level community " +
+ "created via the REST API"),
+ CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ CommunityMetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ CommunityMetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
+ )))));
+
+ }
}
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 d1f77fcdd1..55e2cecc48 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
@@ -10,9 +10,12 @@ package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -33,6 +36,7 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.hamcrest.Matchers;
import org.junit.Test;
+import org.springframework.http.MediaType;
public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest {
@@ -82,6 +86,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
hasJsonPath("$.uuid", not(empty())),
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
+ hasJsonPath("$.owningCommunity", isEmptyOrNullString()),
hasJsonPath("$.type", is("community")),
hasJsonPath("$._links.collections.href", not(empty())),
hasJsonPath("$._links.logo.href", not(empty())),
@@ -101,6 +106,84 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
)))));
}
+ @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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .build();
+
+ ObjectMapper mapper = new ObjectMapper();
+ CommunityRest comm = new CommunityRest();
+ // We send a name but the created community should set this to the title
+ comm.setName("Test Sub-Level Community");
+ comm.setOwningCommunity(parentCommunity.getID().toString());
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample top-level community created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ comm.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+ String authToken = getAuthToken(admin.getEmail(), password);
+ 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("$.owningCommunity", is(parentCommunity.getID().toString())),
+ 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.containsInAnyOrder(
+ CommunityMetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ CommunityMetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample top-level community " +
+ "created via the REST API"),
+ CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ CommunityMetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ CommunityMetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
+ )))));
+
+
+
+ }
+
@Test
public void createUnauthorizedTest() throws Exception {
@@ -511,4 +594,174 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
getClient().perform(get("/api/core/communities/" + UUID.randomUUID())).andExpect(status().isNotFound());
}
+
+ @Test
+ public void updateTest() throws Exception {
+ //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.
+ 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();
+
+ getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(),
+ parentCommunity.getHandle())
+ )))
+ .andExpect(jsonPath("$", Matchers.not(
+ Matchers.is(
+ CommunityMatcher.matchCommunityEntry(child1.getName(), child1.getID(), child1.getHandle())
+ )
+ )))
+ .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities")))
+ ;
+
+ String token = getAuthToken(admin.getEmail(), password);
+
+ getClient(token).perform(put("/api/core/communities/" + parentCommunity.getID().toString())
+ .contentType(MediaType.APPLICATION_JSON).content(
+ "{\"id\": \"" + parentCommunity.getID() + "\",\"uuid\": " +
+ "\"" + parentCommunity.getID() + "\",\"name\": \"Electronic theses and " +
+ "dissertations (ETD)\",\"handle\": \"123456789/5286\",\"metadata\": " +
+ "[{\"key\": \"dc.description.abstract\",\"value\": \"\",\"language\": null}," +
+ "{\"key\": \"dc.title\",\"value\": \"Electronic theses and dissertations " +
+ "(ETD)\",\"language\": null}],\"type\": \"community\"}"
+ ))
+ .andExpect(status().isOk())
+ ;
+
+ getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CommunityMatcher.matchCommunityEntry("Electronic theses and dissertations (ETD)",
+ parentCommunity.getID(),
+ parentCommunity.getHandle())
+ )))
+ .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/communities")))
+ ;
+ }
+
+ @Test
+ public void deleteTest() throws Exception {
+ //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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .withLogo("ThisIsSomeDummyText")
+ .build();
+
+ Community parentCommunity2 = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community 2")
+ .withLogo("SomeTest")
+ .build();
+
+ Community parentCommunityChild1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community")
+ .build();
+
+ Community parentCommunityChild2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community2")
+ .build();
+
+ Community parentCommunityChild2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunityChild2)
+ .withName("Sub Sub Community")
+ .build();
+
+
+ Community parentCommunity2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunity2)
+ .withName("Sub2 Community")
+ .build();
+
+ Collection col1 = CollectionBuilder.createCollection(context, parentCommunityChild1)
+ .withName("Collection 1")
+ .build();
+
+ String token = getAuthToken(admin.getEmail(), password);
+
+ getClient(token).perform(get("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(),
+ parentCommunity.getHandle())
+ )))
+ .andExpect(jsonPath("$._links.self.href",
+ Matchers.containsString("/api/core/communities"))) ;
+ getClient(token).perform(delete("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isNoContent())
+ ;
+ getClient(token).perform(get("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isNotFound())
+ ;
+
+ getClient(token).perform(get("/api/core/communities/" + parentCommunityChild1.getID().toString()))
+ .andExpect(status().isNotFound())
+ ;
+ }
+
+ @Test
+ public void deleteTestUnAuthorized() throws Exception {
+ //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.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .withLogo("ThisIsSomeDummyText")
+ .build();
+
+ Community parentCommunity2 = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community 2")
+ .withLogo("SomeTest")
+ .build();
+
+ Community parentCommunityChild1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community")
+ .build();
+
+ Community parentCommunityChild2 = CommunityBuilder.createSubCommunity(context, parentCommunity)
+ .withName("Sub Community2")
+ .build();
+
+ Community parentCommunityChild2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunityChild2)
+ .withName("Sub Sub Community")
+ .build();
+
+
+ Community parentCommunity2Child1 = CommunityBuilder.createSubCommunity(context, parentCommunity2)
+ .withName("Sub2 Community")
+ .build();
+
+ Collection col1 = CollectionBuilder.createCollection(context, parentCommunityChild1)
+ .withName("Collection 1")
+ .build();
+
+
+ getClient().perform(get("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$", Matchers.is(
+ CommunityMatcher.matchCommunityEntry(parentCommunity.getName(), parentCommunity.getID(),
+ parentCommunity.getHandle())
+ )))
+ .andExpect(jsonPath("$._links.self.href",
+ Matchers.containsString("/api/core/communities"))) ;
+ getClient().perform(delete("/api/core/communities/" + parentCommunity.getID().toString()))
+ .andExpect(status().isUnauthorized())
+ ;
+ }
}
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..f9643bf1e5 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
@@ -61,7 +61,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* All the workspaceitem should be returned regardless of the collection where they were created
- *
+ *
* @throws Exception
*/
public void findAllTest() throws Exception {
@@ -114,7 +114,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* The workspaceitem endpoint must provide proper pagination
- *
+ *
* @throws Exception
*/
public void findAllWithPaginationTest() throws Exception {
@@ -179,7 +179,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* The workspaceitem resource endpoint must expose the proper structure
- *
+ *
* @throws Exception
*/
public void findOneTest() throws Exception {
@@ -212,7 +212,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* The workspaceitem resource endpoint must expose the proper structure
- *
+ *
* @throws Exception
*/
public void findOneRelsTest() throws Exception {
@@ -239,7 +239,8 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/collection"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers
- .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()))));
+ .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
+ col1.getCommunities().get(0).getID()))));
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/item")).andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemWithTitleAndDateIssued(witem.getItem(),
@@ -254,7 +255,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Check the response code for unexistent workspaceitem
- *
+ *
* @throws Exception
*/
public void findOneWrongUUIDTest() throws Exception {
@@ -267,7 +268,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Removing a workspaceitem should result in delete of all the underline resources (item and bitstreams)
- *
+ *
* @throws Exception
*/
public void deleteOneTest() throws Exception {
@@ -321,7 +322,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
/**
* Create three workspaceitem with two different submitter and verify that the findBySubmitter return the proper
* list of workspaceitem for each submitter also paginating
- *
+ *
* @throws Exception
*/
public void findBySubmitterTest() throws Exception {
@@ -424,7 +425,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
/**
* Test the creation of workspaceitem POSTing to the resource collection endpoint. It should respect the collection
* param if present or use a default if it is not used
- *
+ *
* @throws Exception
*/
public void createEmptyWorkspateItemTest() throws Exception {
@@ -466,7 +467,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file
- *
+ *
* @throws Exception
*/
public void createMultipleWorkspaceItemFromFileTest() throws Exception {
@@ -538,7 +539,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
/**
* Test the creation of a workspaceitem POSTing to the resource collection endpoint a PDF file. As a single item
* will be created we expect to have the pdf file stored as a bitstream
- *
+ *
* @throws Exception
*/
public void createWorkspaceItemFromPDFFileTest() throws Exception {
@@ -585,7 +586,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
/**
* Test the exposition of validation error for missing required metadata both at the creation time than on existent
* workspaceitems
- *
+ *
* @throws Exception
*/
public void validationErrorsRequiredMetadataTest() throws Exception {
@@ -646,7 +647,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the update of metadata
- *
+ *
* @throws Exception
*/
public void patchUpdateMetadataTest() throws Exception {
@@ -703,7 +704,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test delete of a metadata
- *
+ *
* @throws Exception
*/
public void patchDeleteMetadataTest() throws Exception {
@@ -896,7 +897,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the addition of metadata
- *
+ *
* @throws Exception
*/
public void patchAddMetadataTest() throws Exception {
@@ -955,7 +956,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the addition of metadata
- *
+ *
* @throws Exception
*/
public void patchAddMultipleMetadataValuesTest() throws Exception {
@@ -1162,7 +1163,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the acceptance of the deposit license
- *
+ *
* @throws Exception
*/
public void patchAcceptLicenseTest() throws Exception {
@@ -1324,7 +1325,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the reject of the deposit license
- *
+ *
* @throws Exception
*/
public void patchRejectLicenseTest() throws Exception {
@@ -1491,7 +1492,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test update of bitstream metadata in the upload section
- *
+ *
* @throws Exception
*/
public void patchUploadTest() throws Exception {
@@ -1618,7 +1619,7 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
@Test
/**
* Test the upload of files in the upload over section
- *
+ *
* @throws Exception
*/
public void uploadTest() throws Exception {
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
index 9986a1072a..1232deb381 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
@@ -22,17 +22,19 @@ public class CollectionMatcher {
private CollectionMatcher() { }
- public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle) {
- return matchCollectionEntry(name, uuid, handle, null);
+ public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle, UUID parentUuid) {
+ return matchCollectionEntry(name, uuid, handle, null, parentUuid);
}
- public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle, Bitstream logo) {
+ public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle,
+ Bitstream logo, UUID parentUuid) {
return allOf(
hasJsonPath("$.uuid", is(uuid.toString())),
hasJsonPath("$.name", is(name)),
hasJsonPath("$.handle", is(handle)),
hasJsonPath("$.type", is("collection")),
- hasJsonPath("$.metadata", Matchers.contains(
+ hasJsonPath("$.owningCommunity", is(parentUuid.toString())),
+ hasJsonPath("$.metadata", Matchers.hasItem(
CollectionMetadataMatcher.matchTitle(name)
)),
matchLinks(uuid),
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
index 585d955c2f..dad9330ae2 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
@@ -11,6 +11,7 @@ import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
+import java.sql.SQLException;
import java.util.UUID;
import org.dspace.content.Collection;
@@ -36,7 +37,7 @@ public class CommunityMatcher {
hasJsonPath("$.name", is(name)),
hasJsonPath("$.handle", is(handle)),
hasJsonPath("$.type", is("community")),
- hasJsonPath("$.metadata", Matchers.contains(
+ hasJsonPath("$.metadata", Matchers.hasItem(
CommunityMetadataMatcher.matchMetadata("dc.title", name)
))
);
@@ -53,12 +54,13 @@ public class CommunityMatcher {
}
public static Matcher super Object> matchCommunityWithCollectionEntry(String name, UUID uuid, String handle,
- Collection col) {
+ Collection col) throws SQLException {
return allOf(
matchProperties(name, uuid, handle),
hasJsonPath("$._embedded.collections._embedded.collections[0]",
CollectionMatcher
- .matchCollectionEntry(col.getName(), col.getID(), col.getHandle(), col.getLogo())),
+ .matchCollectionEntry(col.getName(), col.getID(), col.getHandle(),
+ col.getLogo(), col.getCommunities().get(0).getID())),
hasJsonPath("$._embedded.logo", Matchers.not(Matchers.empty())),
matchLinks(uuid)
);
From 94ed795d00ec91464db03ded4883c66d838680aa Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 22 Aug 2018 20:22:51 -0400
Subject: [PATCH 02/68] [DS-3989] Accumulate reports; implement arbitrary
output paths, not just standard output.
---
.../java/org/dspace/curate/CurationCli.java | 17 ++++++++++++--
.../main/java/org/dspace/curate/Curator.java | 19 ++++++++--------
.../curate/WorkflowCuratorServiceImpl.java | 22 ++++++++++++++++---
3 files changed, 43 insertions(+), 15 deletions(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
index d5577cf368..44e29c76fc 100644
--- a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
+++ b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
@@ -9,6 +9,10 @@ package org.dspace.curate;
import java.io.BufferedReader;
import java.io.FileReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -18,6 +22,7 @@ import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
+import org.apache.commons.io.output.NullOutputStream;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Context;
import org.dspace.core.factory.CoreServiceFactory;
@@ -165,9 +170,17 @@ public class CurationCli {
}
Curator curator = new Curator();
- if (reporterName != null) {
- curator.setReporter(reporterName);
+ OutputStream reporter;
+ if (null == reporterName) {
+ reporter = new NullOutputStream();
+ } else if ("-".equals(reporterName)) {
+ reporter = System.out;
+ } else {
+ reporter = new PrintStream(reporterName);
}
+ Writer reportWriter = new OutputStreamWriter(reporter);
+ curator.setReporter(reportWriter);
+
if (scope != null) {
Curator.TxScope txScope = Curator.TxScope.valueOf(scope.toUpperCase());
curator.setTransactionScope(txScope);
diff --git a/dspace-api/src/main/java/org/dspace/curate/Curator.java b/dspace-api/src/main/java/org/dspace/curate/Curator.java
index 1a78544bc0..f8cf47f798 100644
--- a/dspace-api/src/main/java/org/dspace/curate/Curator.java
+++ b/dspace-api/src/main/java/org/dspace/curate/Curator.java
@@ -14,8 +14,10 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.logging.Level;
import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
@@ -69,16 +71,12 @@ public class Curator {
INTERACTIVE, BATCH, ANY
}
- ;
-
// transaction scopes
public static enum TxScope {
OBJECT, CURATION, OPEN
}
- ;
-
- private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(Curator.class);
+ private static final Logger log = LogManager.getLogger();
protected static final ThreadLocal curationCtx = new ThreadLocal<>();
@@ -86,7 +84,7 @@ public class Curator {
protected Map trMap = new HashMap<>();
protected List perfList = new ArrayList<>();
protected TaskQueue taskQ = null;
- protected String reporter = null;
+ protected Appendable reporter = null;
protected Invoked iMode = null;
protected TaskResolver resolver = new TaskResolver();
protected TxScope txScope = TxScope.OPEN;
@@ -193,7 +191,7 @@ public class Curator {
* causes reporting to standard out.
* @return return self (Curator instance) with reporter set
*/
- public Curator setReporter(String reporter) {
+ public Curator setReporter(Appendable reporter) {
this.reporter = reporter;
return this;
}
@@ -346,9 +344,10 @@ public class Curator {
* @param message the message to output to the reporting stream.
*/
public void report(String message) {
- // Stub for now
- if ("-".equals(reporter)) {
- System.out.println(message);
+ try {
+ reporter.append(message);
+ } catch (IOException ex) {
+ log.error("Task reporting failure", ex);
}
}
diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
index 5cecc13b89..c821c29b61 100644
--- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
@@ -14,8 +14,14 @@ import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.sql.SQLException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -56,9 +62,10 @@ import org.springframework.beans.factory.annotation.Autowired;
public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
/**
- * log4j logger
+ * Logging category
*/
- private Logger log = org.apache.logging.log4j.LogManager.getLogger(WorkflowCuratorServiceImpl.class);
+ private static final Logger log
+ = org.apache.logging.log4j.LogManager.getLogger();
protected Map tsMap = new HashMap();
@@ -118,6 +125,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
Curator curator = new Curator();
// are we going to perform, or just put on queue?
if (step.queue != null) {
+ // The queue runner will call setReporter
for (Task task : step.tasks) {
curator.addTask(task.name);
}
@@ -125,7 +133,15 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
basicWorkflowItemService.update(c, wfi);
return false;
} else {
- return curate(curator, c, wfi);
+ Date now = GregorianCalendar.getInstance().getTime();
+ SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMDDThhmmssSSS");
+ String filename = String.format("curation-%s.log", sdf.format(now));
+ Path logPath = Paths.get(
+ configurationService.getProperty("dspace.dir"), "logs", filename);
+ try (PrintWriter reporter = new PrintWriter(logPath.toFile())) {
+ curator.setReporter(reporter);
+ return curate(curator, c, wfi);
+ }
}
}
return true;
From f23fef032f43d827eafc9d6c5d75a7e7d3de3139 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Fri, 24 Aug 2018 13:49:12 -0400
Subject: [PATCH 03/68] [DS-3989] Fix the date format.
---
.../main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
index c821c29b61..66c18c2cf3 100644
--- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
@@ -134,7 +134,7 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
return false;
} else {
Date now = GregorianCalendar.getInstance().getTime();
- SimpleDateFormat sdf = new SimpleDateFormat("YYYYMMDDThhmmssSSS");
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddThhmmssSSS");
String filename = String.format("curation-%s.log", sdf.format(now));
Path logPath = Paths.get(
configurationService.getProperty("dspace.dir"), "logs", filename);
From d6d0e67017cd6dd5ce26eb88ea94c8f52a1422db Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Mon, 27 Aug 2018 10:30:06 -0400
Subject: [PATCH 04/68] [DS-3989] Placate Checkstyle: unused import.
---
dspace-api/src/main/java/org/dspace/curate/Curator.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/Curator.java b/dspace-api/src/main/java/org/dspace/curate/Curator.java
index f8cf47f798..da415aeca1 100644
--- a/dspace-api/src/main/java/org/dspace/curate/Curator.java
+++ b/dspace-api/src/main/java/org/dspace/curate/Curator.java
@@ -14,7 +14,6 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.logging.Level;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
From 1478ab36fabd2c57a7ecd474d33163fb6805bbeb Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Mon, 10 Sep 2018 21:07:36 -0400
Subject: [PATCH 05/68] [DS-3989] Let tests set multiple values on a
configuration property.
---
.../config/DSpaceConfigurationService.java | 19 +++++++++++++++++++
.../dspace/services/ConfigurationService.java | 10 ++++++++++
2 files changed, 29 insertions(+)
diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
index 3d511a1e67..6e75d7f5d2 100644
--- a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
+++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
@@ -346,6 +346,25 @@ public final class DSpaceConfigurationService implements ConfigurationService {
}
}
+ @Override
+ public synchronized boolean addPropertyValue(String name, Object value) {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null for setting configuration");
+ }
+ if (value == null) {
+ throw new IllegalArgumentException("configuration value may not be null");
+ }
+
+ // If the value is a type of String, trim any leading/trailing spaces before saving it.
+ if (String.class.isInstance(value)) {
+ value = ((String) value).trim();
+ }
+
+ boolean isNew = !configuration.containsKey(name);
+ configuration.addProperty(name, value);
+ return isNew;
+ }
+
/* (non-Javadoc)
* @see org.dspace.services.ConfigurationService#setProperty(java.lang.String, java.lang.Object)
*/
diff --git a/dspace-services/src/main/java/org/dspace/services/ConfigurationService.java b/dspace-services/src/main/java/org/dspace/services/ConfigurationService.java
index 050e4c089c..526a518a09 100644
--- a/dspace-services/src/main/java/org/dspace/services/ConfigurationService.java
+++ b/dspace-services/src/main/java/org/dspace/services/ConfigurationService.java
@@ -237,6 +237,16 @@ public interface ConfigurationService {
*/
public boolean hasProperty(String name);
+ /**
+ * Add a value to a configuration property.
+ *
+ * @param name the property name. May not be null.
+ * @param value the property value. May not be null.
+ * @return true if a new property was created.
+ * @throws IllegalArgumentException if the name or value is null.
+ */
+ public boolean addPropertyValue(String name, Object value);
+
/**
* Set a configuration property (setting) in the system.
* Type is not important here since conversion happens automatically
From ab224b25081bf3389f2c248b7cfc19a1509d1b79 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Mon, 10 Sep 2018 21:08:19 -0400
Subject: [PATCH 06/68] [DS-3989] Integration test for Curator's reporting.
---
.../java/org/dspace/curate/ITCurator.java | 202 ++++++++++++++++++
1 file changed, 202 insertions(+)
create mode 100644 dspace-api/src/test/java/org/dspace/curate/ITCurator.java
diff --git a/dspace-api/src/test/java/org/dspace/curate/ITCurator.java b/dspace-api/src/test/java/org/dspace/curate/ITCurator.java
new file mode 100644
index 0000000000..ecb2667f08
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/curate/ITCurator.java
@@ -0,0 +1,202 @@
+/**
+ * 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.curate;
+
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.dspace.AbstractUnitTest;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.content.Community;
+import org.dspace.content.DSpaceObject;
+import org.dspace.content.Site;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.services.ConfigurationService;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Drive the Curator and check results.
+ *
+ * @author mhwood
+ */
+public class ITCurator
+ extends AbstractUnitTest {
+ Logger LOG = LoggerFactory.getLogger(ITCurator.class);
+
+ public ITCurator() {
+ }
+
+ @BeforeClass
+ public static void setUpClass() {
+ }
+
+ @AfterClass
+ public static void tearDownClass() {
+ }
+
+ @Before
+ public void setUp() {
+ }
+
+ @After
+ public void tearDown() {
+ }
+
+ /**
+ * The report should contain contributions from all tasks and all curated objects.
+ *
+ * @throws SQLException passed through.
+ * @throws IOException passed through.
+ * @throws AuthorizeException passed through.
+ */
+ @Test
+ public void testCurate_Reporting()
+ throws SQLException, IOException, AuthorizeException {
+ // Configure for testing.
+ ConfigurationService cfg = kernelImpl.getConfigurationService();
+ cfg.setProperty("plugin.named.org.dspace.curate.CurationTask",
+ Task1.class.getName() + " = task1");
+ cfg.addPropertyValue("plugin.named.org.dspace.curate.CurationTask",
+ Task2.class.getName() + " = task2");
+
+ // Create some structure.
+ context.turnOffAuthorisationSystem();
+ Site site = ContentServiceFactory.getInstance()
+ .getSiteService()
+ .findSite(context);
+ Community community = ContentServiceFactory.getInstance()
+ .getCommunityService()
+ .create(null, context);
+
+ // Run some tasks.
+ ListReporter reporter = new ListReporter();
+ Curator curator = new Curator();
+ curator.setReporter(reporter);
+ curator.addTask("task1");
+ curator.addTask("task2");
+ curator.curate(context, site);
+
+ // Validate the results.
+ List report = reporter.getReport();
+ for (String aReport : report) {
+ LOG.info("Report: {}", aReport);
+ }
+ Pattern pattern;
+ pattern = Pattern.compile(String.format("task1.*%s", site.getHandle()));
+ Assert.assertTrue("A report should mention 'task1' and site's handle",
+ reportMatcher(report, pattern));
+ pattern = Pattern.compile(String.format("task1.*%s", community.getHandle()));
+ Assert.assertTrue("A report should mention 'task1' and the community's handle",
+ reportMatcher(report, pattern));
+ pattern = Pattern.compile(String.format("task2.*%s", site.getHandle()));
+ Assert.assertTrue("A report should mention 'task2' and the Site's handle",
+ reportMatcher(report, pattern));
+ pattern = Pattern.compile(String.format("task2.*%s", community.getHandle()));
+ Assert.assertTrue("A report should mention 'task2' and the community's handle",
+ reportMatcher(report, pattern));
+ }
+
+ /**
+ * Match a collection of strings against a regular expression.\
+ *
+ * @param reports strings to be searched.
+ * @param pattern expression to be matched.
+ * @return true if at least one string matches the expression.
+ */
+ private boolean reportMatcher(List reports, Pattern pattern) {
+ for (String aReport : reports) {
+ if (pattern.matcher(aReport).find()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Dummy curation task for testing. Reports how it was invoked.
+ *
+ * @author mhwood
+ */
+ public static class Task1 extends AbstractCurationTask {
+ public Task1() {
+ }
+
+ @Override
+ public int perform(DSpaceObject dso)
+ throws IOException {
+ curator.report(String.format(
+ "Task1 received 'perform' on taskId '%s' for object '%s'%n",
+ taskId, dso.getHandle()));
+ return Curator.CURATE_SUCCESS;
+ }
+ }
+
+ /**
+ * Dummy curation task for testing. Reports how it was invoked.
+ *
+ * @author mhwood
+ */
+ public static class Task2 extends AbstractCurationTask {
+ public Task2() {
+ }
+
+ @Override
+ public int perform(DSpaceObject dso) throws IOException {
+ curator.report(String.format(
+ "Task2 received 'perform' on taskId '%s' for object '%s'%n",
+ taskId, dso.getHandle()));
+ return Curator.CURATE_SUCCESS;
+ }
+ }
+
+ /**
+ * Absorb report strings into a sequential collection.
+ */
+ class ListReporter
+ implements Appendable {
+ private final List report = new ArrayList<>();
+
+ /**
+ * Get the content of the report accumulator.
+ * @return accumulated reports.
+ */
+ List getReport() {
+ return report;
+ }
+
+ @Override
+ public Appendable append(CharSequence cs)
+ throws IOException {
+ report.add(cs.toString());
+ return this;
+ }
+
+ @Override
+ public Appendable append(CharSequence cs, int i, int i1)
+ throws IOException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ @Override
+ public Appendable append(char c)
+ throws IOException {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+}
From de33ece1c9ecb42d69c5b1fcc88f21ffa3cfc72f Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 19 Sep 2018 12:07:26 -0400
Subject: [PATCH 07/68] [DS-3989] Pull report writing out through a pluggable
interface, provide log and file plugins
---
.../java/org/dspace/curate/FileReporter.java | 81 +++++++++++++++++++
.../java/org/dspace/curate/LogReporter.java | 70 ++++++++++++++++
.../main/java/org/dspace/curate/Reporter.java | 11 +++
.../curate/WorkflowCuratorServiceImpl.java | 15 ++--
4 files changed, 171 insertions(+), 6 deletions(-)
create mode 100644 dspace-api/src/main/java/org/dspace/curate/FileReporter.java
create mode 100644 dspace-api/src/main/java/org/dspace/curate/LogReporter.java
create mode 100644 dspace-api/src/main/java/org/dspace/curate/Reporter.java
diff --git a/dspace-api/src/main/java/org/dspace/curate/FileReporter.java b/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
new file mode 100644
index 0000000000..7a82347d10
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
@@ -0,0 +1,81 @@
+
+package org.dspace.curate;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.dspace.services.ConfigurationService;
+import org.dspace.utils.DSpace;
+
+/**
+ * Save a curation report to a unique file in the reports directory.
+ * Reports are named by the date and time of day, for example:
+ * "curation-20180916T113903045.report".
+ *
+ * @author mhwood
+ */
+public class FileReporter
+ implements Reporter {
+ private final Writer writer;
+
+ /**
+ * Open a writer to a file in a directory named by the configuration
+ * property {@code reports.dir}, or in {@code [DSpace]/reports} if not
+ * configured.
+ *
+ * @throws IOException if there is a problem with the file path.
+ */
+ public FileReporter()
+ throws IOException {
+ // Calculate a unique(?) file name.
+ Date now = GregorianCalendar.getInstance().getTime();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddThhmmssSSS");
+ String filename = String.format("curation-%s.report", sdf.format(now));
+
+ // Build a path to the directory which is to receive the file.
+ ConfigurationService cfg = new DSpace().getConfigurationService();
+ String reportDir = cfg.getProperty("report.dir");
+ Path reportPath;
+ if (null == reportDir) {
+ reportPath = Paths.get(cfg.getProperty("dspace.dir"),
+ "reports",
+ filename);
+ } else {
+ reportPath = Paths.get(reportDir, filename);
+ }
+
+ // Open the file.
+ writer = new FileWriter(reportPath.toFile());
+ }
+
+ @Override
+ public Appendable append(CharSequence cs)
+ throws IOException {
+ writer.append(cs);
+ return this;
+ }
+
+ @Override
+ public Appendable append(CharSequence cs, int i, int i1)
+ throws IOException {
+ writer.append(cs, i, i1);
+ return this;
+ }
+
+ @Override
+ public Appendable append(char c) throws IOException {
+ writer.append(c);
+ return this;
+ }
+
+ @Override
+ public void close() throws Exception {
+ writer.close();
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
new file mode 100644
index 0000000000..115ae0193c
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
@@ -0,0 +1,70 @@
+
+package org.dspace.curate;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Write curation report records through the logging framework.
+ * Whole lines (strings ending in '\n') are written to a log category named by
+ * the task ID, for example "curation.virusscan".
+ * Any partial line is flushed when the reporter is {@code close()}d.
+ *
+ * @author mhwood
+ */
+public class LogReporter
+ implements Reporter {
+ private static Logger LOG;
+ private final String taskID;
+ private final StringBuilder buffer = new StringBuilder();
+
+ private LogReporter() {
+ taskID = null;
+ }
+
+ public LogReporter(String object, String task) {
+ taskID = task;
+ }
+
+ private Logger getLogger() {
+ if (null == LOG) {
+ LOG = LoggerFactory.getLogger("curation." + taskID);
+ }
+ return LOG;
+ }
+
+ @Override
+ public Appendable append(CharSequence cs)
+ throws IOException {
+ for (int pos = 0; pos < cs.length(); pos++) {
+ char c = cs.charAt(pos);
+ if (c == '\n') {
+ getLogger().info(buffer.toString());
+ buffer.delete(0, buffer.length()); // Clear the buffer
+ } else {
+ buffer.append(c);
+ }
+ }
+ return this;
+ }
+
+ @Override
+ public Appendable append(CharSequence cs, int i, int i1)
+ throws IOException {
+ return append(cs.subSequence(i, i1));
+ }
+
+ @Override
+ public Appendable append(char c)
+ throws IOException {
+ return append(String.valueOf(c));
+ }
+
+ @Override
+ public void close()
+ throws Exception {
+ getLogger().info(buffer.toString());
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/curate/Reporter.java b/dspace-api/src/main/java/org/dspace/curate/Reporter.java
new file mode 100644
index 0000000000..b48f833e57
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/curate/Reporter.java
@@ -0,0 +1,11 @@
+
+package org.dspace.curate;
+
+/**
+ * A marker interface needed to make curation reporter classes into plugins.
+ *
+ * @author mhwood
+ */
+public interface Reporter
+ extends Appendable, AutoCloseable {
+}
diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
index 66c18c2cf3..7389e4517b 100644
--- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
@@ -36,6 +36,8 @@ import org.dspace.content.Item;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
+import org.dspace.core.factory.CoreServiceFactory;
+import org.dspace.core.service.PluginService;
import org.dspace.curate.service.WorkflowCuratorService;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
@@ -133,14 +135,15 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
basicWorkflowItemService.update(c, wfi);
return false;
} else {
- Date now = GregorianCalendar.getInstance().getTime();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddThhmmssSSS");
- String filename = String.format("curation-%s.log", sdf.format(now));
- Path logPath = Paths.get(
- configurationService.getProperty("dspace.dir"), "logs", filename);
- try (PrintWriter reporter = new PrintWriter(logPath.toFile())) {
+ PluginService plugins = CoreServiceFactory.getInstance()
+ .getPluginService();
+ try (Reporter reporter
+ = (Reporter) plugins
+ .getSinglePlugin(Reporter.class);) {
curator.setReporter(reporter);
return curate(curator, c, wfi);
+ } catch (Exception e) {
+ log.error("Failed to close report", e);
}
}
}
From 9f64b9aa954383d9de00e8558811b7dd161c5a4c Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 19 Sep 2018 12:42:29 -0400
Subject: [PATCH 08/68] [DS-3989] Fix license blocks for new classes.
---
.../src/main/java/org/dspace/curate/FileReporter.java | 9 ++++++++-
.../src/main/java/org/dspace/curate/LogReporter.java | 7 +++++++
dspace-api/src/main/java/org/dspace/curate/Reporter.java | 7 +++++++
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/FileReporter.java b/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
index 7a82347d10..d0a2b1c261 100644
--- a/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/FileReporter.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.curate;
@@ -26,7 +33,7 @@ public class FileReporter
/**
* Open a writer to a file in a directory named by the configuration
- * property {@code reports.dir}, or in {@code [DSpace]/reports} if not
+ * property {@code report.dir}, or in {@code [DSpace]/reports} if not
* configured.
*
* @throws IOException if there is a problem with the file path.
diff --git a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
index 115ae0193c..8a2397b8ce 100644
--- a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/LogReporter.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.curate;
diff --git a/dspace-api/src/main/java/org/dspace/curate/Reporter.java b/dspace-api/src/main/java/org/dspace/curate/Reporter.java
index b48f833e57..c4c58f75cf 100644
--- a/dspace-api/src/main/java/org/dspace/curate/Reporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/Reporter.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.curate;
From d9c80d8afceb0c2e920724e749e03039bc5f397d Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 19 Sep 2018 13:47:03 -0400
Subject: [PATCH 09/68] [DS-3989] Fix checkstyle issues.
---
.../java/org/dspace/curate/WorkflowCuratorServiceImpl.java | 6 ------
1 file changed, 6 deletions(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
index 7389e4517b..64577e74f0 100644
--- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
@@ -14,14 +14,8 @@ import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.sql.SQLException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
-import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
From dbcb1f291c80ec53019e40d691c2c52a361f986e Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 26 Sep 2018 20:49:25 -0400
Subject: [PATCH 10/68] [DS-3989] Fix invalid date format.
---
dspace-api/src/main/java/org/dspace/curate/FileReporter.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/FileReporter.java b/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
index d0a2b1c261..796b35eff5 100644
--- a/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/FileReporter.java
@@ -42,7 +42,7 @@ public class FileReporter
throws IOException {
// Calculate a unique(?) file name.
Date now = GregorianCalendar.getInstance().getTime();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddThhmmssSSS");
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'hhmmssSSS");
String filename = String.format("curation-%s.report", sdf.format(now));
// Build a path to the directory which is to receive the file.
From ff8a5fac970e3a2213e89ae0dd3d21be96777580 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 26 Sep 2018 20:50:20 -0400
Subject: [PATCH 11/68] [DS-3989] Add configuration for the Reporter plugin.
---
dspace/config/modules/submission-curation.cfg | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/dspace/config/modules/submission-curation.cfg b/dspace/config/modules/submission-curation.cfg
index b69ba71cbb..ccb81da2bf 100644
--- a/dspace/config/modules/submission-curation.cfg
+++ b/dspace/config/modules/submission-curation.cfg
@@ -5,4 +5,8 @@
# to the scheduling of curation tasks during submission. #
#---------------------------------------------------------------#
# Scan for viruses
-submission-curation.virus-scan = false
\ No newline at end of file
+submission-curation.virus-scan = false
+
+# Report serializer plugin. Uncomment exactly one, or configure your own.
+plugin.single.org.dspace.curate.Reporter = org.dspace.curate.FileReporter
+#plugin.single.org.dspace.curate.Reporter = org.dspace.curate.LogReporter
From 6084f892b2d18a232de223d6c035073853e5b3b4 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Thu, 27 Sep 2018 07:49:38 -0400
Subject: [PATCH 12/68] [DS-3989] Remove unworkable task-id logging; ensure
closure of Reporter.
---
.../java/org/dspace/curate/LogReporter.java | 25 +++----------------
.../curate/WorkflowCuratorServiceImpl.java | 4 ++-
2 files changed, 7 insertions(+), 22 deletions(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
index 8a2397b8ce..d977d49da7 100644
--- a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
@@ -15,40 +15,23 @@ import org.slf4j.LoggerFactory;
/**
* Write curation report records through the logging framework.
- * Whole lines (strings ending in '\n') are written to a log category named by
- * the task ID, for example "curation.virusscan".
+ * Whole lines (strings ending in '\n') are written to the log category "curation".
* Any partial line is flushed when the reporter is {@code close()}d.
*
* @author mhwood
*/
public class LogReporter
implements Reporter {
- private static Logger LOG;
- private final String taskID;
+ private static final Logger LOG = LoggerFactory.getLogger("curation");
private final StringBuilder buffer = new StringBuilder();
- private LogReporter() {
- taskID = null;
- }
-
- public LogReporter(String object, String task) {
- taskID = task;
- }
-
- private Logger getLogger() {
- if (null == LOG) {
- LOG = LoggerFactory.getLogger("curation." + taskID);
- }
- return LOG;
- }
-
@Override
public Appendable append(CharSequence cs)
throws IOException {
for (int pos = 0; pos < cs.length(); pos++) {
char c = cs.charAt(pos);
if (c == '\n') {
- getLogger().info(buffer.toString());
+ LOG.info(buffer.toString());
buffer.delete(0, buffer.length()); // Clear the buffer
} else {
buffer.append(c);
@@ -72,6 +55,6 @@ public class LogReporter
@Override
public void close()
throws Exception {
- getLogger().info(buffer.toString());
+ LOG.info(buffer.toString());
}
}
diff --git a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
index 64577e74f0..a3272c61b4 100644
--- a/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/curate/WorkflowCuratorServiceImpl.java
@@ -135,7 +135,9 @@ public class WorkflowCuratorServiceImpl implements WorkflowCuratorService {
= (Reporter) plugins
.getSinglePlugin(Reporter.class);) {
curator.setReporter(reporter);
- return curate(curator, c, wfi);
+ boolean status = curate(curator, c, wfi);
+ reporter.close();
+ return status;
} catch (Exception e) {
log.error("Failed to close report", e);
}
From 85db4fe2bb5d9e7f3bd999113dd7057eb0c77c3e Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Thu, 27 Sep 2018 22:32:58 -0400
Subject: [PATCH 13/68] [DS-3989] Commit testing task.
---
.../dspace/ctask/test/WorkflowReportTest.java | 39 +++++++++++++++++++
.../java/org/dspace/curate/LogReporter.java | 4 +-
2 files changed, 42 insertions(+), 1 deletion(-)
create mode 100644 dspace-api/src/main/java/org/dspace/ctask/test/WorkflowReportTest.java
diff --git a/dspace-api/src/main/java/org/dspace/ctask/test/WorkflowReportTest.java b/dspace-api/src/main/java/org/dspace/ctask/test/WorkflowReportTest.java
new file mode 100644
index 0000000000..21ffdd0260
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/ctask/test/WorkflowReportTest.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.ctask.test;
+
+import java.io.IOException;
+
+import org.dspace.content.DSpaceObject;
+import org.dspace.curate.AbstractCurationTask;
+import org.dspace.curate.Curator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Curation task which simply reports its invocation without changing anything.
+ * Meant for testing.
+ *
+ * @author mhwood
+ */
+public class WorkflowReportTest
+ extends AbstractCurationTask {
+ private static final Logger LOG = LoggerFactory.getLogger(WorkflowReportTest.class);
+
+ @Override
+ public int perform(DSpaceObject dso)
+ throws IOException {
+ LOG.info("Class {} as task {} received 'perform' for object {}",
+ WorkflowReportTest.class.getSimpleName(), taskId, dso);
+ curator.report(String.format(
+ "Class %s as task %s received 'perform' for object %s%n",
+ WorkflowReportTest.class.getSimpleName(), taskId, dso));
+ return Curator.CURATE_SUCCESS;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
index d977d49da7..bd3ee3cffb 100644
--- a/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
+++ b/dspace-api/src/main/java/org/dspace/curate/LogReporter.java
@@ -55,6 +55,8 @@ public class LogReporter
@Override
public void close()
throws Exception {
- LOG.info(buffer.toString());
+ if (buffer.length() > 0) {
+ LOG.info(buffer.toString());
+ }
}
}
From c795c8b4b437972ca5dd4cd2d7c146e0a0cd3704 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Mon, 22 Oct 2018 16:08:54 -0400
Subject: [PATCH 14/68] [DS-3989] Clarify submission task configuration.
---
dspace/config/modules/submission-curation.cfg | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/dspace/config/modules/submission-curation.cfg b/dspace/config/modules/submission-curation.cfg
index ccb81da2bf..60442a9955 100644
--- a/dspace/config/modules/submission-curation.cfg
+++ b/dspace/config/modules/submission-curation.cfg
@@ -2,11 +2,15 @@
#------------SUBMISSION CURATION CONFIGURATIONS-----------------#
#---------------------------------------------------------------#
# This file contains configuration properties solely relating #
-# to the scheduling of curation tasks during submission. #
+# to the scheduling of curation tasks during submission -- that #
+# is: when tasks are attached to a workflow. #
#---------------------------------------------------------------#
# Scan for viruses
submission-curation.virus-scan = false
-# Report serializer plugin. Uncomment exactly one, or configure your own.
+# Report serializer plugin, to capture submission task reports.
+# Uncomment exactly one, or configure your own.
+# FileReporter writes reports to ${report.dir}/curation-yyyyMMddThhmmssSSS.report
plugin.single.org.dspace.curate.Reporter = org.dspace.curate.FileReporter
+# LogReporter writes report lines to the DSpace log.
#plugin.single.org.dspace.curate.Reporter = org.dspace.curate.LogReporter
From 1e5bcd47ce6209c3c3ab367da81e9ac0b8d800a4 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Mon, 22 Oct 2018 16:17:07 -0400
Subject: [PATCH 15/68] [DS-3989] Clarify help for --reporter option.
---
dspace-api/src/main/java/org/dspace/curate/CurationCli.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
index 44e29c76fc..3832ddf3ec 100644
--- a/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
+++ b/dspace-api/src/main/java/org/dspace/curate/CurationCli.java
@@ -62,7 +62,9 @@ public class CurationCli {
options.addOption("e", "eperson", true,
"email address of curating eperson");
options.addOption("r", "reporter", true,
- "reporter to manage results - use '-' to report to console. If absent, no reporting");
+ "relative or absolute path to the desired report file. "
+ + "Use '-' to report to console. "
+ + "If absent, no reporting");
options.addOption("s", "scope", true,
"transaction scope to impose: use 'object', 'curation', or 'open'. If absent, 'open' " +
"applies");
From 1d3a58958eb78bdb734a645e6debcf217e59a2c9 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Sat, 10 Nov 2018 07:47:35 -0500
Subject: [PATCH 16/68] [DS-3989] Update new method for Commons Configuration
v2.
---
.../dspace/servicemanager/config/DSpaceConfigurationService.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
index 6e75d7f5d2..8bf037cbe3 100644
--- a/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
+++ b/dspace-services/src/main/java/org/dspace/servicemanager/config/DSpaceConfigurationService.java
@@ -360,6 +360,7 @@ public final class DSpaceConfigurationService implements ConfigurationService {
value = ((String) value).trim();
}
+ Configuration configuration = getConfiguration();
boolean isNew = !configuration.containsKey(name);
configuration.addProperty(name, value);
return isNew;
From 844ef85583b2e24f3d877c342794cdf5977ac903 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Sat, 10 Nov 2018 07:48:10 -0500
Subject: [PATCH 17/68] [DS-3989] Placate Checkstyle.
---
dspace-api/src/main/java/org/dspace/curate/Curator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dspace-api/src/main/java/org/dspace/curate/Curator.java b/dspace-api/src/main/java/org/dspace/curate/Curator.java
index da415aeca1..44733174df 100644
--- a/dspace-api/src/main/java/org/dspace/curate/Curator.java
+++ b/dspace-api/src/main/java/org/dspace/curate/Curator.java
@@ -15,8 +15,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
From 8df33db457459b26d891240863840a757e421c25 Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 5 Dec 2018 16:13:24 -0500
Subject: [PATCH 18/68] [DS-3989] Fix code from DS-3990 that was (expectedly)
broken by DS-3989.
---
dspace-api/src/test/java/org/dspace/curate/CuratorTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dspace-api/src/test/java/org/dspace/curate/CuratorTest.java b/dspace-api/src/test/java/org/dspace/curate/CuratorTest.java
index 5761ee7ec7..8ca6b6c172 100644
--- a/dspace-api/src/test/java/org/dspace/curate/CuratorTest.java
+++ b/dspace-api/src/test/java/org/dspace/curate/CuratorTest.java
@@ -58,7 +58,7 @@ public class CuratorTest
// Get and configure a Curator.
Curator instance = new Curator();
- instance.setReporter("-"); // Send any report to standard out. FIXME when DS-3989 is merged
+ instance.setReporter(System.out); // Send any report to standard out.
instance.addTask(TASK_NAME);
// Configure the run.
From e283f434675721d2675bf08537411dca2c5c6db7 Mon Sep 17 00:00:00 2001
From: Samuel
Date: Tue, 18 Dec 2018 11:09:12 +0100
Subject: [PATCH 19/68] Added support for the CRUD operations on the Collection
and Community REST endpoints - send parentCommunity as request parameter
---
.../repository/CollectionRestRepository.java | 25 ++++++++++---------
.../repository/CommunityRestRepository.java | 25 ++++++++++---------
.../app/rest/CollectionRestRepositoryIT.java | 4 +--
.../app/rest/CommunityRestRepositoryIT.java | 2 +-
4 files changed, 29 insertions(+), 27 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 2c0b9bf44a..c3ca8a82cc 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -164,7 +164,7 @@ public class CollectionRestRepository extends DSpaceRestRepositorySome cool HTML code here
");
@@ -514,6 +513,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/collections")
.content(mapper.writeValueAsBytes(collectionRest))
+ .param("parentCommunity", parentCommunity.getID().toString())
.contentType(contentType))
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType))
@@ -522,7 +522,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
hasJsonPath("$.uuid", not(empty())),
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
- hasJsonPath("$.owningCommunity", is(collectionRest.getOwningCommunity())),
+ hasJsonPath("$.owningCommunity", is(parentCommunity.getID().toString())),
hasJsonPath("$.type", is("collection")),
hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
CommunityMetadataMatcher.matchMetadata("dc.description",
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 55e2cecc48..079a748213 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
@@ -122,7 +122,6 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
CommunityRest comm = new CommunityRest();
// We send a name but the created community should set this to the title
comm.setName("Test Sub-Level Community");
- comm.setOwningCommunity(parentCommunity.getID().toString());
MetadataEntryRest description = new MetadataEntryRest();
description.setKey("dc.description");
description.setValue("Some cool HTML code here
");
@@ -152,6 +151,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/communities")
.content(mapper.writeValueAsBytes(comm))
+ .param("parentCommunity", parentCommunity.getID().toString())
.contentType(contentType))
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType))
From fb1a8b8c331773a6cc0ac482641f461124d7a45e Mon Sep 17 00:00:00 2001
From: Samuel
Date: Tue, 18 Dec 2018 14:30:36 +0100
Subject: [PATCH 20/68] Added support for the CRUD operations on the Collection
and Community REST endpoints - remove owningCommunity field from
CommunityRest and CollectionRest
---
.../rest/converter/CollectionConverter.java | 5 --
.../rest/converter/CommunityConverter.java | 8 +--
.../dspace/app/rest/model/CollectionRest.java | 10 ----
.../dspace/app/rest/model/CommunityRest.java | 10 ----
.../app/rest/CollectionRestRepositoryIT.java | 52 ++++++-------------
.../app/rest/CommunityRestRepositoryIT.java | 3 --
.../rest/WorkspaceItemRestRepositoryIT.java | 4 +-
.../app/rest/matcher/CollectionMatcher.java | 8 ++-
.../app/rest/matcher/CommunityMatcher.java | 6 +--
9 files changed, 25 insertions(+), 81 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
index d3d641510f..a4c368d2b4 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
@@ -66,11 +66,6 @@ public class CollectionConverter
col.setDefaultAccessConditions(getDefaultBitstreamPoliciesForCollection(obj.getID()));
- try {
- col.setOwningCommunity(obj.getCommunities().get(0).getID().toString());
- } catch (SQLException e) {
- log.error(e.getMessage(), e);
- }
return col;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
index edb4528482..b1883ccff0 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
@@ -64,13 +64,7 @@ public class CommunityConverter
}
}
com.setSubCommunities(communityRest);
- List parentCommunities = obj.getParentCommunities();
- if (parentCommunities.size() > 0) {
- Community parentCommunity = parentCommunities.get(0);
- if (parentCommunity != null) {
- com.setOwningCommunity(parentCommunity.getID().toString());
- }
- }
+
return com;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
index cc55ef3f55..77bb992004 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CollectionRest.java
@@ -29,8 +29,6 @@ public class CollectionRest extends DSpaceObjectRest {
@JsonIgnore
private BitstreamRest logo;
- private String owningCommunity;
-
@JsonIgnore
private List defaultAccessConditions;
@@ -63,12 +61,4 @@ public class CollectionRest extends DSpaceObjectRest {
this.defaultAccessConditions = defaultAccessConditions;
}
- public String getOwningCommunity() {
- return owningCommunity;
- }
-
- public void setOwningCommunity(String owningCommunity) {
- this.owningCommunity = owningCommunity;
- }
-
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
index 53b9f1333c..19d3decaee 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/CommunityRest.java
@@ -24,16 +24,6 @@ public class CommunityRest extends DSpaceObjectRest {
@JsonIgnore
private BitstreamRest logo;
- private String owningCommunity;
-
- public String getOwningCommunity() {
- return owningCommunity;
- }
-
- public void setOwningCommunity(String owningCommunity) {
- this.owningCommunity = owningCommunity;
- }
-
private List collections;
@LinkRest(linkClass = CollectionRest.class)
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index 744f8c43f0..39f79d4601 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -63,10 +63,8 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.containsInAnyOrder(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID()),
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col2.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()),
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
)));
}
@@ -95,13 +93,11 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._embedded.collections", Matchers.not(
Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
)
)));
@@ -111,13 +107,11 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.collections", Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col2.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
)))
.andExpect(jsonPath("$._embedded.collections", Matchers.not(
Matchers.contains(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)
)));
}
@@ -147,13 +141,11 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$", Matchers.not(
is(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
))));
}
@@ -181,13 +173,11 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$", Matchers.not(
is(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
)))
)
;
@@ -321,13 +311,11 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$", Matchers.not(
is(
- CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col2.getName(), col2.getID(), col2.getHandle())
))));
}
@@ -350,8 +338,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/collections")))
;
@@ -365,8 +352,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
"dissertations (ETD)\",\"handle\": \"" + col1.getHandle() + "\",\"metadata\": " +
"[{\"key\": \"dc.description.abstract\",\"value\": \"\",\"language\": null}," +
"{\"key\": \"dc.title\",\"value\": \"Electronic theses and dissertations " +
- "(ETD)\",\"language\": null}], \"owningCommunity\": \"" +
- child1.getID() + "\",\"type\": \"collection\"}"
+ "(ETD)\",\"language\": null}],\"type\": \"collection\"}"
))
.andExpect(status().isOk())
;
@@ -376,8 +362,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
CollectionMatcher.matchCollectionEntry("Electronic theses and dissertations (ETD)",
- col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/core/collections")))
@@ -415,8 +400,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/core/collections"))) ;
@@ -457,8 +441,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
- CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID())
+ CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._links.self.href",
Matchers.containsString("/api/core/collections"))) ;
@@ -522,7 +505,6 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
hasJsonPath("$.uuid", not(empty())),
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
- hasJsonPath("$.owningCommunity", is(parentCommunity.getID().toString())),
hasJsonPath("$.type", is("collection")),
hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
CommunityMetadataMatcher.matchMetadata("dc.description",
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 079a748213..7a5bf09e72 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
@@ -10,7 +10,6 @@ package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.isEmptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -86,7 +85,6 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
hasJsonPath("$.uuid", not(empty())),
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
- hasJsonPath("$.owningCommunity", isEmptyOrNullString()),
hasJsonPath("$.type", is("community")),
hasJsonPath("$._links.collections.href", not(empty())),
hasJsonPath("$._links.logo.href", not(empty())),
@@ -160,7 +158,6 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
hasJsonPath("$.uuid", not(empty())),
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
- hasJsonPath("$.owningCommunity", is(parentCommunity.getID().toString())),
hasJsonPath("$.type", is("community")),
hasJsonPath("$._links.collections.href", not(empty())),
hasJsonPath("$._links.logo.href", not(empty())),
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 f9643bf1e5..eac8721031 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
@@ -239,8 +239,8 @@ public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegration
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/collection"))
.andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers
- .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle(),
- col1.getCommunities().get(0).getID()))));
+ .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle()))
+ ));
getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/item")).andExpect(status().isOk())
.andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemWithTitleAndDateIssued(witem.getItem(),
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
index 1232deb381..5381c62d93 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
@@ -22,18 +22,16 @@ public class CollectionMatcher {
private CollectionMatcher() { }
- public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle, UUID parentUuid) {
- return matchCollectionEntry(name, uuid, handle, null, parentUuid);
+ public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle) {
+ return matchCollectionEntry(name, uuid, handle, null);
}
- public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle,
- Bitstream logo, UUID parentUuid) {
+ public static Matcher super Object> matchCollectionEntry(String name, UUID uuid, String handle, Bitstream logo) {
return allOf(
hasJsonPath("$.uuid", is(uuid.toString())),
hasJsonPath("$.name", is(name)),
hasJsonPath("$.handle", is(handle)),
hasJsonPath("$.type", is("collection")),
- hasJsonPath("$.owningCommunity", is(parentUuid.toString())),
hasJsonPath("$.metadata", Matchers.hasItem(
CollectionMetadataMatcher.matchTitle(name)
)),
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
index dad9330ae2..600f67ab52 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
@@ -11,7 +11,6 @@ import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
-import java.sql.SQLException;
import java.util.UUID;
import org.dspace.content.Collection;
@@ -54,13 +53,12 @@ public class CommunityMatcher {
}
public static Matcher super Object> matchCommunityWithCollectionEntry(String name, UUID uuid, String handle,
- Collection col) throws SQLException {
+ Collection col) {
return allOf(
matchProperties(name, uuid, handle),
hasJsonPath("$._embedded.collections._embedded.collections[0]",
CollectionMatcher
- .matchCollectionEntry(col.getName(), col.getID(), col.getHandle(),
- col.getLogo(), col.getCommunities().get(0).getID())),
+ .matchCollectionEntry(col.getName(), col.getID(), col.getHandle(), col.getLogo())),
hasJsonPath("$._embedded.logo", Matchers.not(Matchers.empty())),
matchLinks(uuid)
);
From b96cf91ef8d66825cad7c5d346c25e9b4c47f4af Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Fri, 11 Jan 2019 09:38:21 +0100
Subject: [PATCH 21/68] Applied community feedback and fixed tests
---
.../app/rest/RestResourceController.java | 30 +++++++++++++++-
.../rest/converter/CollectionConverter.java | 10 ++++--
.../repository/CollectionRestRepository.java | 26 ++++++++------
.../repository/CommunityRestRepository.java | 29 +++++++++-------
.../rest/repository/DSpaceRestRepository.java | 10 ++++++
.../utils/CollectionRestEqualityUtils.java | 33 ++++++++++++++++++
.../utils/CommunityRestEqualityUtils.java | 33 ++++++++++++++++++
.../utils/DSpaceObjectRestEqualityUtils.java | 34 +++++++++++++++++++
.../app/rest/utils/DSpaceObjectUtils.java | 19 +++++++++++
.../app/rest/CollectionRestRepositoryIT.java | 30 ++++++++++------
.../app/rest/CommunityRestRepositoryIT.java | 30 ++++++++++------
11 files changed, 238 insertions(+), 46 deletions(-)
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/CollectionRestEqualityUtils.java
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/CommunityRestEqualityUtils.java
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java
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 74775a9314..0fcc8953ce 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
@@ -983,7 +983,25 @@ public class RestResourceController implements InitializingBean {
}
-
+ /**
+ * Execute a PUT request for an entity with id of type UUID;
+ *
+ * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}
+ *
+ * Example:
+ *
+ * {@code
+ * curl -X PUT http:///dspace-spring-rest/api/collection
+ * }
+ *
+ *
+ * @param request the http request
+ * @param apiCategory the API category e.g. "api"
+ * @param model the DSpace model e.g. "metadatafield"
+ * @param uuid 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_UUID)
public DSpaceResource put(HttpServletRequest request,
@PathVariable String apiCategory, @PathVariable String model,
@@ -992,6 +1010,16 @@ public class RestResourceController implements InitializingBean {
return putOneInternal(request, apiCategory, model, uuid, jsonNode);
}
+ /**
+ * Internal method to update a single entity
+ *
+ * @param request the http request
+ * @param apiCategory the API category e.g. "api"
+ * @param model the DSpace model e.g. "metadatafield"
+ * @param uuid 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
+ */
private DSpaceResource putOneInternal(HttpServletRequest request,
String apiCategory,
String model, ID uuid,
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
index a4c368d2b4..c1a13686db 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
@@ -25,6 +25,7 @@ import org.dspace.content.service.CollectionService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.services.RequestService;
+import org.dspace.services.model.Request;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -71,12 +72,17 @@ public class CollectionConverter
private List getDefaultBitstreamPoliciesForCollection(UUID uuid) {
- HttpServletRequest request = requestService.getCurrentRequest().getHttpServletRequest();
Context context = null;
+ Request currentRequest = requestService.getCurrentRequest();
+ if (currentRequest != null) {
+ HttpServletRequest request = currentRequest.getHttpServletRequest();
+ context = ContextUtil.obtainContext(request);
+ } else {
+ context = new Context();
+ }
Collection collection = null;
List defaultCollectionPolicies = null;
try {
- context = ContextUtil.obtainContext(request);
collection = collectionService.find(context, uuid);
defaultCollectionPolicies = authorizeService.getPoliciesActionFilter(context, collection,
Constants.DEFAULT_BITSTREAM_READ);
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index c3ca8a82cc..ab6f56ed61 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -30,6 +30,7 @@ import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
+import org.dspace.app.rest.utils.CollectionRestEqualityUtils;
import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
@@ -70,6 +71,9 @@ public class CollectionRestRepository extends DSpaceRestRepository metadataEntryRestList = collectionRest.getMetadata();
collection = (Collection) dspaceObjectUtils.replaceMetadataValues(context,
collection,
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
index 25306d81f0..3c180caf08 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
@@ -29,6 +29,7 @@ import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CommunityResource;
+import org.dspace.app.rest.utils.CommunityRestEqualityUtils;
import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
@@ -61,6 +62,9 @@ public class CommunityRestRepository extends DSpaceRestRepository metadataEntryRestList = communityRest.getMetadata();
community = (Community) dspaceObjectUtils.replaceMetadataValues(context, community, metadataEntryRestList);
} else {
- throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
- + id + ", "
- + communityRest.getId());
+ throw new UnprocessableEntityException("The given JSON and the original Community differ more " +
+ "than just the metadata");
}
return converter.fromModel(community);
}
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 4be7596ad4..5b7e3915c9 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
@@ -418,6 +418,16 @@ public abstract class DSpaceRestRepository metadataEntryRestList)
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index 39f79d4601..13139740db 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -25,6 +25,7 @@ import java.util.UUID;
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.converter.CollectionConverter;
import org.dspace.app.rest.matcher.CollectionMatcher;
import org.dspace.app.rest.matcher.CommunityMetadataMatcher;
import org.dspace.app.rest.model.CollectionRest;
@@ -34,10 +35,13 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.hamcrest.Matchers;
import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTest {
+ @Autowired
+ CollectionConverter collectionConverter;
@Test
public void findAllTest() throws Exception {
@@ -289,7 +293,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
}
@Test
- public void findCollectionWithOwningCommunity() throws Exception {
+ public void findCollectionWithParentCommunity() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
@@ -345,15 +349,19 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
String token = getAuthToken(admin.getEmail(), password);
+ ObjectMapper mapper = new ObjectMapper();
+
+ CollectionRest collectionRest = collectionConverter.fromModel(col1);
+
+ MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
+ metadataEntryRest.setKey("dc.title");
+ metadataEntryRest.setValue("Electronic theses and dissertations");
+
+ collectionRest.setMetadata(Arrays.asList(metadataEntryRest));
+
getClient(token).perform(put("/api/core/collections/" + col1.getID().toString())
- .contentType(MediaType.APPLICATION_JSON).content(
- "{\"id\": \"" + col1.getID() + "\",\"uuid\": " +
- "\"" + col1.getID() + "\",\"name\": \"Electronic theses and " +
- "dissertations (ETD)\",\"handle\": \"" + col1.getHandle() + "\",\"metadata\": " +
- "[{\"key\": \"dc.description.abstract\",\"value\": \"\",\"language\": null}," +
- "{\"key\": \"dc.title\",\"value\": \"Electronic theses and dissertations " +
- "(ETD)\",\"language\": null}],\"type\": \"collection\"}"
- ))
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(mapper.writeValueAsBytes(collectionRest)))
.andExpect(status().isOk())
;
@@ -361,7 +369,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
- CollectionMatcher.matchCollectionEntry("Electronic theses and dissertations (ETD)",
+ CollectionMatcher.matchCollectionEntry("Electronic theses and dissertations",
col1.getID(), col1.getHandle())
)))
.andExpect(jsonPath("$._links.self.href",
@@ -496,7 +504,7 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/collections")
.content(mapper.writeValueAsBytes(collectionRest))
- .param("parentCommunity", parentCommunity.getID().toString())
+ .param("parent", parentCommunity.getID().toString())
.contentType(contentType))
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType))
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 7a5bf09e72..051a4ae0a8 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
@@ -26,6 +26,7 @@ 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.converter.CommunityConverter;
import org.dspace.app.rest.matcher.CommunityMatcher;
import org.dspace.app.rest.matcher.CommunityMetadataMatcher;
import org.dspace.app.rest.model.CommunityRest;
@@ -35,10 +36,14 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.hamcrest.Matchers;
import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest {
+ @Autowired
+ CommunityConverter communityConverter;
+
@Test
public void createTest() throws Exception {
context.turnOffAuthorisationSystem();
@@ -149,7 +154,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/communities")
.content(mapper.writeValueAsBytes(comm))
- .param("parentCommunity", parentCommunity.getID().toString())
+ .param("parent", parentCommunity.getID().toString())
.contentType(contentType))
.andExpect(status().isCreated())
.andExpect(content().contentType(contentType))
@@ -624,15 +629,20 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
String token = getAuthToken(admin.getEmail(), password);
+ ObjectMapper mapper = new ObjectMapper();
+
+ CommunityRest communityRest = communityConverter.fromModel(parentCommunity);
+
+ MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
+ metadataEntryRest.setKey("dc.title");
+ metadataEntryRest.setValue("Electronic theses and dissertations");
+
+ communityRest.setMetadata(Arrays.asList(metadataEntryRest));
+
+
getClient(token).perform(put("/api/core/communities/" + parentCommunity.getID().toString())
- .contentType(MediaType.APPLICATION_JSON).content(
- "{\"id\": \"" + parentCommunity.getID() + "\",\"uuid\": " +
- "\"" + parentCommunity.getID() + "\",\"name\": \"Electronic theses and " +
- "dissertations (ETD)\",\"handle\": \"123456789/5286\",\"metadata\": " +
- "[{\"key\": \"dc.description.abstract\",\"value\": \"\",\"language\": null}," +
- "{\"key\": \"dc.title\",\"value\": \"Electronic theses and dissertations " +
- "(ETD)\",\"language\": null}],\"type\": \"community\"}"
- ))
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(mapper.writeValueAsBytes(communityRest)))
.andExpect(status().isOk())
;
@@ -640,7 +650,7 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
- CommunityMatcher.matchCommunityEntry("Electronic theses and dissertations (ETD)",
+ CommunityMatcher.matchCommunityEntry("Electronic theses and dissertations",
parentCommunity.getID(),
parentCommunity.getHandle())
)))
From 3d011c5411242e88ef871a7639344c5e37abe641 Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Fri, 11 Jan 2019 15:01:59 +0100
Subject: [PATCH 22/68] Applied fixes to catch clauses and added more docs
---
.../repository/CollectionRestRepository.java | 7 +++----
.../rest/repository/CommunityRestRepository.java | 4 +++-
.../rest/repository/DSpaceRestRepository.java | 16 +++++++++++++++-
3 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index ab6f56ed61..31f496b079 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -20,7 +20,6 @@ import javax.ws.rs.BadRequestException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
-import org.apache.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.CollectionConverter;
@@ -57,8 +56,6 @@ import org.springframework.stereotype.Component;
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
public class CollectionRestRepository extends DSpaceRestRepository {
- private static final Logger log = Logger.getLogger(CollectionRestRepository.class);
-
@Autowired
CommunityService communityService;
@@ -256,8 +253,10 @@ public class CollectionRestRepository extends DSpaceRestRepository
Date: Wed, 16 Jan 2019 09:39:14 +0100
Subject: [PATCH 23/68] Fixed RunTimeException messages and addressed
nullpointer error
---
.../rest/repository/CollectionRestRepository.java | 13 ++++++++-----
.../rest/repository/CommunityRestRepository.java | 4 ++--
.../app/rest/repository/DSpaceRestRepository.java | 2 +-
3 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 31f496b079..54957d3068 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -176,9 +176,9 @@ public class CollectionRestRepository extends DSpaceRestRepository
Date: Fri, 18 Jan 2019 07:30:47 +1300
Subject: [PATCH 24/68] WIP commit for oai master port
---
dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
index eae538b50b..21b7f4bae3 100644
--- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
+++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
@@ -57,6 +57,7 @@ import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
+import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.xoai.exceptions.CompilingException;
import org.dspace.xoai.services.api.CollectionsService;
import org.dspace.xoai.services.api.cache.XOAICacheService;
@@ -283,6 +284,7 @@ public class XOAI {
throws DSpaceSolrIndexerException {
try {
int i = 0;
+ int batchSize = configurationService.getIntProperty("oai.import.batch.size", 1000);
SolrServer server = solrServerResolver.getServer();
while (iterator.hasNext()) {
try {
From 6d40a57df7de15033e29c1a3d9c37858da8bbf90 Mon Sep 17 00:00:00 2001
From: Kim Shepherd
Date: Sat, 19 Jan 2019 10:33:00 +1300
Subject: [PATCH 25/68] [DS-4136] Apply same changes as dspace 6.x version (PR
#2320); replace xoai services configurationservice with proper DSpace
configuration service; and replace all instances of legacy configuration
manager with proper DSpace configuration service
---
.../main/java/org/dspace/xoai/app/XOAI.java | 32 +++++++++++++------
dspace/config/modules/oai.cfg | 7 ++++
2 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
index 21b7f4bae3..ed7a66db66 100644
--- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
+++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
@@ -54,16 +54,15 @@ import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
-import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
+import org.dspace.services.ConfigurationService; //added
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.xoai.exceptions.CompilingException;
import org.dspace.xoai.services.api.CollectionsService;
import org.dspace.xoai.services.api.cache.XOAICacheService;
import org.dspace.xoai.services.api.cache.XOAIItemCacheService;
import org.dspace.xoai.services.api.cache.XOAILastCompilationCacheService;
-import org.dspace.xoai.services.api.config.ConfigurationService;
import org.dspace.xoai.services.api.solr.SolrServerResolver;
import org.dspace.xoai.solr.DSpaceSolrSearch;
import org.dspace.xoai.solr.exceptions.DSpaceSolrException;
@@ -95,6 +94,8 @@ public class XOAI {
private final AuthorizeService authorizeService;
private final ItemService itemService;
+ private final static ConfigurationService configurationService = DSpaceServicesFactory
+ .getInstance().getConfigurationService();
private List getFileFormats(Item item) {
List formats = new ArrayList<>();
@@ -286,13 +287,14 @@ public class XOAI {
int i = 0;
int batchSize = configurationService.getIntProperty("oai.import.batch.size", 1000);
SolrServer server = solrServerResolver.getServer();
+ ArrayList list = new ArrayList<>();
while (iterator.hasNext()) {
try {
Item item = iterator.next();
if (item.getHandle() == null) {
log.warn("Skipped item without handle: " + item.getID());
} else {
- server.add(this.index(item));
+ list.add(this.index(item));
}
//Uncache the item to keep memory consumption low
context.uncacheEntity(item);
@@ -302,12 +304,20 @@ public class XOAI {
log.error(ex.getMessage(), ex);
}
i++;
- if (i % 100 == 0) {
+ if (i % 1000 == 0) {
System.out.println(i + " items imported so far...");
}
+ if (i % batchSize == 0) {
+ System.out.println(i + " items imported so far...");
+ server.add(list);
+ server.commit();
+ list.clear();
+ }
}
System.out.println("Total: " + i + " items");
- server.commit();
+ server.add(list);
+ server.commit(true, true);
+ list.clear();
return i;
} catch (SolrServerException | IOException ex) {
throw new DSpaceSolrIndexerException(ex.getMessage(), ex);
@@ -336,6 +346,7 @@ public class XOAI {
dates.add(policy.getEndDate());
}
}
+ context.uncacheEntity(policy);
}
dates.add(item.getLastModified());
Collections.sort(dates);
@@ -460,6 +471,7 @@ public class XOAI {
return true;
}
}
+ context.uncacheEntity(policy);
}
return false;
}
@@ -479,8 +491,8 @@ public class XOAI {
private static boolean getKnownExplanation(Throwable t) {
if (t instanceof ConnectException) {
System.err.println("Solr server ("
- + ConfigurationManager.getProperty("oai", "solr.url")
- + ") is down, turn it on.");
+ + configurationService.getProperty("oai.solr.url", "")
+ + ") is down, turn it on.");
return true;
}
@@ -527,7 +539,7 @@ public class XOAI {
BasicConfiguration.class
});
- ConfigurationService configurationService = applicationContext.getBean(ConfigurationService.class);
+ //ConfigurationService configurationService = applicationContext.getBean(ConfigurationService.class);
XOAICacheService cacheService = applicationContext.getBean(XOAICacheService.class);
XOAIItemCacheService itemCacheService = applicationContext.getBean(XOAIItemCacheService.class);
@@ -549,7 +561,7 @@ public class XOAI {
boolean solr = true; // Assuming solr by default
- solr = !("database").equals(configurationService.getProperty("oai", "storage"));
+ solr = !("database").equals(configurationService.getProperty("oai.storage", "solr"));
boolean run = false;
@@ -654,7 +666,7 @@ public class XOAI {
private static void usage() {
boolean solr = true; // Assuming solr by default
- solr = !("database").equals(ConfigurationManager.getProperty("oai", "storage"));
+ solr = !("database").equals(configurationService.getProperty("oai.storage","solr"));
if (solr) {
System.out.println("OAI Manager Script");
diff --git a/dspace/config/modules/oai.cfg b/dspace/config/modules/oai.cfg
index 5fbce8e880..493eb2510e 100644
--- a/dspace/config/modules/oai.cfg
+++ b/dspace/config/modules/oai.cfg
@@ -31,6 +31,13 @@ oai.cache.enabled = true
# Base Cache Directory
oai.cache.dir = ${dspace.dir}/var/oai
+#---------------------------------------------------------------#
+#--------------OAI IMPORT CONFIGURATION ------------------------#
+#---------------------------------------------------------------#
+
+# Size of batches to commit to solr at a time
+oai.import.batch.size = 1000
+
#---------------------------------------------------------------#
#--------------OAI HARVESTING CONFIGURATIONS--------------------#
#---------------------------------------------------------------#
From 929312d7e8728d33d3425e2b106c444444ea0468 Mon Sep 17 00:00:00 2001
From: Kim Shepherd
Date: Sat, 19 Jan 2019 10:40:21 +1300
Subject: [PATCH 26/68] [DS-4136] tidy up commented out (old)
configurationService instantiation in main()
---
dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
index ed7a66db66..8c2ac8a1f9 100644
--- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
+++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
@@ -539,7 +539,6 @@ public class XOAI {
BasicConfiguration.class
});
- //ConfigurationService configurationService = applicationContext.getBean(ConfigurationService.class);
XOAICacheService cacheService = applicationContext.getBean(XOAICacheService.class);
XOAIItemCacheService itemCacheService = applicationContext.getBean(XOAIItemCacheService.class);
From da1346ef531cf8bd9b1f0693a3ac3d9f915766e6 Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Mon, 28 Jan 2019 10:05:48 -0800
Subject: [PATCH 27/68] Match dspace.restUrl to module name
---
dspace/config/dspace.cfg | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg
index 6cebe39bdc..76c504201a 100644
--- a/dspace/config/dspace.cfg
+++ b/dspace/config/dspace.cfg
@@ -36,7 +36,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}/rest
+dspace.restUrl = ${dspace.baseUrl}/spring-rest
# Optional: DSpace URL for mobile access
# This
From 1957f36988e67a1472a3875c380507daa88176f2 Mon Sep 17 00:00:00 2001
From: Tim Donohue
Date: Wed, 30 Jan 2019 15:24:37 -0600
Subject: [PATCH 28/68] Notes on running tests
---
README.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
diff --git a/README.md b/README.md
index a62fc1943d..aac6b7e6cc 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,57 @@ install, upgrade, customize or host DSpace, then we recommend getting in touch w
The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS/summary
+## Testing
+
+### Running Tests
+
+By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are
+run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all Pull Requests and code commits.
+
+* How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`):
+ ```
+ # NOTE: while "mvn test" runs Unit Tests,
+ # Integration Tests only run for "verify" or "install" phases
+ mvn clean install -Dmaven.test.skip=false -DskipITs=false
+ ```
+* How to run just Unit Tests:
+ ```
+ mvn clean test -Dmaven.test.skip=false
+ ```
+* How to run a *single* Unit Test
+ ```
+ # Run all tests in a specific test class
+ # NOTE: testClassName is just the class name, do not include package
+ mvn clean test -Dmaven.test.skip=false -Dtest=[testClassName]
+
+ # Run one test method in a specific test class
+ mvn clean test -Dmaven.test.skip=false -Dtest=[testClassName]#[testMethodName]
+ ```
+* How to run Integration Tests (requires running Unit tests too)
+ ```
+ mvn clean verify -Dmaven.test.skip=false -DskipITs=false
+ ```
+* How to run a *single* Integration Test (requires running Unit tests too)
+ ```
+ # Run all integration tests in a specific test class
+ # NOTE: Integration Tests only run for "verify" or "install" phases
+ # NOTE: testClassName is just the class name, do not include package
+ mvn clean verify -Dmaven.test.skip=false -DskipITs=false -Dit.test=[testClassName]
+
+ # Run one test method in a specific test class
+ mvn clean verify -Dmaven.test.skip=false -DskipITs=false -Dit.test=[testClassName]#[testMethodName]
+ ```
+* How to run only tests of a specific DSpace module
+ ```
+ # Before you can run only one module's tests, other modules may need installing into your ~/.m2
+ cd [dspace-src]
+ mvn clean install
+
+ # Then, move into a module subdirectory, and run the test command
+ cd [dspace-src]/dspace-spring-rest
+ # Choose your test command from the lists above
+ ```
+
## License
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
From 2db2b70e8201d9616b3ed3be2462a081df413c6e Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Mon, 4 Feb 2019 10:11:52 +0100
Subject: [PATCH 29/68] Altered permissions on the Collection and Community
Repositories and added ITs
---
.../repository/CollectionRestRepository.java | 4 +-
.../repository/CommunityRestRepository.java | 4 +-
.../app/rest/CollectionRestRepositoryIT.java | 118 ++++++++++++++++++
.../app/rest/CommunityRestRepositoryIT.java | 106 ++++++++++++++++
4 files changed, 228 insertions(+), 4 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 54957d3068..9f25e12d19 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -214,7 +214,7 @@ public class CollectionRestRepository extends DSpaceRestRepository
Date: Mon, 26 Nov 2018 11:59:50 +0100
Subject: [PATCH 30/68] Implemented the create method in the ItemRestRepository
---
.../app/rest/converter/ItemConverter.java | 1 +
.../org/dspace/app/rest/model/ItemRest.java | 10 ++
.../rest/repository/ItemRestRepository.java | 56 +++++++++++
.../dspace/app/rest/ItemRestRepositoryIT.java | 95 +++++++++++++++++++
.../dspace/app/rest/matcher/ItemMatcher.java | 2 +
5 files changed, 164 insertions(+)
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 8c9743457c..1a8221161f 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
@@ -46,6 +46,7 @@ public class ItemConverter extends DSpaceObjectConverter {
@Autowired
ItemPatch itemPatch;
+ @Autowired
+ WorkspaceItemService workspaceItemService;
+
+ @Autowired
+ CollectionService collectionService;
+
+ @Autowired
+ DSpaceObjectUtils dspaceObjectUtils;
+
+ @Autowired
+ InstallItemService installItemService;
public ItemRestRepository() {
System.out.println("Repository initialized by Spring");
@@ -177,4 +198,39 @@ public class ItemRestRepository extends DSpaceRestRepository {
}
}
+ @Override
+ @PreAuthorize("hasAuthority('ADMIN')")
+ protected ItemRest createAndReturn(Context context) throws AuthorizeException, SQLException {
+ HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = null;
+ try {
+ ServletInputStream input = req.getInputStream();
+ itemRest = mapper.readValue(input, ItemRest.class);
+ } catch (IOException e1) {
+ throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
+ }
+
+ if (itemRest.getInArchive() == false) {
+ throw new BadRequestException("InArchive attribute should not be set to false for the create");
+ }
+ Collection collection = collectionService.find(context,
+ UUIDUtils.fromString(itemRest.getOwningCollectionUuid()));
+ if (collection == null) {
+ throw new BadRequestException("The given collection in the body is invalid: "
+ + itemRest.getOwningCollectionUuid());
+ }
+ WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false);
+ Item item = workspaceItem.getItem();
+ item.setArchived(true);
+ item.setOwningCollection(collection);
+ item.setDiscoverable(itemRest.getDiscoverable());
+ item.setLastModified(itemRest.getLastModified());
+ dspaceObjectUtils.replaceMetadataValues(context, item, itemRest.getMetadata());
+
+ Item itemToReturn = installItemService.installItem(context, workspaceItem);
+
+ return converter.fromModel(itemToReturn);
+ }
+
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index 55de139f29..8ed44ca86f 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -7,20 +7,26 @@
*/
package org.dspace.app.rest;
+import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import javax.ws.rs.core.MediaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.CharEncoding;
import org.dspace.app.rest.builder.BitstreamBuilder;
@@ -31,6 +37,8 @@ import org.dspace.app.rest.builder.GroupBuilder;
import org.dspace.app.rest.builder.ItemBuilder;
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
import org.dspace.app.rest.matcher.ItemMatcher;
+import org.dspace.app.rest.model.ItemRest;
+import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
@@ -43,6 +51,7 @@ import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.hamcrest.Matchers;
import org.junit.Test;
+import org.springframework.test.web.servlet.MvcResult;
public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
@@ -1414,4 +1423,90 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
Matchers.containsString("/api/core/items")));
}
+ @Test
+ public void testCreateItem() 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();
+
+
+
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = new ItemRest();
+ itemRest.setName("Practices of research data curation in institutional repositories:" +
+ " A qualitative view from repository staff");
+ itemRest.setOwningCollectionUuid(col1.getID().toString());
+ itemRest.setInArchive(true);
+ itemRest.setDiscoverable(true);
+ itemRest.setWithdrawn(false);
+
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample item created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ itemRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+ String token = getAuthToken(admin.getEmail(), password);
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ .content(mapper.writeValueAsBytes(itemRest)).contentType(contentType))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String content = mvcResult.getResponse().getContentAsString();
+ Map map = mapper.readValue(content, Map.class);
+ String itemUuidString = String.valueOf(map.get("uuid"));
+ String itemHandleString = String.valueOf(map.get("handle"));
+
+ //TODO Refactor this to use the converter to Item instead of checking every property separately
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", Matchers.allOf(
+ hasJsonPath("$.id", is(itemUuidString)),
+ hasJsonPath("$.uuid", is(itemUuidString)),
+ hasJsonPath("$.name", is("Title Text")),
+ hasJsonPath("$.handle", is(itemHandleString)),
+ hasJsonPath("$.type", is("item")),
+ hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
+ contains("Title Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
+ contains("Custom Copyright Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
+ contains("HTML News
")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
+ contains("Sample item created via the REST API")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
+ contains("Some cool HTML code here
"))
+
+ )));
+ }
+
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
index e5176eea26..28850fc6ff 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
@@ -64,4 +64,6 @@ public class ItemMatcher {
);
}
+
+
}
From 2e446bf9a33a2b7a2f2f2a34dca484f50a7a550b Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Tue, 4 Dec 2018 16:06:42 +0100
Subject: [PATCH 31/68] Added admin access to item delete and wrote tests
---
.../rest/repository/ItemRestRepository.java | 1 +
.../dspace/app/rest/ItemRestRepositoryIT.java | 187 ++++++++++++++++++
2 files changed, 188 insertions(+)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
index 411c693c83..3764f3f272 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
@@ -176,6 +176,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
}
@Override
+ @PreAuthorize("hasAuthority('ADMIN')")
protected void delete(Context context, UUID id) throws AuthorizeException {
Item item = null;
try {
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index 8ed44ca86f..d1f46541e3 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -1509,4 +1509,191 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
)));
}
+
+ @Test
+ public void testDeleteItem() 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();
+
+
+
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = new ItemRest();
+ itemRest.setName("Practices of research data curation in institutional repositories:" +
+ " A qualitative view from repository staff");
+ itemRest.setOwningCollectionUuid(col1.getID().toString());
+ itemRest.setInArchive(true);
+ itemRest.setDiscoverable(true);
+ itemRest.setWithdrawn(false);
+
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample item created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ itemRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+ String token = getAuthToken(admin.getEmail(), password);
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ .content(mapper.writeValueAsBytes(itemRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String content = mvcResult.getResponse().getContentAsString();
+ Map map = mapper.readValue(content, Map.class);
+ String itemUuidString = String.valueOf(map.get("uuid"));
+ String itemHandleString = String.valueOf(map.get("handle"));
+
+ //TODO Refactor this to use the converter to Item instead of checking every property separately
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", Matchers.allOf(
+ hasJsonPath("$.id", is(itemUuidString)),
+ hasJsonPath("$.uuid", is(itemUuidString)),
+ hasJsonPath("$.name", is("Title Text")),
+ hasJsonPath("$.handle", is(itemHandleString)),
+ hasJsonPath("$.type", is("item")),
+ hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
+ contains("Title Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
+ contains("Custom Copyright Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
+ contains("HTML News
")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
+ contains("Sample item created via the REST API")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
+ contains("Some cool HTML code here
"))
+
+ )));
+
+ getClient(token).perform(delete("/api/core/items/" + itemUuidString))
+ .andExpect(status().isNoContent());
+
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void testDeleteItemUnauthorized() 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();
+
+
+
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = new ItemRest();
+ itemRest.setName("Practices of research data curation in institutional repositories:" +
+ " A qualitative view from repository staff");
+ itemRest.setOwningCollectionUuid(col1.getID().toString());
+ itemRest.setInArchive(true);
+ itemRest.setDiscoverable(true);
+ itemRest.setWithdrawn(false);
+
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample item created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ itemRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+ String token = getAuthToken(admin.getEmail(), password);
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ .content(mapper.writeValueAsBytes(itemRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String content = mvcResult.getResponse().getContentAsString();
+ Map map = mapper.readValue(content, Map.class);
+ String itemUuidString = String.valueOf(map.get("uuid"));
+ String itemHandleString = String.valueOf(map.get("handle"));
+
+ //TODO Refactor this to use the converter to Item instead of checking every property separately
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", Matchers.allOf(
+ hasJsonPath("$.id", is(itemUuidString)),
+ hasJsonPath("$.uuid", is(itemUuidString)),
+ hasJsonPath("$.name", is("Title Text")),
+ hasJsonPath("$.handle", is(itemHandleString)),
+ hasJsonPath("$.type", is("item")),
+ hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
+ contains("Title Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
+ contains("Custom Copyright Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
+ contains("HTML News
")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
+ contains("Sample item created via the REST API")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
+ contains("Some cool HTML code here
"))
+
+ )));
+
+ getClient().perform(delete("/api/core/items/" + itemUuidString))
+ .andExpect(status().isUnauthorized());
+
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isOk());
+ }
+
}
\ No newline at end of file
From db8f6f1bb8bbccbf7a6e6993e5937aadefc56f08 Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Fri, 7 Dec 2018 09:58:13 +0100
Subject: [PATCH 32/68] Fixed the 500 internal server error when calling item
delete endpoint with invalid UUID
---
.../rest/repository/ItemRestRepository.java | 4 +++
.../dspace/app/rest/ItemRestRepositoryIT.java | 29 +++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
index 3764f3f272..50082bf4d5 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
@@ -181,6 +181,10 @@ public class ItemRestRepository extends DSpaceRestRepository {
Item item = null;
try {
item = is.find(context, id);
+ if (item == null) {
+ throw new ResourceNotFoundException(ItemRest.CATEGORY + "." + ItemRest.NAME +
+ " with id: " + id + " not found");
+ }
if (is.isInProgressSubmission(context, item)) {
throw new UnprocessableEntityException("The item cannot be deleted. "
+ "It's part of a in-progress submission.");
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index d1f46541e3..181f1dd075 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -1696,4 +1696,33 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
.andExpect(status().isOk());
}
+ @Test
+ public void deleteOneWrongUuidResourceNotFoundTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ //** GIVEN **
+ //1. A community with one collection.
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .build();
+ Collection col1 = CollectionBuilder
+ .createCollection(context, parentCommunity).withName("Collection 1").build();
+
+ //2. One public item, one workspace item and one template item.
+ Item publicItem = ItemBuilder.createItem(context, col1)
+ .withTitle("Public item 1")
+ .withIssueDate("2017-10-17")
+ .withAuthor("Smith, Donald").withAuthor("Doe, John")
+ .withSubject("ExtraEntry")
+ .build();
+
+
+ String token = getAuthToken(admin.getEmail(), password);
+
+ //Delete public item
+ getClient(token).perform(delete("/api/core/items/" + parentCommunity.getID()))
+ .andExpect(status().is(404));
+
+ }
+
}
\ No newline at end of file
From 02ff91259f8768b6373e52149dfe93c8ea3978ae Mon Sep 17 00:00:00 2001
From: Kevin Van de Velde
Date: Wed, 12 Dec 2018 13:13:04 +0100
Subject: [PATCH 33/68] [DS-4108] Rest api item CRUD: Updating item metadata
---
.../app/rest/RestResourceController.java | 2 +-
.../rest/repository/DSpaceRestRepository.java | 2 +-
.../rest/repository/ItemRestRepository.java | 38 +++++++
.../dspace/app/rest/ItemRestRepositoryIT.java | 107 ++++++++++++++++++
4 files changed, 147 insertions(+), 2 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 5a27ec4087..51d673c1d6 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
@@ -1039,4 +1039,4 @@ public class RestResourceController implements InitializingBean {
linkService.addLinks(result);
return result;
}
-}
+}
\ 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 ab317aef4a..5c3b335a65 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
@@ -447,4 +447,4 @@ public abstract class DSpaceRestRepository {
@Autowired
WorkspaceItemService workspaceItemService;
+ @Autowired
+ ItemService itemService;
+
@Autowired
CollectionService collectionService;
@@ -238,4 +245,35 @@ public class ItemRestRepository extends DSpaceRestRepository {
return converter.fromModel(itemToReturn);
}
+ @Override
+ @PreAuthorize("hasPermission(#id, 'ITEM', 'WRITE')")
+ protected ItemRest put(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
+ JsonNode jsonNode)
+ throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException {
+ HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = null;
+ try {
+ itemRest = mapper.readValue(jsonNode.toString(), ItemRest.class);
+ } catch (IOException e1) {
+ throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
+ }
+
+ Item item = itemService.find(context, uuid);
+ if (item == null) {
+ throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
+ }
+
+ if (StringUtils.equals(uuid.toString(), itemRest.getId())) {
+ List metadataEntryRestList = itemRest.getMetadata();
+ item = (Item) dspaceObjectUtils.replaceMetadataValues(context,
+ item,
+ metadataEntryRestList);
+ } else {
+ throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
+ + uuid + ", "
+ + itemRest.getId());
+ }
+ return converter.fromModel(item);
+ }
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index 181f1dd075..2323430819 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -14,6 +14,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
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.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -1509,6 +1510,112 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
)));
}
+ @Test
+ public void updateTest() throws Exception {
+ //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 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();
+
+ ObjectMapper mapper = new ObjectMapper();
+ ItemRest itemRest = new ItemRest();
+ itemRest.setName("Practices of research data curation in institutional repositories:" +
+ " A qualitative view from repository staff");
+ itemRest.setOwningCollectionUuid(col1.getID().toString());
+ itemRest.setInArchive(true);
+ itemRest.setDiscoverable(true);
+ itemRest.setWithdrawn(false);
+
+ MetadataEntryRest description = new MetadataEntryRest();
+ description.setKey("dc.description");
+ description.setValue("Some cool HTML code here
");
+
+ MetadataEntryRest abs = new MetadataEntryRest();
+ abs.setKey("dc.description.abstract");
+ abs.setValue("Sample item created via the REST API");
+
+ MetadataEntryRest contents = new MetadataEntryRest();
+ contents.setKey("dc.description.tableofcontents");
+ contents.setValue("HTML News
");
+
+ MetadataEntryRest copyright = new MetadataEntryRest();
+ copyright.setKey("dc.rights");
+ copyright.setValue("Custom Copyright Text");
+
+ MetadataEntryRest title = new MetadataEntryRest();
+ title.setKey("dc.title");
+ title.setValue("Title Text");
+
+ itemRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+
+ String token = getAuthToken(admin.getEmail(), password);
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ .content(mapper.writeValueAsBytes(itemRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String content = mvcResult.getResponse().getContentAsString();
+ Map map = mapper.readValue(content, Map.class);
+ String itemUuidString = String.valueOf(map.get("uuid"));
+ String itemHandleString = String.valueOf(map.get("handle"));
+
+
+ title.setValue("New title");
+ copyright.setValue("New Custom Copyright Text");
+
+ itemRest.setUuid(itemUuidString);
+ itemRest.setHandle(itemHandleString);
+ itemRest.setMetadata(Arrays.asList(description,
+ abs,
+ contents,
+ copyright,
+ title));
+ itemRest.setName("New title");
+
+ mvcResult = getClient(token).perform(put("/api/core/items/" + itemUuidString)
+ .content(mapper.writeValueAsBytes(itemRest))
+ .contentType(contentType))
+ .andExpect(status().isOk())
+ .andReturn();
+ map = mapper.readValue(content, Map.class);
+ itemUuidString = String.valueOf(map.get("uuid"));
+ itemHandleString = String.valueOf(map.get("handle"));
+
+ //TODO Refactor this to use the converter to Item instead of checking every property separately
+ getClient(token).perform(get("/api/core/items/" + itemUuidString))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", Matchers.allOf(
+ hasJsonPath("$.id", is(itemUuidString)),
+ hasJsonPath("$.uuid", is(itemUuidString)),
+ hasJsonPath("$.name", is("New title")),
+ hasJsonPath("$.handle", is(itemHandleString)),
+ hasJsonPath("$.type", is("item")),
+ hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
+ contains("New title")),
+ hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
+ contains("New Custom Copyright Text")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
+ contains("HTML News
")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
+ contains("Sample item created via the REST API")),
+ hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
+ contains("Some cool HTML code here
"))
+
+ )));
+ }
+
@Test
public void testDeleteItem() throws Exception {
From 47d7021350a411d2ed8d1efb0ecdfe1f4d2d5a0c Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Mon, 7 Jan 2019 09:56:06 +0100
Subject: [PATCH 34/68] Added owningCollection as parameter to the POST Item
endpoint and removed this from ItemRest. Also added documentation for several
public methods.
---
.../dspace/app/rest/RestResourceController.java | 6 +++---
.../dspace/app/rest/converter/ItemConverter.java | 1 -
.../java/org/dspace/app/rest/model/ItemRest.java | 11 -----------
.../rest/repository/DSpaceRestRepository.java | 10 +++++++---
.../app/rest/repository/ItemRestRepository.java | 9 +++++----
.../dspace/app/rest/ItemRestRepositoryIT.java | 16 ++++++++--------
6 files changed, 23 insertions(+), 30 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 51d673c1d6..dea2395731 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,18 +990,18 @@ public class RestResourceController implements InitializingBean {
/**
* Execute a PUT request for an entity with id of type UUID;
*
- * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}
+ * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}/{uuid}
*
* Example:
*
* {@code
- * curl -X PUT http:///dspace-spring-rest/api/collection
+ * curl -X PUT http:///dspace-spring-rest/api/collection/320c0492-de1d-4646-9e69-193d36b366e9
* }
*
*
* @param request the http request
* @param apiCategory the API category e.g. "api"
- * @param model the DSpace model e.g. "metadatafield"
+ * @param model the DSpace model e.g. "collection"
* @param uuid 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
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 1a8221161f..8c9743457c 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
@@ -46,7 +46,6 @@ public class ItemConverter extends DSpaceObjectConverter bitstreams;
@Override
@@ -102,12 +99,4 @@ public class ItemRest extends DSpaceObjectRest {
public void setBitstreams(List bitstreams) {
this.bitstreams = bitstreams;
}
-
- public String getOwningCollectionUuid() {
- return owningCollectionUuid;
- }
-
- public void setOwningCollectionUuid(String owningCollectionUuid) {
- this.owningCollectionUuid = owningCollectionUuid;
- }
}
\ 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 5c3b335a65..0be6f7475a 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
@@ -433,14 +433,18 @@ public abstract class DSpaceRestRepository {
@PreAuthorize("hasAuthority('ADMIN')")
protected ItemRest createAndReturn(Context context) throws AuthorizeException, SQLException {
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
+ String owningCollectionUuidString = req.getParameter("owningCollection");
ObjectMapper mapper = new ObjectMapper();
ItemRest itemRest = null;
try {
@@ -226,11 +227,11 @@ public class ItemRestRepository extends DSpaceRestRepository {
if (itemRest.getInArchive() == false) {
throw new BadRequestException("InArchive attribute should not be set to false for the create");
}
- Collection collection = collectionService.find(context,
- UUIDUtils.fromString(itemRest.getOwningCollectionUuid()));
+ UUID owningCollectionUuid = UUIDUtils.fromString(owningCollectionUuidString);
+ Collection collection = collectionService.find(context, owningCollectionUuid);
if (collection == null) {
- throw new BadRequestException("The given collection in the body is invalid: "
- + itemRest.getOwningCollectionUuid());
+ throw new BadRequestException("The given owningCollection parameter is invalid: "
+ + owningCollectionUuid);
}
WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false);
Item item = workspaceItem.getItem();
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index 2323430819..e0098d3453 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -1445,7 +1445,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
ItemRest itemRest = new ItemRest();
itemRest.setName("Practices of research data curation in institutional repositories:" +
" A qualitative view from repository staff");
- itemRest.setOwningCollectionUuid(col1.getID().toString());
itemRest.setInArchive(true);
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
@@ -1477,7 +1476,8 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
title));
String token = getAuthToken(admin.getEmail(), password);
- MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
+ col1.getID().toString())
.content(mapper.writeValueAsBytes(itemRest)).contentType(contentType))
.andExpect(status().isCreated())
.andReturn();
@@ -1528,7 +1528,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
ItemRest itemRest = new ItemRest();
itemRest.setName("Practices of research data curation in institutional repositories:" +
" A qualitative view from repository staff");
- itemRest.setOwningCollectionUuid(col1.getID().toString());
itemRest.setInArchive(true);
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
@@ -1560,7 +1559,8 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
title));
String token = getAuthToken(admin.getEmail(), password);
- MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
+ col1.getID().toString())
.content(mapper.writeValueAsBytes(itemRest))
.contentType(contentType))
.andExpect(status().isCreated())
@@ -1638,7 +1638,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
ItemRest itemRest = new ItemRest();
itemRest.setName("Practices of research data curation in institutional repositories:" +
" A qualitative view from repository staff");
- itemRest.setOwningCollectionUuid(col1.getID().toString());
itemRest.setInArchive(true);
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
@@ -1670,7 +1669,8 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
title));
String token = getAuthToken(admin.getEmail(), password);
- MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
+ col1.getID().toString())
.content(mapper.writeValueAsBytes(itemRest))
.contentType(contentType))
.andExpect(status().isCreated())
@@ -1731,7 +1731,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
ItemRest itemRest = new ItemRest();
itemRest.setName("Practices of research data curation in institutional repositories:" +
" A qualitative view from repository staff");
- itemRest.setOwningCollectionUuid(col1.getID().toString());
itemRest.setInArchive(true);
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
@@ -1763,7 +1762,8 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
title));
String token = getAuthToken(admin.getEmail(), password);
- MvcResult mvcResult = getClient(token).perform(post("/api/core/items")
+ MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
+ col1.getID().toString())
.content(mapper.writeValueAsBytes(itemRest))
.contentType(contentType))
.andExpect(status().isCreated())
From 05cb94965547002272bc372ea918da23264e6e81 Mon Sep 17 00:00:00 2001
From: Kevin Van de Velde
Date: Thu, 17 Jan 2019 15:42:43 +0100
Subject: [PATCH 35/68] Small changes in how exceptions are handled in the
ItemRestRepository, DSpaceRestRepository classes
---
.../app/rest/exception/UnprocessableEntityException.java | 4 ++++
.../org/dspace/app/rest/repository/ItemRestRepository.java | 4 ++--
.../test/java/org/dspace/app/rest/matcher/ItemMatcher.java | 2 --
3 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/UnprocessableEntityException.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/UnprocessableEntityException.java
index aa2a9106a3..8bbd7c3909 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/UnprocessableEntityException.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/UnprocessableEntityException.java
@@ -27,6 +27,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY, reason = "Unprocessable request")
public class UnprocessableEntityException extends RuntimeException {
+ public UnprocessableEntityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
public UnprocessableEntityException(String message) {
super(message);
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
index 3863ab2ced..4b70b06ac6 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
@@ -221,7 +221,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
ServletInputStream input = req.getInputStream();
itemRest = mapper.readValue(input, ItemRest.class);
} catch (IOException e1) {
- throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
+ throw new UnprocessableEntityException("Error parsing request body", e1);
}
if (itemRest.getInArchive() == false) {
@@ -257,7 +257,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
try {
itemRest = mapper.readValue(jsonNode.toString(), ItemRest.class);
} catch (IOException e1) {
- throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
+ throw new UnprocessableEntityException("Error parsing request body", e1);
}
Item item = itemService.find(context, uuid);
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
index 28850fc6ff..e5176eea26 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
@@ -64,6 +64,4 @@ public class ItemMatcher {
);
}
-
-
}
From 78f7066c94d0e9e5dc92eaff67c9d8a6555d40c2 Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Wed, 6 Feb 2019 16:19:10 +0100
Subject: [PATCH 36/68] [DS-4164] fixed the bug in the error handling
---
.../org/dspace/app/rest/OpenSearchController.java | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/OpenSearchController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/OpenSearchController.java
index ebba89fff9..37664d0f51 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/OpenSearchController.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/OpenSearchController.java
@@ -43,7 +43,6 @@ import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoverySearchFilter;
-import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -60,7 +59,7 @@ import org.w3c.dom.Document;
*/
@Controller
@RequestMapping("/opensearch")
-public class OpenSearchController implements ErrorController {
+public class OpenSearchController {
private static final Logger log = Logger.getLogger(ScopeResolver.class);
private static final String errorpath = "/error";
@@ -192,16 +191,6 @@ public class OpenSearchController implements ErrorController {
}
}
- @RequestMapping(value = errorpath)
- public String error() {
- return "Error handling";
- }
-
- @Override
- public String getErrorPath() {
- return errorpath;
- }
-
/**
* Internal method for controller initialization
*/
From d489636641f067c999efbdc9d9bb09a14569e462 Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Wed, 6 Feb 2019 10:24:35 -0800
Subject: [PATCH 37/68] Migrate PR2307
---
.dockerignore | 1 +
Dockerfile.dependencies | 24 +++++++++++++++++++++
Dockerfile.jdk8 | 34 ++++++++++++++++--------------
Dockerfile.jdk8-test | 46 ++++++++++++++++++++++-------------------
4 files changed, 68 insertions(+), 37 deletions(-)
create mode 100644 Dockerfile.dependencies
diff --git a/.dockerignore b/.dockerignore
index 670bcb2e25..762ee391c2 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -3,3 +3,4 @@
.settings/
*/target/
dspace/modules/*/target/
+Dockerfile.*
\ No newline at end of file
diff --git a/Dockerfile.dependencies b/Dockerfile.dependencies
new file mode 100644
index 0000000000..a7107d46b5
--- /dev/null
+++ b/Dockerfile.dependencies
@@ -0,0 +1,24 @@
+# This image will be published as dspace/dspace-dependencies
+# The purpose of this image is to make the build for dspace/dspace run faster
+
+# Step 1 - Run Maven Build
+FROM maven:3-jdk-8 as build
+ARG TARGET_DIR=dspace-installer
+WORKDIR /app
+
+RUN useradd dspace \
+ && mkdir /home/dspace \
+ && chown -Rv dspace: /home/dspace
+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
+
+# Trigger the installation of all maven dependencies
+# Clean up the built artifacts in the same step to keep the docker image small
+RUN mvn package && mvn clean
+
+# Clear the contents of the /app directory so no artifacts are left when dspace:dspace is built
+USER root
+RUN rm -rf /app/*
\ No newline at end of file
diff --git a/Dockerfile.jdk8 b/Dockerfile.jdk8
index ec7084f49c..ec465b50b3 100644
--- a/Dockerfile.jdk8
+++ b/Dockerfile.jdk8
@@ -9,20 +9,30 @@
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8
# Step 1 - Run Maven Build
-FROM maven:3-jdk-8 as 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
+
+USER dspace
+
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
-ADD . /app/
+ADD --chown=dspace . /app/
COPY dspace/src/main/docker/local.cfg /app/local.cfg
-RUN mvn package
+# 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 /app /dspace-src
-WORKDIR /dspace-src/dspace/target/${TARGET_DIR}
+COPY --from=build /install /dspace-src
+WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.5
@@ -32,23 +42,15 @@ 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 update_configs update_code update_webapps update_solr_indexes
+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
-COPY --from=ant_build /dspace /dspace
+ENV DSPACE_INSTALL=/dspace
+COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
-# Ant will be embedded in the final container to allow additional deployments
-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
-
-ENV DSPACE_INSTALL=/dspace
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
diff --git a/Dockerfile.jdk8-test b/Dockerfile.jdk8-test
index 94d85a9e8f..e4f398d867 100644
--- a/Dockerfile.jdk8-test
+++ b/Dockerfile.jdk8-test
@@ -5,28 +5,34 @@
# - tomcat:8-jre8
# - ANT 1.10.5
# - maven:3-jdk-8
-# - note: expose /solr to any host; provide /rest over http
+# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8-test
# Step 1 - Run Maven Build
-FROM maven:3-jdk-8 as 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
+
+USER dspace
+
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
-ADD . /app/
+ADD --chown=dspace . /app/
COPY dspace/src/main/docker/local.cfg /app/local.cfg
-# Provide web.xml overrides to make webapps easier to test
-COPY dspace/src/main/docker/test/solr_web.xml /app/dspace-solr/src/main/webapp/WEB-INF/web.xml
-COPY dspace/src/main/docker/test/rest_web.xml /app/dspace-rest/src/main/webapp/WEB-INF/web.xml
-
-RUN mvn package
+# 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 /app /dspace-src
-WORKDIR /dspace-src/dspace/target/${TARGET_DIR}
+COPY --from=build /install /dspace-src
+WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.5
@@ -36,23 +42,15 @@ 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 update_configs update_code update_webapps update_solr_indexes
+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
-COPY --from=ant_build /dspace /dspace
+ENV DSPACE_INSTALL=/dspace
+COPY --from=ant_build /dspace $DSPACE_INSTALL
EXPOSE 8080 8009
-# Ant will be embedded in the final container to allow additional deployments
-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
-
-ENV DSPACE_INSTALL=/dspace
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
@@ -62,3 +60,9 @@ RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr
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
+
+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
From d90e60a92b6109b0596e13e260cdce4879ee42bb Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Wed, 6 Feb 2019 15:28:53 -0800
Subject: [PATCH 38/68] Sync docker solr web.xml with web.xml
---
dspace/src/main/docker/test/solr_web.xml | 58 ++++++++++++++----------
1 file changed, 34 insertions(+), 24 deletions(-)
diff --git a/dspace/src/main/docker/test/solr_web.xml b/dspace/src/main/docker/test/solr_web.xml
index 4329317c53..50a8bd5b9a 100644
--- a/dspace/src/main/docker/test/solr_web.xml
+++ b/dspace/src/main/docker/test/solr_web.xml
@@ -1,6 +1,4 @@
-
-
+
-
-
-
- solr/home
${dspace.dir}/solr
java.lang.String
-
+
- log4j.configuration
- ${dspace.dir}/config/log4j-solr.properties
- URL locating a Log4J configuration file (properties or XML).
+
+ 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
@@ -87,7 +92,16 @@
-->
-
-
- org.dspace.solr.filters.ConfigureLog4jListener
-
-
Zookeeper
org.apache.solr.servlet.ZookeeperInfoServlet
From aa4125c9e9bb31b946ea11d6f676f3439447e983 Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Thu, 7 Feb 2019 15:39:15 +0100
Subject: [PATCH 39/68] Removed the name check from the
DspaceObjectRestEqualityUtils
---
.../dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java
index b7d6e37b1b..c71eb5bf85 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectRestEqualityUtils.java
@@ -27,8 +27,7 @@ public class DSpaceObjectRestEqualityUtils {
public boolean isDSpaceObjectEqualsWithoutMetadata(DSpaceObjectRest original, DSpaceObjectRest updated) {
return StringUtils.equals(original.getId(), updated.getId()) &&
StringUtils.equals(original.getCategory(), updated.getCategory()) &&
- StringUtils.equals(original.getHandle(), updated.getHandle()) &&
- StringUtils.equals(original.getName(), updated.getName());
+ StringUtils.equals(original.getHandle(), updated.getHandle());
}
}
From 42942978a801a0425c52461d364944a3ddce2cf5 Mon Sep 17 00:00:00 2001
From: Samuel
Date: Wed, 12 Dec 2018 14:31:54 +0100
Subject: [PATCH 40/68] Added support for the CRUD operations on the
MetadataField and MetadataSchema REST endpoints
---
.../content/MetadataSchemaServiceImpl.java | 12 +-
.../app/rest/RestResourceController.java | 8 +
.../app/rest/model/MetadataFieldRest.java | 2 +
.../app/rest/model/MetadataSchemaRest.java | 2 +
.../MetadataFieldRestRepository.java | 137 +++++++++-
.../MetadataSchemaRestRepository.java | 118 ++++++++-
.../rest/MetadataSchemaRestRepositoryIT.java | 235 ++++++++++++++++--
.../rest/MetadatafieldRestRepositoryIT.java | 229 ++++++++++++++++-
.../rest/matcher/MetadataschemaMatcher.java | 12 +-
9 files changed, 724 insertions(+), 31 deletions(-)
diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java
index 185addfb01..d5c2c22f88 100644
--- a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaServiceImpl.java
@@ -14,6 +14,7 @@ import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.dao.MetadataSchemaDAO;
+import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
@@ -33,6 +34,9 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService {
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataSchemaServiceImpl.class);
+ @Autowired
+ protected MetadataFieldService metadataFieldService;
+
@Autowired(required = true)
protected AuthorizeService authorizeService;
@@ -115,10 +119,14 @@ public class MetadataSchemaServiceImpl implements MetadataSchemaService {
"Only administrators may modify the metadata registry");
}
- log.info(LogManager.getHeader(context, "delete_metadata_schema",
- "metadata_schema_id=" + metadataSchema.getID()));
+ for (MetadataField metadataField : metadataFieldService.findAllInSchema(context, metadataSchema)) {
+ metadataFieldService.delete(context, metadataField);
+ }
metadataSchemaDAO.delete(context, metadataSchema);
+
+ log.info(LogManager.getHeader(context, "delete_metadata_schema",
+ "metadata_schema_id=" + metadataSchema.getID()));
}
@Override
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 dea2395731..1e4631cec3 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
@@ -987,6 +987,14 @@ public class RestResourceController implements InitializingBean {
}
+ @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);
+ }
+
/**
* Execute a PUT request for an entity with id of type UUID;
*
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
index 51fafd52d5..3fc017db01 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
@@ -8,6 +8,7 @@
package org.dspace.app.rest.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.dspace.app.rest.RestResourceController;
/**
@@ -15,6 +16,7 @@ import org.dspace.app.rest.RestResourceController;
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataFieldRest extends BaseObjectRest {
public static final String NAME = "metadatafield";
public static final String CATEGORY = RestAddressableModel.CORE;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
index c6244af87e..649e2e6e2d 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
@@ -7,6 +7,7 @@
*/
package org.dspace.app.rest.model;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.dspace.app.rest.RestResourceController;
/**
@@ -14,6 +15,7 @@ import org.dspace.app.rest.RestResourceController;
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
+@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataSchemaRest extends BaseObjectRest {
public static final String NAME = "metadataschema";
public static final String CATEGORY = RestAddressableModel.CORE;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
index dddb62b5da..44c5ef0723 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
@@ -7,22 +7,37 @@
*/
package org.dspace.app.rest.repository;
+import static java.lang.Integer.parseInt;
+import static org.apache.commons.lang.StringUtils.isBlank;
+
+import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
+import java.util.Objects;
+import javax.servlet.http.HttpServletRequest;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.MetadataFieldConverter;
+import org.dspace.app.rest.exception.PatchBadRequestException;
+import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.MetadataFieldRest;
import org.dspace.app.rest.model.hateoas.MetadataFieldResource;
+import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
+import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
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.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
@@ -34,7 +49,7 @@ import org.springframework.stereotype.Component;
public class MetadataFieldRestRepository extends DSpaceRestRepository {
@Autowired
- MetadataFieldService metaFieldService;
+ MetadataFieldService metadataFieldService;
@Autowired
MetadataSchemaService metadataSchemaService;
@@ -49,7 +64,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) {
List metadataField = null;
try {
- metadataField = metaFieldService.findAll(context);
+ metadataField = metadataFieldService.findAll(context);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -73,7 +88,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository findBySchema(@Parameter(value = "schema", required = true) String schemaName,
- Pageable pageable) {
+ Pageable pageable) {
Context context = obtainContext();
List metadataFields = null;
try {
@@ -81,7 +96,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository {
@Autowired
- MetadataSchemaService metaScemaService;
+ MetadataSchemaService metadataSchemaService;
@Autowired
MetadataSchemaConverter converter;
@@ -42,7 +56,7 @@ public class MetadataSchemaRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) {
List metadataSchema = null;
try {
- metadataSchema = metaScemaService.findAll(context);
+ metadataSchema = metadataSchemaService.findAll(context);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -73,4 +87,102 @@ public class MetadataSchemaRestRepository extends DSpaceRestRepository idRef = new AtomicReference<>();
+
+ try {
+
+ assertThat(metadataSchemaService.find(context, TEST_NAME), nullValue());
+
+ getClient(authToken)
+ .perform(post("/api/core/metadataschemas")
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
+
+ MetadataSchema metadataSchema = metadataSchemaService.find(context, idRef.get());
+ assertThat(metadataSchema, notNullValue());
+
+ assertEquals(metadataSchema.getID(), idRef.get());
+ assertEquals(metadataSchema.getName(), TEST_NAME);
+ assertEquals(metadataSchema.getNamespace(), TEST_NAMESPACE);
+
+ } finally {
+ deleteMetadataSchemaIfExists(TEST_NAME);
+ }
+ }
+
+ @Test
+ public void createUnauthauthorizedTest()
+ throws Exception {
+
+ MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
+ metadataSchemaRest.setPrefix(TEST_NAME);
+ metadataSchemaRest.setNamespace(TEST_NAMESPACE);
+
+ try {
+ getClient()
+ .perform(post("/api/core/metadataschemas")
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ } finally {
+ deleteMetadataSchemaIfExists(TEST_NAME);
+ }
+ }
+
+ @Test
+ public void deleteSuccess() throws Exception {
+
+ MetadataSchema metadataSchema = createMetadataSchema();
+
+ try {
+
+ assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
+
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isNoContent());
+
+ assertThat(metadataSchemaService.find(context, metadataSchema.getID()), nullValue());
+
+ } finally {
+ deleteMetadataSchemaIfExists(TEST_NAME);
+ }
+ }
+
+ @Test
+ public void deleteUnauthorized() throws Exception {
+
+ MetadataSchema metadataSchema = createMetadataSchema();
+
+ try {
+
+ assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
+
+ getClient()
+ .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isUnauthorized());
+
+ assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
+
+ } finally {
+ deleteMetadataSchemaIfExists(TEST_NAME);
+ }
+ }
+
+ @Test
+ public void deleteNonExisting() throws Exception {
+
+ MetadataSchema metadataSchema = createMetadataSchema();
+ deleteMetadataSchemaIfExists(TEST_NAME);
+
+ Integer id = metadataSchema.getID();
+ assertThat(metadataSchemaService.find(context, id), nullValue());
+
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadataschemas/" + id))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void update() throws Exception {
+
+ MetadataSchema metadataSchema = createMetadataSchema();
+
+ MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
+ metadataSchemaRest.setId(metadataSchema.getID());
+ metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
+ metadataSchemaRest.setNamespace(TEST_NAMESPACE_UPDATED);
+
+ try {
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isOk());
+
+ metadataSchema = metadataSchemaService.find(context, metadataSchema.getID());
+
+ assertEquals(TEST_NAME_UPDATED, metadataSchema.getName());
+ assertEquals(TEST_NAMESPACE_UPDATED, metadataSchema.getNamespace());
+ } finally {
+ deleteMetadataSchemaIfExists(metadataSchema);
+ }
+ }
+
+ @Test
+ public void updateUnauthorized() throws Exception {
+
+ MetadataSchema metadataSchema = createMetadataSchema();
+
+ MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
+ metadataSchemaRest.setId(metadataSchema.getID());
+ metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
+ metadataSchemaRest.setNamespace(TEST_NAMESPACE_UPDATED);
+
+ try {
+ getClient()
+ .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ metadataSchema = metadataSchemaService.find(context, metadataSchema.getID());
+
+ assertEquals(TEST_NAME, metadataSchema.getName());
+ assertEquals(TEST_NAMESPACE, metadataSchema.getNamespace());
+ } finally {
+ deleteMetadataSchemaIfExists(metadataSchema);
+ }
+ }
+
+ private MetadataSchema createMetadataSchema() throws SQLException, AuthorizeException, NonUniqueMetadataException {
+ context.turnOffAuthorisationSystem();
+ MetadataSchema metadataSchema = metadataSchemaService.create(context, TEST_NAME, TEST_NAMESPACE);
+ context.commit();
+ return metadataSchema;
+ }
+
+ private void deleteMetadataSchemaIfExists(String name) throws SQLException, AuthorizeException {
+
+ deleteMetadataSchemaIfExists(metadataSchemaService.find(context, name));
+ }
+
+ private void deleteMetadataSchemaIfExists(MetadataSchema metadataSchema) throws SQLException, AuthorizeException {
+
+ if (metadataSchema != null) {
+ context.turnOffAuthorisationSystem();
+ metadataSchemaService.delete(context, metadataSchema);
+ context.commit();
+ }
}
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
index 7217030ab3..b207dcd655 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
@@ -7,23 +7,62 @@
*/
package org.dspace.app.rest;
+import static com.jayway.jsonpath.JsonPath.read;
import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
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.content;
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 java.util.concurrent.atomic.AtomicReference;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.dspace.app.rest.builder.MetadataFieldBuilder;
import org.dspace.app.rest.builder.MetadataSchemaBuilder;
import org.dspace.app.rest.matcher.MetadataFieldMatcher;
+import org.dspace.app.rest.model.MetadataFieldRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
+import org.dspace.content.MetadataFieldServiceImpl;
import org.dspace.content.MetadataSchema;
+import org.dspace.content.NonUniqueMetadataException;
+import org.dspace.content.service.MetadataSchemaService;
import org.hamcrest.Matchers;
+import org.junit.Before;
import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegrationTest {
+ private static final String ELEMENT = "test element";
+ private static final String QUALIFIER = "test qualifier";
+ private static final String SCOPE_NOTE = "test scope_note";
+
+ private static final String ELEMENT_UPDATED = "test element updated";
+ private static final String QUALIFIER_UPDATED = "test qualifier updated";
+ private static final String SCOPE_NOTE_UPDATED = "test scope_note updated";
+
+ private MetadataSchema metadataSchema;
+
+ @Autowired
+ private MetadataSchemaService metadataSchemaService;
+
+ @Autowired
+ private MetadataFieldServiceImpl metadataFieldService;
+
+ @Before
+ public void setup() throws Exception {
+ metadataSchema = metadataSchemaService.findAll(context).get(0);
+ }
@Test
public void findAll() throws Exception {
@@ -66,12 +105,12 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void searchMethodsExist() throws Exception {
getClient().perform(get("/api/core/metadatafields"))
- .andExpect(jsonPath("$._links.search.href", Matchers.notNullValue()));
+ .andExpect(jsonPath("$._links.search.href", notNullValue()));
getClient().perform(get("/api/core/metadatafields/search"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
- .andExpect(jsonPath("$._links.bySchema", Matchers.notNullValue()));
+ .andExpect(jsonPath("$._links.bySchema", notNullValue()));
}
@Test
@@ -124,4 +163,190 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
.andExpect(status().isUnprocessableEntity());
}
+ @Test
+ public void createSuccess() throws Exception {
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setElement(ELEMENT);
+ metadataFieldRest.setQualifier(QUALIFIER);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE);
+
+ String authToken = getAuthToken(admin.getEmail(), password);
+ AtomicReference idRef = new AtomicReference<>();
+
+ try {
+ assertThat(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER), nullValue());
+
+ getClient(authToken)
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
+
+ MetadataField metadataField = metadataFieldService.find(context, idRef.get());
+ assertThat(metadataField, notNullValue());
+
+ assertEquals(metadataField.getMetadataSchema(), metadataSchema);
+ assertEquals(metadataField.getElement(), ELEMENT);
+ assertEquals(metadataField.getQualifier(), QUALIFIER);
+ assertEquals(metadataField.getScopeNote(), SCOPE_NOTE);
+
+ } finally {
+ deleteMetadataFieldIfExists();
+ }
+ }
+
+ @Test
+ public void createUnauthauthorized() throws Exception {
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setElement(ELEMENT);
+ metadataFieldRest.setQualifier(QUALIFIER);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE);
+
+ try {
+ getClient()
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+ } finally {
+ deleteMetadataFieldIfExists();
+ }
+ }
+
+ @Test
+ public void deleteSuccess() throws Exception {
+
+ MetadataField metadataField = createMetadataField();
+
+ try {
+
+ assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
+
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isNoContent());
+
+ assertThat(metadataFieldService.find(context, metadataField.getID()), nullValue());
+
+ } finally {
+ deleteMetadataFieldIfExists();
+ }
+ }
+
+ @Test
+ public void deleteUnauthorized() throws Exception {
+
+ MetadataField metadataField = createMetadataField();
+
+ try {
+
+ assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
+
+ getClient()
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isUnauthorized());
+
+ assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
+
+ } finally {
+ deleteMetadataFieldIfExists();
+ }
+ }
+
+ @Test
+ public void deleteNonExisting() throws Exception {
+
+ MetadataField metadataField = createMetadataField();
+ deleteMetadataFieldIfExists();
+
+ Integer id = metadataField.getID();
+ assertThat(metadataFieldService.find(context, id), nullValue());
+
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadatafields/" + id))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void update() throws Exception {
+
+ MetadataField metadataField = createMetadataField();
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setId(metadataField.getID());
+ metadataFieldRest.setElement(ELEMENT_UPDATED);
+ metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
+
+ try {
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isOk());
+
+ metadataField = metadataFieldService.find(context, metadataField.getID());
+
+ assertEquals(ELEMENT_UPDATED, metadataField.getElement());
+ assertEquals(QUALIFIER_UPDATED, metadataField.getQualifier());
+ assertEquals(SCOPE_NOTE_UPDATED, metadataField.getScopeNote());
+ } finally {
+ deleteMetadataFieldIfExists(metadataField);
+ }
+ }
+
+ @Test
+ public void updateUnauthorized() throws Exception {
+
+ MetadataField metadataField = createMetadataField();
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setId(metadataField.getID());
+ metadataFieldRest.setElement(ELEMENT_UPDATED);
+ metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
+
+ try {
+ getClient()
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ metadataField = metadataFieldService.find(context, metadataField.getID());
+
+ assertEquals(ELEMENT, metadataField.getElement());
+ assertEquals(QUALIFIER, metadataField.getQualifier());
+ assertEquals(SCOPE_NOTE, metadataField.getScopeNote());
+ } finally {
+ deleteMetadataFieldIfExists(metadataField);
+ }
+ }
+
+ private MetadataField createMetadataField() throws AuthorizeException, SQLException, NonUniqueMetadataException {
+ context.turnOffAuthorisationSystem();
+ MetadataField metadataField = metadataFieldService.create(
+ context, metadataSchema, ELEMENT, QUALIFIER, SCOPE_NOTE
+ );
+ context.commit();
+ return metadataField;
+ }
+
+ private void deleteMetadataFieldIfExists() throws SQLException, AuthorizeException {
+
+ deleteMetadataFieldIfExists(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER));
+ }
+
+ private void deleteMetadataFieldIfExists(MetadataField metadataField) throws SQLException, AuthorizeException {
+ if (metadataField != null) {
+ context.turnOffAuthorisationSystem();
+ metadataFieldService.delete(context, metadataField);
+ context.commit();
+ }
+ }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java
index 18e8a5ad8d..42b70810a5 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataschemaMatcher.java
@@ -29,11 +29,15 @@ public class MetadataschemaMatcher {
}
public static Matcher super Object> matchEntry(MetadataSchema metadataSchema) {
+ return matchEntry(metadataSchema.getName(), metadataSchema.getNamespace());
+ }
+
+ public static Matcher super Object> matchEntry(String name, String nameSpace) {
return allOf(
- hasJsonPath("$.prefix", is(metadataSchema.getName())),
- hasJsonPath("$.namespace", is(metadataSchema.getNamespace())),
- hasJsonPath("$.type", is("metadataschema")),
- hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadataschemas"))
+ hasJsonPath("$.prefix", is(name)),
+ hasJsonPath("$.namespace", is(nameSpace)),
+ hasJsonPath("$.type", is("metadataschema")),
+ hasJsonPath("$._links.self.href", Matchers.containsString("/api/core/metadataschemas"))
);
}
}
From 0a7a8aab8ec774a2efdf74baaf6086f90be1bcae Mon Sep 17 00:00:00 2001
From: Samuel
Date: Thu, 13 Dec 2018 17:18:26 +0100
Subject: [PATCH 41/68] Added support for the CRUD operations on the
MetadataField and MetadataSchema REST endpoints - feedback
---
.../app/rest/RestResourceController.java | 24 +++++++++++++--
.../rest/repository/DSpaceRestRepository.java | 29 ++++++++++---------
.../MetadataFieldRestRepository.java | 6 +---
.../MetadataSchemaRestRepository.java | 6 +---
4 files changed, 39 insertions(+), 26 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 1e4631cec3..e0c80ee66f 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
@@ -987,11 +987,31 @@ 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}
+ *
+ * Example:
+ *
+ * {@code
+ * curl -X PUT http:///dspace-spring-rest/api/metadatafield
+ * }
+ *
+ *
+ * @param request the http request
+ * @param apiCategory the API category e.g. "api"
+ * @param model the DSpace model e.g. "metadatafield"
+ * @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,
@PathVariable Integer id,
- @RequestBody(required = true) JsonNode jsonNode) {
+ @RequestBody JsonNode jsonNode) {
return putOneInternal(request, apiCategory, model, id, jsonNode);
}
@@ -1018,7 +1038,7 @@ public class RestResourceController implements InitializingBean {
public DSpaceResource put(HttpServletRequest request,
@PathVariable String apiCategory, @PathVariable String model,
@PathVariable UUID uuid,
- @RequestBody(required = true) JsonNode jsonNode) {
+ @RequestBody JsonNode jsonNode) {
return putOneInternal(request, apiCategory, model, uuid, jsonNode);
}
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 0be6f7475a..29e0085bb3 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
@@ -71,7 +71,7 @@ public abstract class DSpaceRestRepository
Date: Thu, 10 Jan 2019 11:42:31 +0100
Subject: [PATCH 42/68] Added support for the CRUD operations on the
MetadataField and MetadataSchema REST endpoints - feedback
---
.../dspace/app/rest/exception/PatchBadRequestException.java | 5 ++++-
.../app/rest/repository/MetadataFieldRestRepository.java | 4 ++--
.../app/rest/repository/MetadataSchemaRestRepository.java | 6 ++++--
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/PatchBadRequestException.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/PatchBadRequestException.java
index 5c3328a1dd..2000684fb2 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/PatchBadRequestException.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/exception/PatchBadRequestException.java
@@ -22,7 +22,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
public class PatchBadRequestException extends RuntimeException {
public PatchBadRequestException(String message) {
- super(message);
+ this(message, null);
}
+ public PatchBadRequestException(String message, Exception e) {
+ super(message, e);
+ }
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
index 502e626520..46f1644540 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
@@ -127,7 +127,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository
Date: Wed, 23 Jan 2019 15:34:55 -0600
Subject: [PATCH 43/68] Minor improvements to English in error messages.
---
.../app/rest/repository/MetadataFieldRestRepository.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
index 46f1644540..c548c8604b 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
@@ -133,16 +133,16 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository
Date: Wed, 23 Jan 2019 15:37:46 -0600
Subject: [PATCH 44/68] More minor corrections to English
---
.../app/rest/repository/MetadataFieldRestRepository.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
index c548c8604b..3b67acaf7c 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataFieldRestRepository.java
@@ -191,16 +191,16 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository
Date: Wed, 23 Jan 2019 15:39:38 -0600
Subject: [PATCH 45/68] English grammar corrections
---
.../repository/MetadataSchemaRestRepository.java | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataSchemaRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataSchemaRestRepository.java
index 915a785e26..36d290e247 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataSchemaRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/MetadataSchemaRestRepository.java
@@ -106,10 +106,10 @@ public class MetadataSchemaRestRepository extends DSpaceRestRepository
Date: Thu, 7 Feb 2019 15:11:14 +0100
Subject: [PATCH 46/68] Applied feedback and fixed test cases
---
.../app/rest/RestResourceController.java | 12 +-
.../app/rest/model/MetadataFieldRest.java | 4 +-
.../app/rest/model/MetadataSchemaRest.java | 4 +-
.../rest/repository/DSpaceRestRepository.java | 7 +-
.../rest/MetadataSchemaRestRepositoryIT.java | 191 ++++++--------
.../rest/MetadatafieldRestRepositoryIT.java | 237 +++++++++---------
6 files changed, 213 insertions(+), 242 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 e0c80ee66f..536379c696 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
@@ -991,17 +991,17 @@ 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}
+ * curl -X PUT http:///api/{apiCategory}/{model}/{id}
*
* Example:
*
* {@code
- * curl -X PUT http:///dspace-spring-rest/api/metadatafield
+ * curl -X PUT http:///api/core/metadatafield/1
* }
*
*
* @param request the http request
- * @param apiCategory the API category e.g. "api"
+ * @param apiCategory the API category e.g. "core"
* @param model the DSpace model e.g. "metadatafield"
* @param id the ID of the target REST object
* @param jsonNode the part of the request body representing the updated rest object
@@ -1018,17 +1018,17 @@ public class RestResourceController implements InitializingBean {
/**
* Execute a PUT request for an entity with id of type UUID;
*
- * curl -X PUT http:///dspace-spring-rest/api/{apiCategory}/{model}/{uuid}
+ * curl -X PUT http:///api/{apiCategory}/{model}/{uuid}
*
* Example:
*
* {@code
- * curl -X PUT http:///dspace-spring-rest/api/collection/320c0492-de1d-4646-9e69-193d36b366e9
+ * curl -X PUT http:///api/core/collection/8b632938-77c2-487c-81f0-e804f63e68e6
* }
*
*
* @param request the http request
- * @param apiCategory the API category e.g. "api"
+ * @param apiCategory the API category e.g. "core"
* @param model the DSpace model e.g. "collection"
* @param uuid the ID of the target REST object
* @param jsonNode the part of the request body representing the updated rest object
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
index 3fc017db01..7e6eabc4d0 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataFieldRest.java
@@ -8,7 +8,7 @@
package org.dspace.app.rest.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.rest.RestResourceController;
/**
@@ -16,7 +16,6 @@ import org.dspace.app.rest.RestResourceController;
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
-@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataFieldRest extends BaseObjectRest {
public static final String NAME = "metadatafield";
public static final String CATEGORY = RestAddressableModel.CORE;
@@ -63,6 +62,7 @@ public class MetadataFieldRest extends BaseObjectRest {
}
@Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
index 649e2e6e2d..27229ea429 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataSchemaRest.java
@@ -7,7 +7,7 @@
*/
package org.dspace.app.rest.model;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.rest.RestResourceController;
/**
@@ -15,7 +15,6 @@ import org.dspace.app.rest.RestResourceController;
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
-@JsonIgnoreProperties(ignoreUnknown = true)
public class MetadataSchemaRest extends BaseObjectRest {
public static final String NAME = "metadataschema";
public static final String CATEGORY = RestAddressableModel.CORE;
@@ -41,6 +40,7 @@ public class MetadataSchemaRest extends BaseObjectRest {
}
@Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
public String getType() {
return NAME;
}
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 29e0085bb3..5cf16f6031 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,8 @@ public abstract class DSpaceRestRepository idRef = new AtomicReference<>();
- try {
- assertThat(metadataSchemaService.find(context, TEST_NAME), nullValue());
+ getClient(authToken)
+ .perform(post("/api/core/metadataschemas")
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
- getClient(authToken)
- .perform(post("/api/core/metadataschemas")
- .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
- .contentType(contentType))
- .andExpect(status().isCreated())
- .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
-
- MetadataSchema metadataSchema = metadataSchemaService.find(context, idRef.get());
- assertThat(metadataSchema, notNullValue());
-
- assertEquals(metadataSchema.getID(), idRef.get());
- assertEquals(metadataSchema.getName(), TEST_NAME);
- assertEquals(metadataSchema.getNamespace(), TEST_NAMESPACE);
-
- } finally {
- deleteMetadataSchemaIfExists(TEST_NAME);
- }
+ getClient().perform(get("/api/core/metadataschemas/" + idRef.get()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataschemaMatcher.matchEntry(TEST_NAME, TEST_NAMESPACE)));
}
@Test
public void createUnauthauthorizedTest()
throws Exception {
+ context.turnOffAuthorisationSystem();
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setPrefix(TEST_NAME);
metadataSchemaRest.setNamespace(TEST_NAMESPACE);
- try {
- getClient()
- .perform(post("/api/core/metadataschemas")
- .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
-
- } finally {
- deleteMetadataSchemaIfExists(TEST_NAME);
- }
+ getClient()
+ .perform(post("/api/core/metadataschemas")
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
}
@Test
public void deleteSuccess() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = createMetadataSchema();
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "A namespace")
+ .build();
- try {
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isOk());
- assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
- getClient(getAuthToken(admin.getEmail(), password))
- .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
- .andExpect(status().isNoContent());
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isNoContent());
- assertThat(metadataSchemaService.find(context, metadataSchema.getID()), nullValue());
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isNotFound());
- } finally {
- deleteMetadataSchemaIfExists(TEST_NAME);
- }
}
@Test
public void deleteUnauthorized() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = createMetadataSchema();
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
+ .build();
- try {
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID())).andExpect(status().isOk());
- assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
+ getClient()
+ .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isUnauthorized());
- getClient()
- .perform(delete("/api/core/metadataschemas/" + metadataSchema.getID()))
- .andExpect(status().isUnauthorized());
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID())).andExpect(status().isOk());
- assertThat(metadataSchemaService.find(context, metadataSchema.getID()), notNullValue());
-
- } finally {
- deleteMetadataSchemaIfExists(TEST_NAME);
- }
}
@Test
public void deleteNonExisting() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = createMetadataSchema();
- deleteMetadataSchemaIfExists(TEST_NAME);
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "A name", "A namespace")
+ .build();
Integer id = metadataSchema.getID();
- assertThat(metadataSchemaService.find(context, id), nullValue());
+
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadataschemas/" + id))
+ .andExpect(status().isNoContent());
getClient(getAuthToken(admin.getEmail(), password))
.perform(delete("/api/core/metadataschemas/" + id))
@@ -188,74 +175,50 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
@Test
public void update() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = createMetadataSchema();
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
+ .build();
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setId(metadataSchema.getID());
metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
metadataSchemaRest.setNamespace(TEST_NAMESPACE_UPDATED);
- try {
- getClient(getAuthToken(admin.getEmail(), password))
- .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
- .contentType(contentType))
- .andExpect(status().isOk());
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isOk());
- metadataSchema = metadataSchemaService.find(context, metadataSchema.getID());
-
- assertEquals(TEST_NAME_UPDATED, metadataSchema.getName());
- assertEquals(TEST_NAMESPACE_UPDATED, metadataSchema.getNamespace());
- } finally {
- deleteMetadataSchemaIfExists(metadataSchema);
- }
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataschemaMatcher
+ .matchEntry(TEST_NAME_UPDATED, TEST_NAMESPACE_UPDATED)));
}
@Test
public void updateUnauthorized() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = createMetadataSchema();
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
+ .build();
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setId(metadataSchema.getID());
metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
metadataSchemaRest.setNamespace(TEST_NAMESPACE_UPDATED);
- try {
- getClient()
- .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
+ getClient()
+ .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataschemaMatcher
+ .matchEntry(TEST_NAME, TEST_NAMESPACE)));
+}
- metadataSchema = metadataSchemaService.find(context, metadataSchema.getID());
-
- assertEquals(TEST_NAME, metadataSchema.getName());
- assertEquals(TEST_NAMESPACE, metadataSchema.getNamespace());
- } finally {
- deleteMetadataSchemaIfExists(metadataSchema);
- }
- }
-
- private MetadataSchema createMetadataSchema() throws SQLException, AuthorizeException, NonUniqueMetadataException {
- context.turnOffAuthorisationSystem();
- MetadataSchema metadataSchema = metadataSchemaService.create(context, TEST_NAME, TEST_NAMESPACE);
- context.commit();
- return metadataSchema;
- }
-
- private void deleteMetadataSchemaIfExists(String name) throws SQLException, AuthorizeException {
-
- deleteMetadataSchemaIfExists(metadataSchemaService.find(context, name));
- }
-
- private void deleteMetadataSchemaIfExists(MetadataSchema metadataSchema) throws SQLException, AuthorizeException {
-
- if (metadataSchema != null) {
- context.turnOffAuthorisationSystem();
- metadataSchemaService.delete(context, metadataSchema);
- context.commit();
- }
- }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
index b207dcd655..a90305abbb 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
@@ -11,7 +11,6 @@ import static com.jayway.jsonpath.JsonPath.read;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -21,7 +20,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
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 java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -30,11 +28,9 @@ import org.dspace.app.rest.builder.MetadataSchemaBuilder;
import org.dspace.app.rest.matcher.MetadataFieldMatcher;
import org.dspace.app.rest.model.MetadataFieldRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
-import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataFieldServiceImpl;
import org.dspace.content.MetadataSchema;
-import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.service.MetadataSchemaService;
import org.hamcrest.Matchers;
import org.junit.Before;
@@ -104,6 +100,8 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void searchMethodsExist() throws Exception {
+ context.turnOffAuthorisationSystem();
+
getClient().perform(get("/api/core/metadatafields"))
.andExpect(jsonPath("$._links.search.href", notNullValue()));
@@ -147,6 +145,7 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void findByUndefinedSchema() throws Exception {
+ context.turnOffAuthorisationSystem();
getClient().perform(get("/api/core/metadatafields/search/bySchema")
.param("schema", "undefined"))
@@ -158,6 +157,7 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void findByNullSchema() throws Exception {
+ context.turnOffAuthorisationSystem();
getClient().perform(get("/api/core/metadatafields/search/bySchema"))
.andExpect(status().isUnprocessableEntity());
@@ -165,106 +165,135 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void createSuccess() throws Exception {
+ context.turnOffAuthorisationSystem();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
- metadataFieldRest.setElement(ELEMENT);
- metadataFieldRest.setQualifier(QUALIFIER);
+ metadataFieldRest.setElement("testElementForCreate");
+ metadataFieldRest.setQualifier("testQualifierForCreate");
metadataFieldRest.setScopeNote(SCOPE_NOTE);
String authToken = getAuthToken(admin.getEmail(), password);
AtomicReference idRef = new AtomicReference<>();
- try {
- assertThat(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER), nullValue());
+ assertThat(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER), nullValue());
- getClient(authToken)
- .perform(post("/api/core/metadatafields")
- .param("schemaId", metadataSchema.getID() + "")
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isCreated())
- .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
+ getClient(authToken)
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
- MetadataField metadataField = metadataFieldService.find(context, idRef.get());
- assertThat(metadataField, notNullValue());
-
- assertEquals(metadataField.getMetadataSchema(), metadataSchema);
- assertEquals(metadataField.getElement(), ELEMENT);
- assertEquals(metadataField.getQualifier(), QUALIFIER);
- assertEquals(metadataField.getScopeNote(), SCOPE_NOTE);
-
- } finally {
- deleteMetadataFieldIfExists();
- }
+ getClient(authToken).perform(get("/api/core/metadatafields/" + idRef.get()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
+ metadataSchema.getName(), "testElementForCreate", "testQualifierForCreate")));
}
@Test
- public void createUnauthauthorized() throws Exception {
+ public void createUnauthorized() throws Exception {
+ context.turnOffAuthorisationSystem();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setElement(ELEMENT);
metadataFieldRest.setQualifier(QUALIFIER);
metadataFieldRest.setScopeNote(SCOPE_NOTE);
- try {
- getClient()
- .perform(post("/api/core/metadatafields")
- .param("schemaId", metadataSchema.getID() + "")
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
- } finally {
- deleteMetadataFieldIfExists();
- }
+ getClient()
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+ }
+
+ @Test
+ public void createUnauthorizedEPersonNoAdminRights() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setElement(ELEMENT);
+ metadataFieldRest.setQualifier(QUALIFIER);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE);
+
+ String token = getAuthToken(eperson.getEmail(), password);
+
+ getClient(token)
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isForbidden());
}
@Test
public void deleteSuccess() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataField metadataField = createMetadataField();
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
- try {
- assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk());
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isNoContent());
- getClient(getAuthToken(admin.getEmail(), password))
- .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
- .andExpect(status().isNoContent());
-
- assertThat(metadataFieldService.find(context, metadataField.getID()), nullValue());
-
- } finally {
- deleteMetadataFieldIfExists();
- }
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isNotFound());
}
@Test
public void deleteUnauthorized() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataField metadataField = createMetadataField();
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
- try {
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk());
+ getClient()
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isUnauthorized());
- assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
-
- getClient()
- .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
- .andExpect(status().isUnauthorized());
-
- assertThat(metadataFieldService.find(context, metadataField.getID()), notNullValue());
-
- } finally {
- deleteMetadataFieldIfExists();
- }
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk());
}
@Test
- public void deleteNonExisting() throws Exception {
+ public void deleteUnauthorizedEPersonNoAdminRights() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataField metadataField = createMetadataField();
- deleteMetadataFieldIfExists();
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
+ String token = getAuthToken(eperson.getEmail(), password);
+
+
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk());
+ getClient(token)
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isForbidden());
+
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk());
+ }
+
+
+ @Test
+ public void deleteNonExisting() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
Integer id = metadataField.getID();
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(delete("/api/core/metadatafields/" + id))
+ .andExpect(status().isNoContent());
+
assertThat(metadataFieldService.find(context, id), nullValue());
getClient(getAuthToken(admin.getEmail(), password))
@@ -274,79 +303,55 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void update() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataField metadataField = createMetadataField();
-
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setId(metadataField.getID());
metadataFieldRest.setElement(ELEMENT_UPDATED);
metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
- try {
- getClient(getAuthToken(admin.getEmail(), password))
- .perform(put("/api/core/metadatafields/" + metadataField.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isOk());
+ getClient(getAuthToken(admin.getEmail(), password))
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isOk());
- metadataField = metadataFieldService.find(context, metadataField.getID());
-
- assertEquals(ELEMENT_UPDATED, metadataField.getElement());
- assertEquals(QUALIFIER_UPDATED, metadataField.getQualifier());
- assertEquals(SCOPE_NOTE_UPDATED, metadataField.getScopeNote());
- } finally {
- deleteMetadataFieldIfExists(metadataField);
- }
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
+ metadataSchema.getName(), ELEMENT_UPDATED, QUALIFIER_UPDATED)
+ ));
}
@Test
public void updateUnauthorized() throws Exception {
+ context.turnOffAuthorisationSystem();
- MetadataField metadataField = createMetadataField();
-
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setId(metadataField.getID());
metadataFieldRest.setElement(ELEMENT_UPDATED);
metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
- try {
- getClient()
- .perform(put("/api/core/metadatafields/" + metadataField.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
+ getClient()
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
+ metadataSchema.getName(), ELEMENT, QUALIFIER)
+ ));
- metadataField = metadataFieldService.find(context, metadataField.getID());
- assertEquals(ELEMENT, metadataField.getElement());
- assertEquals(QUALIFIER, metadataField.getQualifier());
- assertEquals(SCOPE_NOTE, metadataField.getScopeNote());
- } finally {
- deleteMetadataFieldIfExists(metadataField);
- }
}
- private MetadataField createMetadataField() throws AuthorizeException, SQLException, NonUniqueMetadataException {
- context.turnOffAuthorisationSystem();
- MetadataField metadataField = metadataFieldService.create(
- context, metadataSchema, ELEMENT, QUALIFIER, SCOPE_NOTE
- );
- context.commit();
- return metadataField;
- }
- private void deleteMetadataFieldIfExists() throws SQLException, AuthorizeException {
-
- deleteMetadataFieldIfExists(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER));
- }
-
- private void deleteMetadataFieldIfExists(MetadataField metadataField) throws SQLException, AuthorizeException {
- if (metadataField != null) {
- context.turnOffAuthorisationSystem();
- metadataFieldService.delete(context, metadataField);
- context.commit();
- }
- }
}
From 7cde38d2298721ab3b9a78a3788b7612d0b77bff Mon Sep 17 00:00:00 2001
From: Kim Shepherd
Date: Wed, 13 Feb 2019 13:03:37 +1300
Subject: [PATCH 47/68] [DS-4136] Tidy up comments, only display per-1k msg if
batch size !1000
---
dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
index 8c2ac8a1f9..1a6083ca24 100644
--- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
+++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
@@ -56,7 +56,7 @@ import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
-import org.dspace.services.ConfigurationService; //added
+import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.xoai.exceptions.CompilingException;
import org.dspace.xoai.services.api.CollectionsService;
@@ -304,7 +304,7 @@ public class XOAI {
log.error(ex.getMessage(), ex);
}
i++;
- if (i % 1000 == 0) {
+ if (i % 1000 == 0 && batchSize != 1000) {
System.out.println(i + " items imported so far...");
}
if (i % batchSize == 0) {
From d450b59899119cd70e32c3c2f788c22c19d0d02a Mon Sep 17 00:00:00 2001
From: Raf Ponsaerts
Date: Wed, 13 Feb 2019 13:08:30 +0100
Subject: [PATCH 48/68] Applied feedback and added tests
---
.../rest/MetadataSchemaRestRepositoryIT.java | 52 ++++++-
.../rest/MetadatafieldRestRepositoryIT.java | 142 ++++++++++++------
2 files changed, 140 insertions(+), 54 deletions(-)
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java
index 922ff65867..8ffcd4df67 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadataSchemaRestRepositoryIT.java
@@ -31,6 +31,11 @@ import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
+/**
+ * Integration tests for the {@link org.dspace.app.rest.repository.MetadataSchemaRestRepository}
+ * This class will include all the tests for the logic with regards to the
+ * {@link org.dspace.app.rest.repository.MetadataSchemaRestRepository}
+ */
public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegrationTest {
private static final String TEST_NAME = "testSchemaName";
@@ -48,6 +53,7 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
context.turnOffAuthorisationSystem();
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "ANamespace")
.build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadataschemas"))
.andExpect(status().isOk())
@@ -65,6 +71,7 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
context.turnOffAuthorisationSystem();
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "ANamespace")
.build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
.andExpect(status().isOk())
@@ -79,8 +86,7 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "ANamespace")
.build();
-
-
+ context.restoreAuthSystemState();
MetadataSchemaRest metadataSchemaRest = metadataSchemaConverter.fromModel(metadataSchema);
metadataSchemaRest.setPrefix(TEST_NAME);
@@ -103,10 +109,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
}
@Test
- public void createUnauthauthorizedTest()
+ public void createUnauthorizedTest()
throws Exception {
- context.turnOffAuthorisationSystem();
-
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setPrefix(TEST_NAME);
metadataSchemaRest.setNamespace(TEST_NAMESPACE);
@@ -125,6 +129,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "ATest", "A namespace")
.build();
+ context.restoreAuthSystemState();
+
getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
.andExpect(status().isOk());
@@ -145,6 +151,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
.build();
+ context.restoreAuthSystemState();
+
getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID())).andExpect(status().isOk());
getClient()
@@ -162,6 +170,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, "A name", "A namespace")
.build();
+ context.restoreAuthSystemState();
+
Integer id = metadataSchema.getID();
getClient(getAuthToken(admin.getEmail(), password))
@@ -180,6 +190,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
.build();
+ context.restoreAuthSystemState();
+
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setId(metadataSchema.getID());
metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
@@ -204,6 +216,8 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
.build();
+ context.restoreAuthSystemState();
+
MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
metadataSchemaRest.setId(metadataSchema.getID());
metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
@@ -219,6 +233,32 @@ public class MetadataSchemaRestRepositoryIT extends AbstractControllerIntegratio
.andExpect(status().isOk())
.andExpect(jsonPath("$", MetadataschemaMatcher
.matchEntry(TEST_NAME, TEST_NAMESPACE)));
-}
+ }
+
+ @Test
+ public void updateWrongRights() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ MetadataSchema metadataSchema = MetadataSchemaBuilder.createMetadataSchema(context, TEST_NAME, TEST_NAMESPACE)
+ .build();
+
+ context.restoreAuthSystemState();
+
+ MetadataSchemaRest metadataSchemaRest = new MetadataSchemaRest();
+ metadataSchemaRest.setId(metadataSchema.getID());
+ metadataSchemaRest.setPrefix(TEST_NAME_UPDATED);
+ metadataSchemaRest.setNamespace(TEST_NAMESPACE_UPDATED);
+
+ getClient(getAuthToken(eperson.getEmail(), password))
+ .perform(put("/api/core/metadataschemas/" + metadataSchema.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataSchemaRest))
+ .contentType(contentType))
+ .andExpect(status().isForbidden());
+
+ getClient().perform(get("/api/core/metadataschemas/" + metadataSchema.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataschemaMatcher
+ .matchEntry(TEST_NAME, TEST_NAMESPACE)));
+ }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
index a90305abbb..49a5995be7 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/MetadatafieldRestRepositoryIT.java
@@ -37,6 +37,11 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
+/**
+ * Integration tests for the {@link org.dspace.app.rest.repository.MetadataFieldRestRepository}
+ * This class will include all the tests for the logic with regards to the
+ * {@link org.dspace.app.rest.repository.MetadataFieldRestRepository}
+ */
public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegrationTest {
private static final String ELEMENT = "test element";
@@ -66,14 +71,15 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
context.turnOffAuthorisationSystem();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, "AnElement", "AQualifier", "AScopeNote").build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields")
- .param("size", String.valueOf(100)))
+ .param("size", String.valueOf(100)))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
- MetadataFieldMatcher.matchMetadataFieldByKeys("dc","title", null),
- MetadataFieldMatcher.matchMetadataFieldByKeys("dc","date", "issued"))
+ MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "title", null),
+ MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "date", "issued"))
))
.andExpect(jsonPath("$._links.first.href", Matchers.containsString("/api/core/metadatafields")))
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields")))
@@ -89,6 +95,7 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
context.turnOffAuthorisationSystem();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, "AnElement", "AQualifier", "AScopeNote").build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
@@ -100,7 +107,6 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void searchMethodsExist() throws Exception {
- context.turnOffAuthorisationSystem();
getClient().perform(get("/api/core/metadatafields"))
.andExpect(jsonPath("$._links.search.href", notNullValue()));
@@ -116,39 +122,39 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
- "http://www.dspace.org/ns/aschema").build();
+ "http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement", "AQualifier", "AScopeNote").build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields/search/bySchema")
- .param("schema", "dc")
- .param("size", String.valueOf(100)))
+ .param("schema", "dc")
+ .param("size", String.valueOf(100)))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
- MetadataFieldMatcher.matchMetadataFieldByKeys("dc","title", null),
- MetadataFieldMatcher.matchMetadataFieldByKeys("dc","date", "issued"))
+ MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "title", null),
+ MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "date", "issued"))
))
.andExpect(jsonPath("$.page.size", is(100)));
getClient().perform(get("/api/core/metadatafields/search/bySchema")
- .param("schema", schema.getName()))
- .andExpect(status().isOk())
- .andExpect(content().contentType(contentType))
- .andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
- MetadataFieldMatcher.matchMetadataField(metadataField))
- ))
- .andExpect(jsonPath("$.page.size", is(20)))
- .andExpect(jsonPath("$.page.totalElements", is(1)));
+ .param("schema", schema.getName()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(contentType))
+ .andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
+ MetadataFieldMatcher.matchMetadataField(metadataField))
+ ))
+ .andExpect(jsonPath("$.page.size", is(20)))
+ .andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByUndefinedSchema() throws Exception {
- context.turnOffAuthorisationSystem();
getClient().perform(get("/api/core/metadatafields/search/bySchema")
- .param("schema", "undefined"))
+ .param("schema", "undefined"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.page.size", is(20)))
@@ -157,7 +163,6 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void findByNullSchema() throws Exception {
- context.turnOffAuthorisationSystem();
getClient().perform(get("/api/core/metadatafields/search/bySchema"))
.andExpect(status().isUnprocessableEntity());
@@ -165,7 +170,6 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void createSuccess() throws Exception {
- context.turnOffAuthorisationSystem();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setElement("testElementForCreate");
@@ -178,12 +182,12 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
assertThat(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER), nullValue());
getClient(authToken)
- .perform(post("/api/core/metadatafields")
- .param("schemaId", metadataSchema.getID() + "")
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isCreated())
- .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isCreated())
+ .andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
getClient(authToken).perform(get("/api/core/metadatafields/" + idRef.get()))
.andExpect(status().isOk())
@@ -193,7 +197,6 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
@Test
public void createUnauthorized() throws Exception {
- context.turnOffAuthorisationSystem();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setElement(ELEMENT);
@@ -201,16 +204,15 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
metadataFieldRest.setScopeNote(SCOPE_NOTE);
getClient()
- .perform(post("/api/core/metadatafields")
- .param("schemaId", metadataSchema.getID() + "")
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
+ .perform(post("/api/core/metadatafields")
+ .param("schemaId", metadataSchema.getID() + "")
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
}
@Test
public void createUnauthorizedEPersonNoAdminRights() throws Exception {
- context.turnOffAuthorisationSystem();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setElement(ELEMENT);
@@ -233,13 +235,14 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+ context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk());
getClient(getAuthToken(admin.getEmail(), password))
- .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
- .andExpect(status().isNoContent());
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isNoContent());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isNotFound());
@@ -252,11 +255,13 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+ context.restoreAuthSystemState();
+
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk());
getClient()
- .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
- .andExpect(status().isUnauthorized());
+ .perform(delete("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isUnauthorized());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk());
@@ -268,6 +273,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+
+ context.restoreAuthSystemState();
+
String token = getAuthToken(eperson.getEmail(), password);
@@ -289,6 +297,8 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+ context.restoreAuthSystemState();
+
Integer id = metadataField.getID();
getClient(getAuthToken(admin.getEmail(), password))
.perform(delete("/api/core/metadatafields/" + id))
@@ -297,8 +307,8 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
assertThat(metadataFieldService.find(context, id), nullValue());
getClient(getAuthToken(admin.getEmail(), password))
- .perform(delete("/api/core/metadatafields/" + id))
- .andExpect(status().isNotFound());
+ .perform(delete("/api/core/metadatafields/" + id))
+ .andExpect(status().isNotFound());
}
@Test
@@ -307,6 +317,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+
+ context.restoreAuthSystemState();
+
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setId(metadataField.getID());
metadataFieldRest.setElement(ELEMENT_UPDATED);
@@ -314,10 +327,10 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
getClient(getAuthToken(admin.getEmail(), password))
- .perform(put("/api/core/metadatafields/" + metadataField.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isOk());
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isOk());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
@@ -332,6 +345,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
+
+ context.restoreAuthSystemState();
+
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setId(metadataField.getID());
metadataFieldRest.setElement(ELEMENT_UPDATED);
@@ -339,10 +355,40 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
getClient()
- .perform(put("/api/core/metadatafields/" + metadataField.getID())
- .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
- .contentType(contentType))
- .andExpect(status().isUnauthorized());
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isUnauthorized());
+
+ getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
+ metadataSchema.getName(), ELEMENT, QUALIFIER)
+ ));
+
+
+ }
+
+ @Test
+ public void updateWrongRights() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
+ .build();
+
+ context.restoreAuthSystemState();
+
+ MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
+ metadataFieldRest.setId(metadataField.getID());
+ metadataFieldRest.setElement(ELEMENT_UPDATED);
+ metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
+ metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
+
+ getClient(getAuthToken(eperson.getEmail(), password))
+ .perform(put("/api/core/metadatafields/" + metadataField.getID())
+ .content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
+ .contentType(contentType))
+ .andExpect(status().isForbidden());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
From 0b1216821847a4f78369e1b13622a2ad716a30d0 Mon Sep 17 00:00:00 2001
From: ssolim <30314886+ssolim@users.noreply.github.com>
Date: Wed, 6 Feb 2019 09:42:23 +0100
Subject: [PATCH 49/68] XOAI.java skip empty list and dont add it to solr
---
dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
index 1a6083ca24..32fb2dbca5 100644
--- a/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
+++ b/dspace-oai/src/main/java/org/dspace/xoai/app/XOAI.java
@@ -315,9 +315,11 @@ public class XOAI {
}
}
System.out.println("Total: " + i + " items");
- server.add(list);
- server.commit(true, true);
- list.clear();
+ if (i > 0) {
+ server.add(list);
+ server.commit(true, true);
+ list.clear();
+ }
return i;
} catch (SolrServerException | IOException ex) {
throw new DSpaceSolrIndexerException(ex.getMessage(), ex);
From b6f73682a398e58d0ffd1983262d26ff29a5a2eb Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Fri, 15 Feb 2019 15:33:39 -0800
Subject: [PATCH 50/68] Migrate postgres update-sequences.sql
---
.../dspace/storage/rdbms/DatabaseUtils.java | 56 +++++++++++++++----
.../rdbms/sqlmigration/postgres/README.md | 12 ++++
.../postgres/update-sequences.sql | 0
dspace/etc/postgres/README.md | 12 ----
4 files changed, 56 insertions(+), 24 deletions(-)
rename {dspace/etc => dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration}/postgres/update-sequences.sql (100%)
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 a8ca129e85..cf9157d21e 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
@@ -10,6 +10,7 @@ package org.dspace.storage.rdbms;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
@@ -88,7 +89,8 @@ public class DatabaseUtils {
// Usage checks
if (argv.length < 1) {
System.out.println("\nDatabase action argument is missing.");
- System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair', 'validate' or 'clean'");
+ System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair', 'validate', " +
+ "'update-sequences' or 'clean'");
System.out.println("\nOr, type 'database help' for more information.\n");
System.exit(1);
}
@@ -328,24 +330,54 @@ public class DatabaseUtils {
e.printStackTrace();
System.exit(1);
}
+ } else if (argv[0].equalsIgnoreCase("update-sequences")) {
+ try (Connection connection = dataSource.getConnection()) {
+ String dbType = getDbType(connection);
+ String sqlfile = "org/dspace/storage/rdbms/sqlmigration/" + dbType +
+ "/update-sequences.sql";
+ InputStream sqlstream = DatabaseUtils.class.getClassLoader().getResourceAsStream(sqlfile);
+ if (sqlstream != null) {
+ StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(sqlstream))) {
+ for (String line = br.readLine(); line != null; line = br.readLine()) {
+ sb.append(line);
+ }
+ }
+ if (sb.length() > 0) {
+ System.out.println("Running " + sqlfile);
+ connection.createStatement().execute(sb.toString());
+ System.out.println("update-sequences complete");
+ } else {
+ System.err.println(sqlfile + " contains no SQL to execute");
+ }
+ } else {
+ System.err.println(sqlfile + " not found");
+ }
+ }
} else {
System.out.println("\nUsage: database [action]");
- System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair' or 'clean'");
+ System.out.println("Valid actions: 'test', 'info', 'migrate', 'repair', " +
+ "'update-sequences' or 'clean'");
System.out.println(
- " - test = Performs a test connection to database to validate connection settings");
+ " - test = Performs a test connection to database to " +
+ "validate connection settings");
System.out.println(
- " - info / status = Describe basic info/status about database, including validating the " +
- "compatibility of this database");
- System.out.println(" - migrate = Migrate the database to the latest version");
+ " - info / status = Describe basic info/status about database, including validating the " +
+ "compatibility of this database");
System.out.println(
- " - repair = Attempt to repair any previously failed database migrations or checksum " +
- "mismatches (via Flyway repair)");
+ " - migrate = Migrate the database to the latest version");
System.out.println(
- " - validate = Validate current database's migration status (via Flyway validate), " +
- "validating all migration checksums.");
+ " - repair = Attempt to repair any previously failed database " +
+ "migrations or checksum mismatches (via Flyway repair)");
System.out.println(
- " - clean = DESTROY all data and tables in database (WARNING there is no going back!). " +
- "Requires 'db.cleanDisabled=false' setting in config.");
+ " - validate = Validate current database's migration status (via Flyway validate), " +
+ "validating all migration checksums.");
+ System.out.println(
+ " - update-sequences = Update database sequences after running AIP ingest.");
+ System.out.println(
+ " - clean = DESTROY all data and tables in database " +
+ "(WARNING there is no going back!). " +
+ "Requires 'db.cleanDisabled=false' setting in config.");
System.out.println("");
System.exit(0);
}
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/README.md b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/README.md
index 8f549b9c45..72eb279912 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/README.md
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/README.md
@@ -17,4 +17,16 @@ not realize you manually ran one or more scripts.
Please see the Flyway Documentation for more information: http://flywaydb.org/
+## Using the update-sequences.sql script
+
+The `update-sequences.sql` script in this directory may still be used to update
+your internal database counts if you feel they have gotten out of "sync". This
+may sometimes occur after large restores of content (e.g. when using the DSpace
+[AIP Backup and Restore](https://wiki.duraspace.org/display/DSDOC5x/AIP+Backup+and+Restore)
+feature).
+
+This `update-sequences.sql` script can be executed by running
+"dspace database update-sequences". It will not harm your
+database (or its contents) in any way. It just ensures all database counts (i.e.
+sequences) are properly set to the next available value.
diff --git a/dspace/etc/postgres/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
similarity index 100%
rename from dspace/etc/postgres/update-sequences.sql
rename to dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
diff --git a/dspace/etc/postgres/README.md b/dspace/etc/postgres/README.md
index 7d4a9ad2da..976f245931 100644
--- a/dspace/etc/postgres/README.md
+++ b/dspace/etc/postgres/README.md
@@ -19,15 +19,3 @@ database up-to-date. These scripts are now located in the source code at:
As Flyway automates the upgrade process, you should NEVER run these SQL scripts
manually. For more information, please see the `README.md` in the scripts directory.
-
-## Using the update-sequences.sql script
-
-The `update-sequences.sql` script in this directory may still be used to update
-your internal database counts if you feel they have gotten out of "sync". This
-may sometimes occur after large restores of content (e.g. when using the DSpace
-[AIP Backup and Restore](https://wiki.duraspace.org/display/DSDOC5x/AIP+Backup+and+Restore)
-feature).
-
-This `update-sequences.sql` script can be run manually. It will not harm your
-database (or its contents) in any way. It just ensures all database counts (i.e.
-sequences) are properly set to the next available value.
From e421a7c7c7580d9ef2f071d95f6790c39237152e Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 06:26:12 -0800
Subject: [PATCH 51/68] apply review feedback
---
.../dspace/storage/rdbms/DatabaseUtils.java | 2 +-
.../sqlmigration/oracle/update-sequences.sql | 104 ++++++++++++++++++
.../postgres/update-sequences.sql | 7 ++
3 files changed, 112 insertions(+), 1 deletion(-)
create mode 100644 dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
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 cf9157d21e..a32662f83c 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
@@ -333,7 +333,7 @@ public class DatabaseUtils {
} else if (argv[0].equalsIgnoreCase("update-sequences")) {
try (Connection connection = dataSource.getConnection()) {
String dbType = getDbType(connection);
- String sqlfile = "org/dspace/storage/rdbms/sqlmigration/" + dbType +
+ String sqlfile = "/org/dspace/storage/rdbms/sqlmigration/" + dbType +
"/update-sequences.sql";
InputStream sqlstream = DatabaseUtils.class.getClassLoader().getResourceAsStream(sqlfile);
if (sqlstream != null) {
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
new file mode 100644
index 0000000000..4a0402488f
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
@@ -0,0 +1,104 @@
+--
+-- 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/
+--
+-- update-sequences.sql
+--
+-- Copyright (c) 2002-2016, The DSpace Foundation. All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- - Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- - Redistributions in binary form must reproduce the above copyright
+-- notice, this list of conditions and the following disclaimer in the
+-- documentation and/or other materials provided with the distribution.
+--
+-- - Neither the name of the DSpace Foundation nor the names of its
+-- contributors may be used to endorse or promote products derived from
+-- this software without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+-- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+-- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+-- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+-- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+-- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+-- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+-- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+-- DAMAGE.
+
+-- SQL code to update the ID (primary key) generating sequences, if some
+-- import operation has set explicit IDs.
+--
+-- Sequences are used to generate IDs for new rows in the database. If a
+-- bulk import operation, such as an SQL dump, specifies primary keys for
+-- imported data explicitly, the sequences are out of sync and need updating.
+-- This SQL code does just that.
+--
+-- This should rarely be needed; any bulk import should be performed using the
+-- org.dspace.content API which is safe to use concurrently and in multiple
+-- JVMs. The SQL code below will typically only be required after a direct
+-- SQL data dump from a backup or somesuch.
+
+-- Depends on being run from sqlplus with incseq.sql in the current path
+-- you can find incseq.sql at: http://www.akadia.com/services/scripts/incseq.sql
+-- Here that script was renamed to updateseq.sql.
+
+DECLARE
+ PROCEDURE updateseq ( seq IN VARCHAR,
+ tbl IN VARCHAR,
+ attr IN VARCHAR,
+ cond IN VARCHAR ) IS
+ curr NUMBER := 0;
+ BEGIN
+ EXECUTE IMMEDIATE 'SELECT max('
+ || attr
+ || ') INTO curr FROM '
+ || tbl || ' ' || cond;
+ curr := curr + 1;
+ EXECUTE IMMEDIATE 'DROP SEQUENCE ' || seq;
+ EXECUTE IMMEDIATE 'CREATE SEQUENCE '
+ || seq
+ || ' START WITH '
+ || NVL(curr, 1);
+ END;
+BEGIN
+ updateseq('seq', 'tbl', 'attr', '');
+END;
+/
+
+execute updateseq(bitstreamformatregistry_seq, bitstreamformatregistry, bitstream_format_id, "");
+execute updateseq(fileextension_seq, fileextension, file_extension_id, "");
+execute updateseq(resourcepolicy_seq, resourcepolicy, policy_id, "");
+execute updateseq(workspaceitem_seq, workspaceitem, workspace_item_id, "");
+execute updateseq(workflowitem_seq, workflowitem, workflow_id, "");
+execute updateseq(tasklistitem_seq, tasklistitem, tasklist_id, "");
+execute updateseq(registrationdata_seq, registrationdata, registrationdata_id, "");
+execute updateseq(subscription_seq, subscription, subscription_id, "");
+execute updateseq(metadatafieldregistry_seq, metadatafieldregistry, metadata_field_id, "");
+execute updateseq(metadatavalue_seq, metadatavalue, metadata_value_id, "");
+execute updateseq(metadataschemaregistry_seq, metadataschemaregistry, metadata_schema_id, "");
+execute updateseq(harvested_collection_seq, harvested_collection, id, "");
+execute updateseq(harvested_item_seq, harvested_item, id, "");
+execute updateseq(webapp_seq, webapp, webapp_id, "");
+execute updateseq(requestitem_seq, requestitem, requestitem_id, "");
+execute updateseq(handle_id_seq, handle, handle_id, "");
+
+-- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
+-- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'
+-- always needs to be set to the value of the *largest* handle suffix. That way when the
+-- next handle is assigned, it will use the next largest number. This query does the following:
+-- For all 'handle' values which have a number in their suffix (after '/'), find the maximum
+-- suffix value, convert it to a number, and set the 'handle_seq' to start at the next value
+-- (see updateseq.sql script for more)
+execute updateseq(handle_seq, handle, "to_number(regexp_replace(handle, '.*/', ''), '999999999999')", "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')");
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
index 9928dbf319..e479993201 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
@@ -1,4 +1,11 @@
--
+-- 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/
+--
+--
-- update-sequences.sql
--
-- Copyright (c) 2002-2016, The DSpace Foundation. All rights reserved.
From 5f47771e4e95597e3286db73815f7a329036fa04 Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 06:26:28 -0800
Subject: [PATCH 52/68] remove /etc directory
---
dspace/etc/oracle/README.md | 33 ------------
dspace/etc/oracle/update-sequences.sql | 75 --------------------------
dspace/etc/oracle/updateseq.sql | 30 -----------
dspace/etc/postgres/README.md | 21 --------
4 files changed, 159 deletions(-)
delete mode 100644 dspace/etc/oracle/README.md
delete mode 100644 dspace/etc/oracle/update-sequences.sql
delete mode 100644 dspace/etc/oracle/updateseq.sql
delete mode 100644 dspace/etc/postgres/README.md
diff --git a/dspace/etc/oracle/README.md b/dspace/etc/oracle/README.md
deleted file mode 100644
index 0ed2a66aa9..0000000000
--- a/dspace/etc/oracle/README.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# DSpace Database Now Upgrades Automatically
-
-AS OF DSPACE 5, the DSpace database now upgrades itself AUTOMATICALLY.
-
-Therefore, all `database_schema*.sql` files have been removed. Starting
-with DSpace 4.x -> 5.0 upgrade, you will no longer need to manually run any
-SQL scripts to upgrade your database.
-
-Please see the [5.0 Upgrade Instructions](https://wiki.duraspace.org/display/DSDOC5x/Upgrading+DSpace)
-for more information on upgrading to DSpace 5.
-
-
-## More info on automatic database upgrades
-
-As of DSpace 5.0, we now use [Flyway DB](http://flywaydb.org/) along with the
-SQL scripts embedded in the `dspace-api.jar` to automatically keep your DSpace
-database up-to-date. These scripts are now located in the source code at:
-`[dspace-src]/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle`
-
-As Flyway automates the upgrade process, you should NEVER run these SQL scripts
-manually. For more information, please see the `README.md` in the scripts directory.
-
-## Using the update-sequences.sql script
-
-The `update-sequences.sql` script in this directory may still be used to update
-your internal database counts if you feel they have gotten out of "sync". This
-may sometimes occur after large restores of content (e.g. when using the DSpace
-[AIP Backup and Restore](https://wiki.duraspace.org/display/DSDOC5x/AIP+Backup+and+Restore)
-feature).
-
-This `update-sequences.sql` script can be run manually. It will not harm your
-database (or its contents) in any way. It just ensures all database counts (i.e.
-sequences) are properly set to the next available value.
diff --git a/dspace/etc/oracle/update-sequences.sql b/dspace/etc/oracle/update-sequences.sql
deleted file mode 100644
index d40f7665a7..0000000000
--- a/dspace/etc/oracle/update-sequences.sql
+++ /dev/null
@@ -1,75 +0,0 @@
---
--- update-sequences.sql
---
--- Copyright (c) 2002-2016, The DSpace Foundation. All rights reserved.
---
--- Redistribution and use in source and binary forms, with or without
--- modification, are permitted provided that the following conditions are
--- met:
---
--- - Redistributions of source code must retain the above copyright
--- notice, this list of conditions and the following disclaimer.
---
--- - Redistributions in binary form must reproduce the above copyright
--- notice, this list of conditions and the following disclaimer in the
--- documentation and/or other materials provided with the distribution.
---
--- - Neither the name of the DSpace Foundation nor the names of its
--- contributors may be used to endorse or promote products derived from
--- this software without specific prior written permission.
---
--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
--- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
--- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
--- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
--- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
--- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
--- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
--- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
--- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
--- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
--- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
--- DAMAGE.
-
--- SQL code to update the ID (primary key) generating sequences, if some
--- import operation has set explicit IDs.
---
--- Sequences are used to generate IDs for new rows in the database. If a
--- bulk import operation, such as an SQL dump, specifies primary keys for
--- imported data explicitly, the sequences are out of sync and need updating.
--- This SQL code does just that.
---
--- This should rarely be needed; any bulk import should be performed using the
--- org.dspace.content API which is safe to use concurrently and in multiple
--- JVMs. The SQL code below will typically only be required after a direct
--- SQL data dump from a backup or somesuch.
-
--- Depends on being run from sqlplus with incseq.sql in the current path
--- you can find incseq.sql at: http://www.akadia.com/services/scripts/incseq.sql
--- Here that script was renamed to updateseq.sql.
-
-@updateseq.sql bitstreamformatregistry_seq bitstreamformatregistry bitstream_format_id ""
-@updateseq.sql fileextension_seq fileextension file_extension_id ""
-@updateseq.sql resourcepolicy_seq resourcepolicy policy_id ""
-@updateseq.sql workspaceitem_seq workspaceitem workspace_item_id ""
-@updateseq.sql workflowitem_seq workflowitem workflow_id ""
-@updateseq.sql tasklistitem_seq tasklistitem tasklist_id ""
-@updateseq.sql registrationdata_seq registrationdata registrationdata_id ""
-@updateseq.sql subscription_seq subscription subscription_id ""
-@updateseq.sql metadatafieldregistry_seq metadatafieldregistry metadata_field_id ""
-@updateseq.sql metadatavalue_seq metadatavalue metadata_value_id ""
-@updateseq.sql metadataschemaregistry_seq metadataschemaregistry metadata_schema_id ""
-@updateseq.sql harvested_collection_seq harvested_collection id ""
-@updateseq.sql harvested_item_seq harvested_item id ""
-@updateseq.sql webapp_seq webapp webapp_id ""
-@updateseq.sql requestitem_seq requestitem requestitem_id ""
-@updateseq.sql handle_id_seq handle handle_id ""
-
--- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
--- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'
--- always needs to be set to the value of the *largest* handle suffix. That way when the
--- next handle is assigned, it will use the next largest number. This query does the following:
--- For all 'handle' values which have a number in their suffix (after '/'), find the maximum
--- suffix value, convert it to a number, and set the 'handle_seq' to start at the next value
--- (see updateseq.sql script for more)
-@updateseq.sql handle_seq handle "to_number(regexp_replace(handle, '.*/', ''), '999999999999')" "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')"
diff --git a/dspace/etc/oracle/updateseq.sql b/dspace/etc/oracle/updateseq.sql
deleted file mode 100644
index 49d3701cd2..0000000000
--- a/dspace/etc/oracle/updateseq.sql
+++ /dev/null
@@ -1,30 +0,0 @@
--- #############################################################################################
---
--- %Purpose: Set a sequence to the max value of a given attribute
---
--- #############################################################################################
---
--- Paramters:
--- 1: sequence name
--- 2: table name
--- 3: attribute name
---
--- Sample usage:
--- @updateseq.sql my_sequence my_table my_attribute where-clause
---
---------------------------------------------------------------------------------
---
-SET SERVEROUTPUT ON SIZE 1000000;
---
-DECLARE
- curr NUMBER := 0;
-BEGIN
- SELECT max(&3) INTO curr FROM &2 &4;
-
- curr := curr + 1;
-
- EXECUTE IMMEDIATE 'DROP SEQUENCE &1';
-
- EXECUTE IMMEDIATE 'CREATE SEQUENCE &1 START WITH ' || NVL(curr,1);
-END;
-/
diff --git a/dspace/etc/postgres/README.md b/dspace/etc/postgres/README.md
deleted file mode 100644
index 976f245931..0000000000
--- a/dspace/etc/postgres/README.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# DSpace Database Now Upgrades Automatically
-
-AS OF DSPACE 5, the DSpace database now upgrades itself AUTOMATICALLY.
-
-Therefore, all `database_schema*.sql` files have been removed. Starting
-with DSpace 4.x -> 5.0 upgrade, you will no longer need to manually run any
-SQL scripts to upgrade your database.
-
-Please see the [5.0 Upgrade Instructions](https://wiki.duraspace.org/display/DSDOC5x/Upgrading+DSpace)
-for more information on upgrading to DSpace 5.
-
-
-## More info on automatic database upgrades
-
-As of DSpace 5.0, we now use [Flyway DB](http://flywaydb.org/) along with the
-SQL scripts embedded in the `dspace-api.jar` to automatically keep your DSpace
-database up-to-date. These scripts are now located in the source code at:
-`[dspace-src]/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres`
-
-As Flyway automates the upgrade process, you should NEVER run these SQL scripts
-manually. For more information, please see the `README.md` in the scripts directory.
From 22cc5469a23f6f86d4cb330030f8a542c8149efd Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 06:30:25 -0800
Subject: [PATCH 53/68] simplify string extract from stream
---
.../java/org/dspace/storage/rdbms/DatabaseUtils.java | 12 ++++--------
1 file changed, 4 insertions(+), 8 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 a32662f83c..2dfac7fa93 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
@@ -24,6 +24,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.sql.DataSource;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.core.Context;
@@ -337,15 +338,10 @@ public class DatabaseUtils {
"/update-sequences.sql";
InputStream sqlstream = DatabaseUtils.class.getClassLoader().getResourceAsStream(sqlfile);
if (sqlstream != null) {
- StringBuilder sb = new StringBuilder();
- try (BufferedReader br = new BufferedReader(new InputStreamReader(sqlstream))) {
- for (String line = br.readLine(); line != null; line = br.readLine()) {
- sb.append(line);
- }
- }
- if (sb.length() > 0) {
+ String s = IOUtils.toString(sqlstream, "UTF-8");
+ if (!s.isEmpty()) {
System.out.println("Running " + sqlfile);
- connection.createStatement().execute(sb.toString());
+ connection.createStatement().execute(s);
System.out.println("update-sequences complete");
} else {
System.err.println(sqlfile + " contains no SQL to execute");
From 4ac06271c874a36e0c7f51e3b274ad9483b4dfa5 Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 06:53:30 -0800
Subject: [PATCH 54/68] attempt to fix headers
---
.../sqlmigration/oracle/update-sequences.sql | 31 ------------------
.../postgres/update-sequences.sql | 32 -------------------
2 files changed, 63 deletions(-)
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
index 4a0402488f..1f70d409f4 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
@@ -5,37 +5,6 @@
--
-- http://www.dspace.org/license/
--
--- update-sequences.sql
---
--- Copyright (c) 2002-2016, The DSpace Foundation. All rights reserved.
---
--- Redistribution and use in source and binary forms, with or without
--- modification, are permitted provided that the following conditions are
--- met:
---
--- - Redistributions of source code must retain the above copyright
--- notice, this list of conditions and the following disclaimer.
---
--- - Redistributions in binary form must reproduce the above copyright
--- notice, this list of conditions and the following disclaimer in the
--- documentation and/or other materials provided with the distribution.
---
--- - Neither the name of the DSpace Foundation nor the names of its
--- contributors may be used to endorse or promote products derived from
--- this software without specific prior written permission.
---
--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
--- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
--- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
--- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
--- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
--- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
--- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
--- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
--- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
--- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
--- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
--- DAMAGE.
-- SQL code to update the ID (primary key) generating sequences, if some
-- import operation has set explicit IDs.
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
index e479993201..c1aaadce86 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/update-sequences.sql
@@ -5,38 +5,6 @@
--
-- http://www.dspace.org/license/
--
---
--- update-sequences.sql
---
--- Copyright (c) 2002-2016, The DSpace Foundation. All rights reserved.
---
--- Redistribution and use in source and binary forms, with or without
--- modification, are permitted provided that the following conditions are
--- met:
---
--- - Redistributions of source code must retain the above copyright
--- notice, this list of conditions and the following disclaimer.
---
--- - Redistributions in binary form must reproduce the above copyright
--- notice, this list of conditions and the following disclaimer in the
--- documentation and/or other materials provided with the distribution.
---
--- Neither the name of the DSpace Foundation nor the names of its
--- contributors may be used to endorse or promote products derived from
--- this software without specific prior written permission.
---
--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
--- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
--- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
--- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
--- HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
--- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
--- BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
--- OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
--- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
--- TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
--- USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
--- DAMAGE.
-- SQL code to update the ID (primary key) generating sequences, if some
-- import operation has set explicit IDs.
From f829b7df5a1ee75077003e65706ecf0890f1ab61 Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 07:11:23 -0800
Subject: [PATCH 55/68] remove dspace/etc from build steps
---
dspace/src/main/config/build.xml | 27 ---------------------------
1 file changed, 27 deletions(-)
diff --git a/dspace/src/main/config/build.xml b/dspace/src/main/config/build.xml
index ab13191561..8b4f588dd0 100644
--- a/dspace/src/main/config/build.xml
+++ b/dspace/src/main/config/build.xml
@@ -569,16 +569,6 @@ Common usage:
-
-
-
-
-
-
-
-
-
-
@@ -593,10 +583,6 @@ Common usage:
${dspace.dir}/lib.bak-${build.date}
- ${dspace.dir}/etc was backed up to
-
- ${dspace.dir}/etc.bak-${build.date}
-
Please review these directories and delete if no longer needed.
====================================================================
@@ -728,8 +714,6 @@ Common usage:
-
-
@@ -821,17 +805,6 @@ Common usage:
-
-
-
-
-
-
-
-
-
From 89c1cc77291977329ba7f71eb3817ddf6604096f Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 07:34:56 -0800
Subject: [PATCH 56/68] remove /org
---
.../src/main/java/org/dspace/storage/rdbms/DatabaseUtils.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 2dfac7fa93..f4b0936c6f 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
@@ -334,7 +334,7 @@ public class DatabaseUtils {
} else if (argv[0].equalsIgnoreCase("update-sequences")) {
try (Connection connection = dataSource.getConnection()) {
String dbType = getDbType(connection);
- String sqlfile = "/org/dspace/storage/rdbms/sqlmigration/" + dbType +
+ String sqlfile = "org/dspace/storage/rdbms/sqlmigration/" + dbType +
"/update-sequences.sql";
InputStream sqlstream = DatabaseUtils.class.getClassLoader().getResourceAsStream(sqlfile);
if (sqlstream != null) {
From 7773b46aca60ed129e6fe6a93f18a77a1538e05e Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Tue, 19 Feb 2019 10:16:21 -0800
Subject: [PATCH 57/68] update sql
---
.../sqlmigration/oracle/update-sequences.sql | 68 +++++++++++++------
1 file changed, 46 insertions(+), 22 deletions(-)
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
index 1f70d409f4..5b7b9324b2 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
@@ -23,7 +23,9 @@
-- you can find incseq.sql at: http://www.akadia.com/services/scripts/incseq.sql
-- Here that script was renamed to updateseq.sql.
-DECLARE
+--
+
+create or replace
PROCEDURE updateseq ( seq IN VARCHAR,
tbl IN VARCHAR,
attr IN VARCHAR,
@@ -41,27 +43,49 @@ DECLARE
|| ' START WITH '
|| NVL(curr, 1);
END;
-BEGIN
- updateseq('seq', 'tbl', 'attr', '');
-END;
-/
-execute updateseq(bitstreamformatregistry_seq, bitstreamformatregistry, bitstream_format_id, "");
-execute updateseq(fileextension_seq, fileextension, file_extension_id, "");
-execute updateseq(resourcepolicy_seq, resourcepolicy, policy_id, "");
-execute updateseq(workspaceitem_seq, workspaceitem, workspace_item_id, "");
-execute updateseq(workflowitem_seq, workflowitem, workflow_id, "");
-execute updateseq(tasklistitem_seq, tasklistitem, tasklist_id, "");
-execute updateseq(registrationdata_seq, registrationdata, registrationdata_id, "");
-execute updateseq(subscription_seq, subscription, subscription_id, "");
-execute updateseq(metadatafieldregistry_seq, metadatafieldregistry, metadata_field_id, "");
-execute updateseq(metadatavalue_seq, metadatavalue, metadata_value_id, "");
-execute updateseq(metadataschemaregistry_seq, metadataschemaregistry, metadata_schema_id, "");
-execute updateseq(harvested_collection_seq, harvested_collection, id, "");
-execute updateseq(harvested_item_seq, harvested_item, id, "");
-execute updateseq(webapp_seq, webapp, webapp_id, "");
-execute updateseq(requestitem_seq, requestitem, requestitem_id, "");
-execute updateseq(handle_id_seq, handle, handle_id, "");
+create or replace procedure updateseq(
+ seq IN VARCHAR,
+ tbl IN VARCHAR,
+ attr IN VARCHAR,
+ cond IN VARCHAR )
+IS
+ l_val number := 0;
+ new_val number:= 0;
+ offset number:=0;
+BEGIN
+ execute immediate
+ 'select ' || seq || '.nextval from dual' INTO l_val;
+
+ execute immediate
+ 'select max(' || attr || ') from ' || tbl || ' ' || cond || '' INTO new_val;
+
+ execute immediate
+ 'alter sequence ' || seq || ' increment by ' || (new_val - l_val + 1) || ' minvalue 0';
+
+ execute immediate
+ 'select ' || seq || '.nextval from dual' INTO l_val;
+
+ execute immediate
+ 'alter sequence ' || seq || ' increment by 1 minvalue 0';
+END;
+
+execute updateseq('bitstreamformatregistry_seq', 'bitstreamformatregistry', 'bitstream_format_id', '');
+execute updateseq('fileextension_seq', 'fileextension', 'file_extension_id', '');
+execute updateseq('resourcepolicy_seq', 'resourcepolicy', 'policy_id', '');
+execute updateseq('workspaceitem_seq', 'workspaceitem', 'workspace_item_id', '');
+execute updateseq('workflowitem_seq', 'workflowitem', 'workflow_id', '');
+execute updateseq('tasklistitem_seq', 'tasklistitem', 'tasklist_id', '');
+execute updateseq('registrationdata_seq', 'registrationdata', 'registrationdata_id', '');
+execute updateseq('subscription_seq', 'subscription', 'subscription_id', '');
+execute updateseq('metadatafieldregistry_seq', 'metadatafieldregistry', 'metadata_field_id', '');
+execute updateseq('metadatavalue_seq', 'metadatavalue', 'metadata_value_id', '');
+execute updateseq('metadataschemaregistry_seq', 'metadataschemaregistry', 'metadata_schema_id', '');
+execute updateseq('harvested_collection_seq', 'harvested_collection', 'id', '');
+execute updateseq('harvested_item_seq', 'harvested_item', 'id', '');
+execute updateseq('webapp_seq', 'webapp', 'webapp_id', '');
+execute updateseq('requestitem_seq', 'requestitem', 'requestitem_id', '');
+execute updateseq('handle_id_seq', 'handle', 'handle_id', '');
-- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
-- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'
@@ -70,4 +94,4 @@ execute updateseq(handle_id_seq, handle, handle_id, "");
-- For all 'handle' values which have a number in their suffix (after '/'), find the maximum
-- suffix value, convert it to a number, and set the 'handle_seq' to start at the next value
-- (see updateseq.sql script for more)
-execute updateseq(handle_seq, handle, "to_number(regexp_replace(handle, '.*/', ''), '999999999999')", "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')");
+execute updateseq('handle_seq', 'handle', "to_number(regexp_replace(handle, '.*/', ''), '999999999999')", "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')");
From 330283565098296a6dbe05699b567bcfdeb64b9b Mon Sep 17 00:00:00 2001
From: "Mark H. Wood"
Date: Wed, 20 Feb 2019 11:23:21 -0500
Subject: [PATCH 58/68] [DS-4167] Fix various problems with Oracle script.
---
.../sqlmigration/oracle/update-sequences.sql | 80 ++++++++++---------
1 file changed, 43 insertions(+), 37 deletions(-)
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
index 1f70d409f4..cc706416ab 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
@@ -19,55 +19,61 @@
-- JVMs. The SQL code below will typically only be required after a direct
-- SQL data dump from a backup or somesuch.
--- Depends on being run from sqlplus with incseq.sql in the current path
--- you can find incseq.sql at: http://www.akadia.com/services/scripts/incseq.sql
--- Here that script was renamed to updateseq.sql.
+-- The 'updateseq' procedure was derived from incseq.sql found at:
+-- http://www.akadia.com/services/scripts/incseq.sql
DECLARE
PROCEDURE updateseq ( seq IN VARCHAR,
tbl IN VARCHAR,
attr IN VARCHAR,
- cond IN VARCHAR ) IS
+ cond IN VARCHAR DEFAULT '' ) IS
curr NUMBER := 0;
BEGIN
- EXECUTE IMMEDIATE 'SELECT max('
- || attr
- || ') INTO curr FROM '
- || tbl || ' ' || cond;
+ EXECUTE IMMEDIATE 'SELECT max(' || attr
+ || ') FROM ' || tbl
+ || ' ' || cond
+ INTO curr;
curr := curr + 1;
EXECUTE IMMEDIATE 'DROP SEQUENCE ' || seq;
EXECUTE IMMEDIATE 'CREATE SEQUENCE '
|| seq
|| ' START WITH '
|| NVL(curr, 1);
- END;
+ END updateseq;
+
BEGIN
- updateseq('seq', 'tbl', 'attr', '');
+ updateseq('bitstreamformatregistry_seq', 'bitstreamformatregistry',
+ 'bitstream_format_id');
+ updateseq('fileextension_seq', 'fileextension', 'file_extension_id');
+ updateseq('resourcepolicy_seq', 'resourcepolicy', 'policy_id');
+ updateseq('workspaceitem_seq', 'workspaceitem', 'workspace_item_id');
+ updateseq('workflowitem_seq', 'workflowitem', 'workflow_id');
+ updateseq('tasklistitem_seq', 'tasklistitem', 'tasklist_id');
+ updateseq('registrationdata_seq', 'registrationdata',
+ 'registrationdata_id');
+ updateseq('subscription_seq', 'subscription', 'subscription_id');
+ updateseq('metadatafieldregistry_seq', 'metadatafieldregistry',
+ 'metadata_field_id');
+ updateseq('metadatavalue_seq', 'metadatavalue', 'metadata_value_id');
+ updateseq('metadataschemaregistry_seq', 'metadataschemaregistry',
+ 'metadata_schema_id');
+ updateseq('harvested_collection_seq', 'harvested_collection', 'id');
+ updateseq('harvested_item_seq', 'harvested_item', 'id');
+ updateseq('webapp_seq', 'webapp', 'webapp_id');
+ updateseq('requestitem_seq', 'requestitem', 'requestitem_id');
+ updateseq('handle_id_seq', 'handle', 'handle_id');
+
+ -- Handle Sequence is a special case. Since Handles minted by DSpace
+ -- use the 'handle_seq', we need to ensure the next assigned handle
+ -- will *always* be unique. So, 'handle_seq' always needs to be set
+ -- to the value of the *largest* handle suffix. That way when the
+ -- next handle is assigned, it will use the next largest number. This
+ -- query does the following:
+ -- For all 'handle' values which have a number in their suffix
+ -- (after '/'), find the maximum suffix value, convert it to a
+ -- number, and set the 'handle_seq' to start at the next value (see
+ -- updateseq above for more).
+ updateseq('handle_seq', 'handle',
+ q'{to_number(regexp_replace(handle, '.*/', ''), '999999999999')}',
+ q'{WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')}');
END;
-/
-
-execute updateseq(bitstreamformatregistry_seq, bitstreamformatregistry, bitstream_format_id, "");
-execute updateseq(fileextension_seq, fileextension, file_extension_id, "");
-execute updateseq(resourcepolicy_seq, resourcepolicy, policy_id, "");
-execute updateseq(workspaceitem_seq, workspaceitem, workspace_item_id, "");
-execute updateseq(workflowitem_seq, workflowitem, workflow_id, "");
-execute updateseq(tasklistitem_seq, tasklistitem, tasklist_id, "");
-execute updateseq(registrationdata_seq, registrationdata, registrationdata_id, "");
-execute updateseq(subscription_seq, subscription, subscription_id, "");
-execute updateseq(metadatafieldregistry_seq, metadatafieldregistry, metadata_field_id, "");
-execute updateseq(metadatavalue_seq, metadatavalue, metadata_value_id, "");
-execute updateseq(metadataschemaregistry_seq, metadataschemaregistry, metadata_schema_id, "");
-execute updateseq(harvested_collection_seq, harvested_collection, id, "");
-execute updateseq(harvested_item_seq, harvested_item, id, "");
-execute updateseq(webapp_seq, webapp, webapp_id, "");
-execute updateseq(requestitem_seq, requestitem, requestitem_id, "");
-execute updateseq(handle_id_seq, handle, handle_id, "");
-
--- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
--- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'
--- always needs to be set to the value of the *largest* handle suffix. That way when the
--- next handle is assigned, it will use the next largest number. This query does the following:
--- For all 'handle' values which have a number in their suffix (after '/'), find the maximum
--- suffix value, convert it to a number, and set the 'handle_seq' to start at the next value
--- (see updateseq.sql script for more)
-execute updateseq(handle_seq, handle, "to_number(regexp_replace(handle, '.*/', ''), '999999999999')", "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')");
From 35e98f0d4b71f0806576f8f4c955b1cce70fe8bb Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Wed, 20 Feb 2019 08:40:34 -0800
Subject: [PATCH 59/68] v1 oracle sql
---
.../sqlmigration/oracle/update-sequences.sql | 61 +++++++++++--------
1 file changed, 37 insertions(+), 24 deletions(-)
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
index 5b7b9324b2..780a78074a 100644
--- a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/oracle/update-sequences.sql
@@ -25,43 +25,27 @@
--
-create or replace
- PROCEDURE updateseq ( seq IN VARCHAR,
- tbl IN VARCHAR,
- attr IN VARCHAR,
- cond IN VARCHAR ) IS
- curr NUMBER := 0;
- BEGIN
- EXECUTE IMMEDIATE 'SELECT max('
- || attr
- || ') INTO curr FROM '
- || tbl || ' ' || cond;
- curr := curr + 1;
- EXECUTE IMMEDIATE 'DROP SEQUENCE ' || seq;
- EXECUTE IMMEDIATE 'CREATE SEQUENCE '
- || seq
- || ' START WITH '
- || NVL(curr, 1);
- END;
-
create or replace procedure updateseq(
seq IN VARCHAR,
tbl IN VARCHAR,
- attr IN VARCHAR,
- cond IN VARCHAR )
+ attr IN VARCHAR2,
+ cond IN VARCHAR2 )
IS
l_val number := 0;
new_val number:= 0;
- offset number:=0;
BEGIN
execute immediate
'select ' || seq || '.nextval from dual' INTO l_val;
execute immediate
'select max(' || attr || ') from ' || tbl || ' ' || cond || '' INTO new_val;
+
+ IF new_val is null THEN
+ new_val := 0;
+ END IF;
execute immediate
- 'alter sequence ' || seq || ' increment by ' || (new_val - l_val + 1) || ' minvalue 0';
+ 'alter sequence ' || seq || ' increment by ' || (new_val - l_val) || ' minvalue 0';
execute immediate
'select ' || seq || '.nextval from dual' INTO l_val;
@@ -87,6 +71,7 @@ execute updateseq('webapp_seq', 'webapp', 'webapp_id', '');
execute updateseq('requestitem_seq', 'requestitem', 'requestitem_id', '');
execute updateseq('handle_id_seq', 'handle', 'handle_id', '');
+
-- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq',
-- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq'
-- always needs to be set to the value of the *largest* handle suffix. That way when the
@@ -94,4 +79,32 @@ execute updateseq('handle_id_seq', 'handle', 'handle_id', '');
-- For all 'handle' values which have a number in their suffix (after '/'), find the maximum
-- suffix value, convert it to a number, and set the 'handle_seq' to start at the next value
-- (see updateseq.sql script for more)
-execute updateseq('handle_seq', 'handle', "to_number(regexp_replace(handle, '.*/', ''), '999999999999')", "WHERE REGEXP_LIKE(handle, '^.*/[0123456789]*$')");
+
+create or replace procedure updatehandleseq(
+ seq IN VARCHAR )
+IS
+ l_val number := 0;
+ new_val number := 0;
+BEGIN
+ execute immediate
+ 'select ' || seq || '.nextval from dual' INTO l_val;
+
+ execute immediate
+ 'select max(to_number(regexp_replace(handle, ''.*/'', ''''), ''999999999999'')) from handle WHERE REGEXP_LIKE(handle, ''^.*/[0123456789]*$'')' INTO new_val;
+
+ IF new_val is null THEN
+ new_val := 0;
+ END IF;
+
+ execute immediate
+ 'alter sequence ' || seq || ' increment by ' || (new_val - l_val) || ' minvalue 0';
+
+ execute immediate
+ 'select ' || seq || '.nextval from dual' INTO l_val;
+
+ execute immediate
+ 'alter sequence ' || seq || ' increment by 1 minvalue 0';
+END;
+
+
+execute updatehandleseq('bitstreamformatregistry_seq');
From 60ea589296836b20d154e711cd1a5c3f771ad4de Mon Sep 17 00:00:00 2001
From: Chris Wilper
Date: Tue, 11 Dec 2018 15:27:25 -0500
Subject: [PATCH 60/68] DS-4107 Represent DSO metadata as a map in REST
---
.../rest/converter/DSpaceObjectConverter.java | 19 +-
.../app/rest/converter/MetadataConverter.java | 91 +++++++
.../converter/MetadataValueConverter.java | 28 +++
.../app/rest/model/DSpaceObjectRest.java | 8 +-
.../app/rest/model/MetadataEntryRest.java | 47 ----
.../dspace/app/rest/model/MetadataRest.java | 56 +++++
.../app/rest/model/MetadataValueRest.java | 15 +-
.../repository/CollectionRestRepository.java | 22 +-
.../repository/CommunityRestRepository.java | 24 +-
.../rest/repository/DSpaceRestRepository.java | 4 +
.../repository/EPersonRestRepository.java | 13 +-
.../rest/repository/GroupRestRepository.java | 14 +-
.../rest/repository/ItemRestRepository.java | 16 +-
.../app/rest/utils/DSpaceObjectUtils.java | 62 -----
.../app/rest/BrowsesResourceControllerIT.java | 17 +-
.../app/rest/CollectionRestRepositoryIT.java | 79 +++---
.../app/rest/CommunityRestRepositoryIT.java | 137 +++++-----
.../app/rest/EPersonRestRepositoryIT.java | 23 +-
.../dspace/app/rest/ItemRestRepositoryIT.java | 235 ++++++------------
.../app/rest/matcher/BitstreamMatcher.java | 8 +-
.../matcher/BitstreamMetadataMatcher.java | 33 ---
.../app/rest/matcher/CollectionMatcher.java | 4 +-
.../matcher/CollectionMetadataMatcher.java | 26 --
.../app/rest/matcher/CommunityMatcher.java | 4 +-
.../app/rest/matcher/EPersonMatcher.java | 6 +-
.../rest/matcher/EPersonMetadataMatcher.java | 40 ---
.../dspace/app/rest/matcher/ItemMatcher.java | 7 +-
...adataMatcher.java => MetadataMatcher.java} | 15 +-
28 files changed, 431 insertions(+), 622 deletions(-)
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java
delete mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataEntryRest.java
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
delete mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectUtils.java
delete mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java
delete mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java
delete mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java
rename dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/{CommunityMetadataMatcher.java => MetadataMatcher.java} (56%)
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..462768de4b 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
@@ -7,12 +7,8 @@
*/
package org.dspace.app.rest.converter;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.content.DSpaceObject;
-import org.dspace.content.MetadataValue;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* This is the base converter from/to objects in the DSpace API data model and
@@ -26,6 +22,9 @@ public abstract class DSpaceObjectConverter
extends DSpaceConverter {
+ @Autowired(required = true)
+ private MetadataConverter metadataConverter;
+
@Override
public R fromModel(M obj) {
R resource = newInstance();
@@ -34,15 +33,7 @@ public abstract class DSpaceObjectConverter metadata = new ArrayList();
- for (MetadataValue mv : obj.getMetadata()) {
- MetadataEntryRest me = new MetadataEntryRest();
- me.setKey(mv.getMetadataField().toString('.'));
- me.setValue(mv.getValue());
- me.setLanguage(mv.getLanguage());
- metadata.add(me);
- }
- resource.setMetadata(metadata);
+ resource.setMetadata(metadataConverter.convert(obj.getMetadata()));
return resource;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
new file mode 100644
index 0000000000..ec1835bf07
--- /dev/null
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
@@ -0,0 +1,91 @@
+/**
+ * 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 java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.MetadataValueRest;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.content.DSpaceObject;
+import org.dspace.content.Item;
+import org.dspace.content.MetadataValue;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.DSpaceObjectService;
+import org.dspace.core.Context;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MetadataConverter implements Converter, MetadataRest> {
+
+ @Autowired
+ private ContentServiceFactory contentServiceFactory;
+
+ @Autowired
+ private MetadataValueConverter valueConverter;
+
+ @Override
+ public MetadataRest convert(List metadataValueList) {
+ // Convert each value to a DTO while retaining place order in a map of key -> SortedSet
+ Map> mapOfSortedSets = new HashMap<>();
+ for (MetadataValue metadataValue : metadataValueList) {
+ String key = metadataValue.getMetadataField().toString('.');
+ SortedSet set = mapOfSortedSets.get(key);
+ if (set == null) {
+ set = new TreeSet<>(Comparator.comparingInt(MetadataValueRest::getPlace));
+ mapOfSortedSets.put(key, set);
+ }
+ set.add(valueConverter.convert(metadataValue));
+ }
+
+ MetadataRest metadataRest = new MetadataRest();
+
+ // Populate MetadataRest's map of key -> List while respecting SortedSet's order
+ Map> mapOfLists = metadataRest.getMap();
+ for (Map.Entry> entry : mapOfSortedSets.entrySet()) {
+ mapOfLists.put(entry.getKey(), entry.getValue().stream().collect(Collectors.toList()));
+ }
+
+ return metadataRest;
+ }
+
+ /**
+ * Completely replaces the metadata in the given dso.
+ *
+ * @param context the context to use.
+ * @param dso the dso whose metadata should be updated.
+ * @param metadataRest the new metadata.
+ * @throws SQLException if a database error occurs.
+ * @throws AuthorizeException if an authorization error occurs.
+ */
+ public void setMetadata(Context context, DSpaceObject dso, MetadataRest metadataRest)
+ throws SQLException, AuthorizeException {
+ DSpaceObjectService dsoService = contentServiceFactory.getDSpaceObjectService(dso);
+ dsoService.clearMetadata(context, dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
+ for (Map.Entry> entry: metadataRest.getMap().entrySet()) {
+ String[] seq = entry.getKey().split("\\.");
+ String schema = seq[0];
+ String element = seq[1];
+ String qualifier = seq.length == 3 ? seq[2] : null;
+ for (MetadataValueRest mvr: entry.getValue()) {
+ dsoService.addMetadata(context, dso, schema, element, qualifier, mvr.getLanguage(),
+ mvr.getValue(), mvr.getAuthority(), mvr.getConfidence());
+ }
+ }
+ dsoService.update(context, dso);
+ }
+}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java
new file mode 100644
index 0000000000..1dfe4ab12f
--- /dev/null
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.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.app.rest.converter;
+
+import org.dspace.app.rest.model.MetadataValueRest;
+import org.dspace.content.MetadataValue;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.stereotype.Component;
+
+@Component
+public class MetadataValueConverter implements Converter {
+
+ @Override
+ public MetadataValueRest convert(MetadataValue model) {
+ MetadataValueRest metadataValueRest = new MetadataValueRest();
+ metadataValueRest.setValue(model.getValue());
+ metadataValueRest.setLanguage(model.getLanguage());
+ metadataValueRest.setAuthority(model.getAuthority());
+ metadataValueRest.setConfidence(model.getConfidence());
+ metadataValueRest.setPlace(model.getPlace());
+ return metadataValueRest;
+ }
+}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
index bf89cd7a61..c0ef206aa1 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
@@ -7,8 +7,6 @@
*/
package org.dspace.app.rest.model;
-import java.util.List;
-
import org.dspace.app.rest.RestResourceController;
/**
@@ -22,7 +20,7 @@ public abstract class DSpaceObjectRest extends BaseObjectRest {
private String name;
private String handle;
- List metadata;
+ MetadataRest metadata = new MetadataRest();
@Override
public String getId() {
@@ -53,11 +51,11 @@ public abstract class DSpaceObjectRest extends BaseObjectRest {
this.handle = handle;
}
- public List getMetadata() {
+ public MetadataRest getMetadata() {
return metadata;
}
- public void setMetadata(List metadata) {
+ public void setMetadata(MetadataRest metadata) {
this.metadata = metadata;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataEntryRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataEntryRest.java
deleted file mode 100644
index da2b841f2e..0000000000
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataEntryRest.java
+++ /dev/null
@@ -1,47 +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.app.rest.model;
-
-/**
- * An embeddable representation of the Metadata to use in with DSpace REST
- * Resource
- *
- * @author Andrea Bollini (andrea.bollini at 4science.it)
- */
-public class MetadataEntryRest {
- String key;
-
- String value;
-
- String language;
-
- public String getKey() {
- return key;
- }
-
- public void setKey(String key) {
- this.key = key;
- }
-
- public String getValue() {
- return value;
- }
-
- public void setValue(String value) {
- this.value = value;
- }
-
- public String getLanguage() {
- return language;
- }
-
- public void setLanguage(String language) {
- this.language = language;
- }
-
-}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
new file mode 100644
index 0000000000..6225843d62
--- /dev/null
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.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.model;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+public class MetadataRest {
+
+ @JsonAnySetter
+ private SortedMap> map = new TreeMap();
+
+ @JsonAnyGetter
+ public SortedMap> getMap() {
+ return map;
+ }
+
+ /**
+ * Sets the metadata values for a given key.
+ *
+ * @param key the key.
+ * @param values the values. The values will be ordered according to their {@code place} value, if
+ * nonnegative. Values that are negative (the default is -1) are assume to be non-explicitly
+ * set and will will be ordered at the end of the list, after the last value with an order,
+ * in the order they are passed to this method.
+ * @return this instance, to support chaining calls for easy initialization.
+ */
+ public MetadataRest put(String key, MetadataValueRest... values) {
+ // determine highest explicitly ordered value
+ int highest = -1;
+ for (MetadataValueRest value : values) {
+ if (value.getPlace() > highest) {
+ highest = value.getPlace();
+ }
+ }
+ // add any non-explicitly ordered values after highest
+ for (MetadataValueRest value : values) {
+ if (value.getPlace() < 0) {
+ highest++;
+ value.setPlace(highest);
+ }
+ }
+ map.put(key, Arrays.asList(values));
+ return this;
+ }
+}
\ No newline at end of file
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 4dc7be11e9..768a81a4ff 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,8 +7,7 @@
*/
package org.dspace.app.rest.model;
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.annotation.JsonProperty.Access;
+import com.fasterxml.jackson.annotation.JsonIgnore;
/**
* An embeddable representation of the Metadata to use in with DSpace REST
@@ -26,8 +25,15 @@ public class MetadataValueRest {
int confidence;
- @JsonProperty(access = Access.READ_ONLY)
- int place;
+ @JsonIgnore
+ int place = -1;
+
+ public MetadataValueRest() {
+ }
+
+ public MetadataValueRest(String value) {
+ this.value = value;
+ }
public String getValue() {
return value;
@@ -68,5 +74,4 @@ public class MetadataValueRest {
public void setPlace(int place) {
this.place = place;
}
-
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 9f25e12d19..c00b7d3b07 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -23,14 +23,13 @@ import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.CollectionConverter;
+import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.CommunityRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
import org.dspace.app.rest.utils.CollectionRestEqualityUtils;
-import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -66,7 +65,7 @@ public class CollectionRestRepository extends DSpaceRestRepository metadataEntryRestList = collectionRest.getMetadata();
- collection = (Collection) dspaceObjectUtils.replaceMetadataValues(context,
- collection,
- metadataEntryRestList);
+ metadataConverter.setMetadata(context, collection, collectionRest.getMetadata());
} else {
throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
+ id + ", "
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
index 2e6834b3cf..67c1262e3b 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
@@ -19,18 +19,16 @@ import javax.ws.rs.BadRequestException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.CommunityConverter;
+import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CommunityRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.CommunityResource;
import org.dspace.app.rest.utils.CommunityRestEqualityUtils;
-import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.content.service.CommunityService;
@@ -60,7 +58,7 @@ public class CommunityRestRepository extends DSpaceRestRepository metadataEntryRestList = communityRest.getMetadata();
- community = (Community) dspaceObjectUtils.replaceMetadataValues(context, community, metadataEntryRestList);
+ metadataConverter.setMetadata(context, community, communityRest.getMetadata());
} else {
throw new UnprocessableEntityException("The given JSON and the original Community differ more " +
"than just the metadata");
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 5cf16f6031..6cda70eee3 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
@@ -25,6 +25,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.service.MetadataFieldService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
@@ -54,6 +55,9 @@ public abstract class DSpaceRestRepository thisRepository;
+ @Autowired
+ private MetadataFieldService metadataFieldService;
+
@Override
public S save(S entity) {
Context context = null;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
index 721e4c6313..37853dfb88 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
@@ -20,11 +20,11 @@ import org.apache.commons.lang3.StringUtils;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.EPersonConverter;
+import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.PatchBadRequestException;
import org.dspace.app.rest.exception.RESTAuthorizationException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.EPersonRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.EPersonResource;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.Patch;
@@ -60,6 +60,9 @@ public class EPersonRestRepository extends DSpaceRestRepository {
@Autowired
GroupConverter converter;
+ @Autowired
+ MetadataConverter metadataConverter;
+
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected GroupRest createAndReturn(Context context)
@@ -65,14 +68,7 @@ public class GroupRestRepository extends DSpaceRestRepository {
group = gs.create(context);
gs.setName(group, groupRest.getName());
gs.update(context, group);
-
- if (groupRest.getMetadata() != null) {
- for (MetadataEntryRest mer: groupRest.getMetadata()) {
- String[] metadatakey = mer.getKey().split("\\.");
- gs.addMetadata(context, group, metadatakey[0], metadatakey[1],
- metadatakey.length == 3 ? metadatakey[2] : null, mer.getLanguage(), mer.getValue());
- }
- }
+ metadataConverter.setMetadata(context, group, groupRest.getMetadata());
} catch (SQLException excSQL) {
throw new RuntimeException(excSQL.getMessage(), excSQL);
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
index 4b70b06ac6..44ab659fe1 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
@@ -22,16 +22,15 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.rest.converter.ItemConverter;
+import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.PatchBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.ItemRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
import org.dspace.app.rest.model.hateoas.ItemResource;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.ItemPatch;
-import org.dspace.app.rest.utils.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Item;
@@ -67,6 +66,9 @@ public class ItemRestRepository extends DSpaceRestRepository {
@Autowired
ItemConverter converter;
+ @Autowired
+ MetadataConverter metadataConverter;
+
@Autowired
ItemPatch itemPatch;
@@ -79,9 +81,6 @@ public class ItemRestRepository extends DSpaceRestRepository {
@Autowired
CollectionService collectionService;
- @Autowired
- DSpaceObjectUtils dspaceObjectUtils;
-
@Autowired
InstallItemService installItemService;
@@ -239,7 +238,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
item.setOwningCollection(collection);
item.setDiscoverable(itemRest.getDiscoverable());
item.setLastModified(itemRest.getLastModified());
- dspaceObjectUtils.replaceMetadataValues(context, item, itemRest.getMetadata());
+ metadataConverter.setMetadata(context, item, itemRest.getMetadata());
Item itemToReturn = installItemService.installItem(context, workspaceItem);
@@ -266,10 +265,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
}
if (StringUtils.equals(uuid.toString(), itemRest.getId())) {
- List metadataEntryRestList = itemRest.getMetadata();
- item = (Item) dspaceObjectUtils.replaceMetadataValues(context,
- item,
- metadataEntryRestList);
+ metadataConverter.setMetadata(context, item, itemRest.getMetadata());
} else {
throw new IllegalArgumentException("The UUID in the Json and the UUID in the url do not match: "
+ uuid + ", "
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectUtils.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectUtils.java
deleted file mode 100644
index eff3dcd657..0000000000
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/DSpaceObjectUtils.java
+++ /dev/null
@@ -1,62 +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.app.rest.utils;
-
-import java.sql.SQLException;
-import java.util.List;
-
-import org.dspace.app.rest.model.MetadataEntryRest;
-import org.dspace.authorize.AuthorizeException;
-import org.dspace.content.DSpaceObject;
-import org.dspace.content.Item;
-import org.dspace.content.factory.ContentServiceFactory;
-import org.dspace.content.service.DSpaceObjectService;
-import org.dspace.core.Context;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-/**
- * This class will be used as a Utils class to implement certain useful methods that can be reused by
- * multiple DSpaceObject instances
- */
-@Component
-public class DSpaceObjectUtils {
-
- @Autowired
- ContentServiceFactory contentServiceFactory;
-
- /**
- * This method will replace ALL MetadataValues from the given DSpaceObject with the MetadataValues passed along
- * in the metadataEntryRestList. These MetadataEntryRest objects will be analysed to use the MetadataValue key,
- * language and value to build a proper MetadataValue for the given DSpaceObject.
- * This will result in the DSpaceObject only containing MetadataValues that are represented in the given
- * metadataEntryRestList.
- * @param context The relevant DSpace context
- * @param dSpaceObject The DSpaceObject for which the MetadataValues will be cleared and filled up
- * with the MetadataValues created from the metadataEntryRestList
- * @param metadataEntryRestList The list of MetadataEntryRest objects that will be used to construct
- * MetadataValue objects for the given DSpaceObject
- * @return Returns the DSpaceObject
- * @throws SQLException If something goes wrong
- * @throws AuthorizeException If something goes wrong
- */
- public DSpaceObject replaceMetadataValues(Context context,
- DSpaceObject dSpaceObject,
- List metadataEntryRestList)
- throws SQLException, AuthorizeException {
- DSpaceObjectService dSpaceObjectService = contentServiceFactory.getDSpaceObjectService(dSpaceObject);
- dSpaceObjectService.clearMetadata(context, dSpaceObject, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
- for (MetadataEntryRest mer : metadataEntryRestList) {
- String[] metadatakey = mer.getKey().split("\\.");
- dSpaceObjectService.addMetadata(context, dSpaceObject, metadatakey[0], metadatakey[1],
- metadatakey.length == 3 ? metadatakey[2] : null, mer.getLanguage(), mer.getValue());
- }
- dSpaceObjectService.update(context, dSpaceObject);
- return dSpaceObject;
- }
-}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java
index beacc1b838..980604a8ae 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BrowsesResourceControllerIT.java
@@ -7,10 +7,10 @@
*/
package org.dspace.app.rest;
+import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@@ -31,6 +31,7 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.eperson.Group;
+import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
@@ -380,14 +381,10 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
"An embargoed publication",
"2017-08-10"))))
- //The private item must not be present
- .andExpect(jsonPath("$._embedded.items[*].metadata[?(@.key=='dc.title')].value",
- not(hasItem("This is a private item"))))
-
- //The internal item must not be present
- .andExpect(jsonPath("$._embedded.items[*].metadata[?(@.key=='dc.title')].value",
- not(hasItem("Internal publication"))))
- ;
+ //The private and internal items must not be present
+ .andExpect(jsonPath("$._embedded.items[*].metadata", Matchers.allOf(
+ not(matchMetadata("dc.title", "This is a private item")),
+ not(matchMetadata("dc.title", "Internal publication")))));
}
@Test
@@ -883,4 +880,4 @@ public class BrowsesResourceControllerIT extends AbstractControllerIntegrationTe
)));
}
-}
\ No newline at end of file
+}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index c34bcbd94a..7b160710d5 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -19,7 +19,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import java.util.Arrays;
import java.util.UUID;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -27,9 +26,10 @@ import org.dspace.app.rest.builder.CollectionBuilder;
import org.dspace.app.rest.builder.CommunityBuilder;
import org.dspace.app.rest.converter.CollectionConverter;
import org.dspace.app.rest.matcher.CollectionMatcher;
-import org.dspace.app.rest.matcher.CommunityMetadataMatcher;
+import org.dspace.app.rest.matcher.MetadataMatcher;
import org.dspace.app.rest.model.CollectionRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
@@ -358,11 +358,8 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
CollectionRest collectionRest = collectionConverter.fromModel(col1);
- MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
- metadataEntryRest.setKey("dc.title");
- metadataEntryRest.setValue("Electronic theses and dissertations");
-
- collectionRest.setMetadata(Arrays.asList(metadataEntryRest));
+ collectionRest.setMetadata(new MetadataRest()
+ .put("dc.title", new MetadataValueRest("Electronic theses and dissertations")));
getClient(token).perform(put("/api/core/collections/" + col1.getID().toString())
.contentType(MediaType.APPLICATION_JSON)
@@ -479,32 +476,18 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
CollectionRest collectionRest = new CollectionRest();
// We send a name but the created collection should set this to the title
collectionRest.setName("Collection");
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
-
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample top-level community created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- collectionRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ collectionRest.setMetadata(new MetadataRest()
+ .put("dc.description",
+ new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract",
+ new MetadataValueRest("Sample top-level community created via the REST API"))
+ .put("dc.description.tableofcontents",
+ new MetadataValueRest("HTML News
"))
+ .put("dc.rights",
+ new MetadataValueRest("Custom Copyright Text"))
+ .put("dc.title",
+ new MetadataValueRest("Title Text")));
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/collections")
@@ -519,18 +502,17 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", not(empty())),
hasJsonPath("$.type", is("collection")),
- hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
- CommunityMetadataMatcher.matchMetadata("dc.description",
- "Some cool HTML code here
"),
- CommunityMetadataMatcher.matchMetadata("dc.description.abstract",
- "Sample top-level community " +
- "created via the REST API"),
- CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents",
- "HTML News
"),
- CommunityMetadataMatcher.matchMetadata("dc.rights",
- "Custom Copyright Text"),
- CommunityMetadataMatcher.matchMetadata("dc.title",
- "Title Text")
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample top-level community created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
)))));
}
@@ -621,11 +603,8 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
CollectionRest collectionRest = collectionConverter.fromModel(col1);
- MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
- metadataEntryRest.setKey("dc.title");
- metadataEntryRest.setValue("Electronic theses and dissertations");
-
- collectionRest.setMetadata(Arrays.asList(metadataEntryRest));
+ collectionRest.setMetadata(new MetadataRest()
+ .put("dc.title", new MetadataValueRest("Electronic theses and dissertations")));
getClient(token).perform(put("/api/core/collections/" + col1.getID().toString())
.contentType(MediaType.APPLICATION_JSON)
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 ec55ab4faa..b5c7178d52 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
@@ -8,6 +8,7 @@
package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@@ -19,7 +20,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-import java.util.Arrays;
import java.util.UUID;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -28,9 +28,10 @@ import org.dspace.app.rest.builder.CollectionBuilder;
import org.dspace.app.rest.builder.CommunityBuilder;
import org.dspace.app.rest.converter.CommunityConverter;
import org.dspace.app.rest.matcher.CommunityMatcher;
-import org.dspace.app.rest.matcher.CommunityMetadataMatcher;
+import org.dspace.app.rest.matcher.MetadataMatcher;
import org.dspace.app.rest.model.CommunityRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
@@ -58,31 +59,29 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
// We send a name but the created community should set this to the title
comm.setName("Test Top-Level Community");
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
+ MetadataRest metadataRest = new MetadataRest();
+
+ MetadataValueRest description = new MetadataValueRest();
description.setValue("Some cool HTML code here
");
+ metadataRest.put("dc.description", description);
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
+ MetadataValueRest abs = new MetadataValueRest();
abs.setValue("Sample top-level community created via the REST API");
+ metadataRest.put("dc.description.abstract", abs);
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
+ MetadataValueRest contents = new MetadataValueRest();
contents.setValue("HTML News
");
+ metadataRest.put("dc.description.tableofcontents", contents);
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
+ MetadataValueRest copyright = new MetadataValueRest();
copyright.setValue("Custom Copyright Text");
+ metadataRest.put("dc.rights", copyright);
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
+ MetadataValueRest title = new MetadataValueRest();
title.setValue("Title Text");
+ metadataRest.put("dc.title", title);
- comm.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ comm.setMetadata(metadataRest);
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/communities")
@@ -100,19 +99,14 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
hasJsonPath("$._links.logo.href", not(empty())),
hasJsonPath("$._links.subcommunities.href", not(empty())),
hasJsonPath("$._links.self.href", not(empty())),
- hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
- CommunityMetadataMatcher.matchMetadata("dc.description",
- "Some cool HTML code here
"),
- CommunityMetadataMatcher.matchMetadata("dc.description.abstract",
- "Sample top-level community created via the REST API"),
- CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents",
- "HTML News
"),
- CommunityMetadataMatcher.matchMetadata("dc.rights",
- "Custom Copyright Text"),
- CommunityMetadataMatcher.matchMetadata("dc.title",
- "Title Text")
+ 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")
)))));
-
}
@Test
public void createWithParentTest() throws Exception {
@@ -130,31 +124,18 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
CommunityRest comm = new CommunityRest();
// We send a name but the created community should set this to the title
comm.setName("Test Sub-Level Community");
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample top-level community created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- comm.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ comm.setMetadata(new MetadataRest()
+ .put("dc.description",
+ new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract",
+ new MetadataValueRest("Sample top-level community created via the REST API"))
+ .put("dc.description.tableofcontents",
+ new MetadataValueRest("HTML News
"))
+ .put("dc.rights",
+ new MetadataValueRest("Custom Copyright Text"))
+ .put("dc.title",
+ new MetadataValueRest("Title Text")));
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/core/communities")
@@ -173,18 +154,17 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
hasJsonPath("$._links.logo.href", not(empty())),
hasJsonPath("$._links.subcommunities.href", not(empty())),
hasJsonPath("$._links.self.href", not(empty())),
- hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
- CommunityMetadataMatcher.matchMetadata("dc.description",
- "Some cool HTML code here
"),
- CommunityMetadataMatcher.matchMetadata("dc.description.abstract",
- "Sample top-level community " +
- "created via the REST API"),
- CommunityMetadataMatcher.matchMetadata("dc.description.tableofcontents",
- "HTML News
"),
- CommunityMetadataMatcher.matchMetadata("dc.rights",
- "Custom Copyright Text"),
- CommunityMetadataMatcher.matchMetadata("dc.title",
- "Title Text")
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample top-level community created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
)))));
@@ -200,11 +180,13 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
CommunityRest comm = new CommunityRest();
comm.setName("Test Top-Level Community");
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
+ MetadataRest metadataRest = new MetadataRest();
- comm.setMetadata(Arrays.asList(title));
+ MetadataValueRest title = new MetadataValueRest();
+ title.setValue("Title Text");
+ metadataRest.put("dc.title", title);
+
+ comm.setMetadata(metadataRest);
// Anonymous user tries to create a community.
// Should fail because user is not authenticated. Error 401.
@@ -638,12 +620,8 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
CommunityRest communityRest = communityConverter.fromModel(parentCommunity);
- MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
- metadataEntryRest.setKey("dc.title");
- metadataEntryRest.setValue("Electronic theses and dissertations");
-
- communityRest.setMetadata(Arrays.asList(metadataEntryRest));
-
+ communityRest.setMetadata(new MetadataRest()
+ .put("dc.title", new MetadataValueRest("Electronic theses and dissertations")));
getClient(token).perform(put("/api/core/communities/" + parentCommunity.getID().toString())
.contentType(MediaType.APPLICATION_JSON)
@@ -845,11 +823,8 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
CommunityRest communityRest = communityConverter.fromModel(parentCommunity);
- MetadataEntryRest metadataEntryRest = new MetadataEntryRest();
- metadataEntryRest.setKey("dc.title");
- metadataEntryRest.setValue("Electronic theses and dissertations");
-
- communityRest.setMetadata(Arrays.asList(metadataEntryRest));
+ communityRest.setMetadata(new MetadataRest()
+ .put("dc.title", new MetadataValueRest("Electronic theses and dissertations")));
context.setCurrentUser(eperson);
authorizeService.addPolicy(context, parentCommunity, Constants.WRITE, eperson);
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..82dc0e6a3b 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
@@ -8,6 +8,7 @@
package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@@ -21,7 +22,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import javax.ws.rs.core.MediaType;
@@ -32,9 +32,9 @@ 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.matcher.EPersonMatcher;
-import org.dspace.app.rest.matcher.EPersonMetadataMatcher;
import org.dspace.app.rest.model.EPersonRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
@@ -54,15 +54,16 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
// we should check how to get it from Spring
ObjectMapper mapper = new ObjectMapper();
EPersonRest data = new EPersonRest();
+ MetadataRest metadataRest = new MetadataRest();
data.setEmail("createtest@fake-email.com");
data.setCanLogIn(true);
- MetadataEntryRest surname = new MetadataEntryRest();
- surname.setKey("eperson.lastname");
+ MetadataValueRest surname = new MetadataValueRest();
surname.setValue("Doe");
- MetadataEntryRest firstname = new MetadataEntryRest();
- firstname.setKey("eperson.firstname");
+ metadataRest.put("eperson.lastname", surname);
+ MetadataValueRest firstname = new MetadataValueRest();
firstname.setValue("John");
- data.setMetadata(Arrays.asList(surname, firstname));
+ metadataRest.put("eperson.firstname", firstname);
+ data.setMetadata(metadataRest);
String authToken = getAuthToken(admin.getEmail(), password);
getClient(authToken).perform(post("/api/eperson/epersons")
@@ -79,9 +80,9 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
hasJsonPath("$.canLogIn", is(true)),
hasJsonPath("$.requireCertificate", is(false)),
hasJsonPath("$._links.self.href", not(empty())),
- hasJsonPath("$.metadata", Matchers.containsInAnyOrder(
- EPersonMetadataMatcher.matchFirstName("John"),
- EPersonMetadataMatcher.matchLastName("Doe")
+ hasJsonPath("$.metadata", Matchers.allOf(
+ matchMetadata("eperson.firstname", "John"),
+ matchMetadata("eperson.lastname", "Doe")
)))));
// TODO cleanup the context!!!
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index e0098d3453..872e09a655 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -8,7 +8,6 @@
package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
-import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -21,7 +20,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -38,8 +36,10 @@ import org.dspace.app.rest.builder.GroupBuilder;
import org.dspace.app.rest.builder.ItemBuilder;
import org.dspace.app.rest.builder.WorkspaceItemBuilder;
import org.dspace.app.rest.matcher.ItemMatcher;
+import org.dspace.app.rest.matcher.MetadataMatcher;
import org.dspace.app.rest.model.ItemRest;
-import org.dspace.app.rest.model.MetadataEntryRest;
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
@@ -1449,31 +1449,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
-
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample item created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- itemRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ itemRest.setMetadata(new MetadataRest()
+ .put("dc.description", new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract", new MetadataValueRest("Sample item created via the REST API"))
+ .put("dc.description.tableofcontents", new MetadataValueRest("HTML News
"))
+ .put("dc.rights", new MetadataValueRest("Custom Copyright Text"))
+ .put("dc.title", new MetadataValueRest("Title Text")));
String token = getAuthToken(admin.getEmail(), password);
MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
@@ -1496,18 +1477,18 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", is(itemHandleString)),
hasJsonPath("$.type", is("item")),
- hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
- contains("Title Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
- contains("Custom Copyright Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
- contains("HTML News
")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
- contains("Sample item created via the REST API")),
- hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
- contains("Some cool HTML code here
"))
-
- )));
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample item created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
+ )))));
}
@Test
@@ -1532,31 +1513,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
-
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample item created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- itemRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
String token = getAuthToken(admin.getEmail(), password);
MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
@@ -1571,18 +1527,15 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
String itemUuidString = String.valueOf(map.get("uuid"));
String itemHandleString = String.valueOf(map.get("handle"));
-
- title.setValue("New title");
- copyright.setValue("New Custom Copyright Text");
+ itemRest.setMetadata(new MetadataRest()
+ .put("dc.description", new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract", new MetadataValueRest("Sample item created via the REST API"))
+ .put("dc.description.tableofcontents", new MetadataValueRest("HTML News
"))
+ .put("dc.rights", new MetadataValueRest("New Custom Copyright Text"))
+ .put("dc.title", new MetadataValueRest("New title")));
itemRest.setUuid(itemUuidString);
itemRest.setHandle(itemHandleString);
- itemRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
- itemRest.setName("New title");
mvcResult = getClient(token).perform(put("/api/core/items/" + itemUuidString)
.content(mapper.writeValueAsBytes(itemRest))
@@ -1602,18 +1555,18 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
hasJsonPath("$.name", is("New title")),
hasJsonPath("$.handle", is(itemHandleString)),
hasJsonPath("$.type", is("item")),
- hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
- contains("New title")),
- hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
- contains("New Custom Copyright Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
- contains("HTML News
")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
- contains("Sample item created via the REST API")),
- hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
- contains("Some cool HTML code here
"))
-
- )));
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample item created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "New Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "New title")
+ )))));
}
@@ -1642,31 +1595,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
-
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample item created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- itemRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ itemRest.setMetadata(new MetadataRest()
+ .put("dc.description", new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract", new MetadataValueRest("Sample item created via the REST API"))
+ .put("dc.description.tableofcontents", new MetadataValueRest("HTML News
"))
+ .put("dc.rights", new MetadataValueRest("Custom Copyright Text"))
+ .put("dc.title", new MetadataValueRest("Title Text")));
String token = getAuthToken(admin.getEmail(), password);
MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
@@ -1690,18 +1624,18 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", is(itemHandleString)),
hasJsonPath("$.type", is("item")),
- hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
- contains("Title Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
- contains("Custom Copyright Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
- contains("HTML News
")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
- contains("Sample item created via the REST API")),
- hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
- contains("Some cool HTML code here
"))
-
- )));
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample item created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
+ )))));
getClient(token).perform(delete("/api/core/items/" + itemUuidString))
.andExpect(status().isNoContent());
@@ -1735,31 +1669,12 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
itemRest.setDiscoverable(true);
itemRest.setWithdrawn(false);
- MetadataEntryRest description = new MetadataEntryRest();
- description.setKey("dc.description");
- description.setValue("Some cool HTML code here
");
-
- MetadataEntryRest abs = new MetadataEntryRest();
- abs.setKey("dc.description.abstract");
- abs.setValue("Sample item created via the REST API");
-
- MetadataEntryRest contents = new MetadataEntryRest();
- contents.setKey("dc.description.tableofcontents");
- contents.setValue("HTML News
");
-
- MetadataEntryRest copyright = new MetadataEntryRest();
- copyright.setKey("dc.rights");
- copyright.setValue("Custom Copyright Text");
-
- MetadataEntryRest title = new MetadataEntryRest();
- title.setKey("dc.title");
- title.setValue("Title Text");
-
- itemRest.setMetadata(Arrays.asList(description,
- abs,
- contents,
- copyright,
- title));
+ itemRest.setMetadata(new MetadataRest()
+ .put("dc.description", new MetadataValueRest("Some cool HTML code here
"))
+ .put("dc.description.abstract", new MetadataValueRest("Sample item created via the REST API"))
+ .put("dc.description.tableofcontents", new MetadataValueRest("HTML News
"))
+ .put("dc.rights", new MetadataValueRest("Custom Copyright Text"))
+ .put("dc.title", new MetadataValueRest("Title Text")));
String token = getAuthToken(admin.getEmail(), password);
MvcResult mvcResult = getClient(token).perform(post("/api/core/items?owningCollection=" +
@@ -1783,18 +1698,18 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
hasJsonPath("$.name", is("Title Text")),
hasJsonPath("$.handle", is(itemHandleString)),
hasJsonPath("$.type", is("item")),
- hasJsonPath("$.metadata[?(@.key=='dc.title')].value",
- contains("Title Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.rights')].value",
- contains("Custom Copyright Text")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.tableofcontents')].value",
- contains("HTML News
")),
- hasJsonPath("$.metadata[?(@.key=='dc.description.abstract')].value",
- contains("Sample item created via the REST API")),
- hasJsonPath("$.metadata[?(@.key=='dc.description')].value",
- contains("Some cool HTML code here
"))
-
- )));
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.description",
+ "Some cool HTML code here
"),
+ MetadataMatcher.matchMetadata("dc.description.abstract",
+ "Sample item created via the REST API"),
+ MetadataMatcher.matchMetadata("dc.description.tableofcontents",
+ "HTML News
"),
+ MetadataMatcher.matchMetadata("dc.rights",
+ "Custom Copyright Text"),
+ MetadataMatcher.matchMetadata("dc.title",
+ "Title Text")
+ )))));
getClient().perform(delete("/api/core/items/" + itemUuidString))
.andExpect(status().isUnauthorized());
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java
index db9caa857c..9ff71928e5 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMatcher.java
@@ -8,8 +8,8 @@
package org.dspace.app.rest.matcher;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
@@ -30,9 +30,9 @@ public class BitstreamMatcher {
hasJsonPath("$.uuid", is(bitstream.getID().toString())),
hasJsonPath("$.name", is(bitstream.getName())),
hasJsonPath("$.bundleName", is("ORIGINAL")),
- hasJsonPath("$.metadata", containsInAnyOrder(
- BitstreamMetadataMatcher.matchTitle(bitstream.getName()),
- BitstreamMetadataMatcher.matchDescription(bitstream.getDescription())
+ hasJsonPath("$.metadata", allOf(
+ matchMetadata("dc.title", bitstream.getName()),
+ matchMetadata("dc.description", bitstream.getDescription())
)),
hasJsonPath("$.sizeBytes", is((int) bitstream.getSizeBytes())),
hasJsonPath("$.checkSum", matchChecksum()),
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java
deleted file mode 100644
index 1fba985560..0000000000
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/BitstreamMetadataMatcher.java
+++ /dev/null
@@ -1,33 +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.app.rest.matcher;
-
-import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.is;
-
-import org.hamcrest.Matcher;
-
-public class BitstreamMetadataMatcher {
-
- private BitstreamMetadataMatcher() { }
-
- public static Matcher super Object> matchTitle(String title) {
- return allOf(
- hasJsonPath("$.key", is("dc.title")),
- hasJsonPath("$.value", is(title))
- );
- }
-
- public static Matcher super Object> matchDescription(String description) {
- return allOf(
- hasJsonPath("$.key", is("dc.description")),
- hasJsonPath("$.value", is(description))
- );
- }
-}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
index 5381c62d93..8e8579c64c 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMatcher.java
@@ -32,8 +32,8 @@ public class CollectionMatcher {
hasJsonPath("$.name", is(name)),
hasJsonPath("$.handle", is(handle)),
hasJsonPath("$.type", is("collection")),
- hasJsonPath("$.metadata", Matchers.hasItem(
- CollectionMetadataMatcher.matchTitle(name)
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.title", name)
)),
matchLinks(uuid),
matchLogo(logo)
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java
deleted file mode 100644
index 3f5bbefe59..0000000000
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CollectionMetadataMatcher.java
+++ /dev/null
@@ -1,26 +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.app.rest.matcher;
-
-import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.Matchers.allOf;
-
-import org.hamcrest.Matcher;
-
-public class CollectionMetadataMatcher {
-
- private CollectionMetadataMatcher() { }
-
- public static Matcher super Object> matchTitle(String title) {
- return allOf(
- hasJsonPath("$.key", is("dc.title")),
- hasJsonPath("$.value", is(title))
- );
- }
-}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
index 600f67ab52..f1fffaa5c3 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMatcher.java
@@ -36,8 +36,8 @@ public class CommunityMatcher {
hasJsonPath("$.name", is(name)),
hasJsonPath("$.handle", is(handle)),
hasJsonPath("$.type", is("community")),
- hasJsonPath("$.metadata", Matchers.hasItem(
- CommunityMetadataMatcher.matchMetadata("dc.title", name)
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("dc.title", name)
))
);
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java
index 421af32dbe..819f1dccf6 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMatcher.java
@@ -29,9 +29,9 @@ public class EPersonMatcher {
hasJsonPath("$.type", is("eperson")),
hasJsonPath("$.canLogIn", not(empty())),
hasJsonPath("$._links.self.href", containsString("/api/eperson/epersons/" + ePerson.getID().toString())),
- hasJsonPath("$.metadata", Matchers.hasItems(
- EPersonMetadataMatcher.matchFirstName(ePerson.getFirstName()),
- EPersonMetadataMatcher.matchLastName(ePerson.getLastName())
+ hasJsonPath("$.metadata", Matchers.allOf(
+ MetadataMatcher.matchMetadata("eperson.firstname", ePerson.getFirstName()),
+ MetadataMatcher.matchMetadata("eperson.lastname", ePerson.getLastName())
))
);
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java
deleted file mode 100644
index 74ff800632..0000000000
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/EPersonMetadataMatcher.java
+++ /dev/null
@@ -1,40 +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.app.rest.matcher;
-
-import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.is;
-
-import org.hamcrest.Matcher;
-
-public class EPersonMetadataMatcher {
-
- private EPersonMetadataMatcher() { }
-
- public static Matcher super Object> matchFirstName(String firstName) {
- return allOf(
- hasJsonPath("$.key", is("eperson.firstname")),
- hasJsonPath("$.value", is(firstName))
- );
- }
-
- public static Matcher super Object> matchLastName(String lastName) {
- return allOf(
- hasJsonPath("$.key", is("eperson.lastname")),
- hasJsonPath("$.value", is(lastName))
- );
- }
-
- public static Matcher super Object> matchLanguage(String language) {
- return allOf(
- hasJsonPath("$.key", is("eperson.language")),
- hasJsonPath("$.value", is(language))
- );
- }
-}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
index e5176eea26..0f6eb553f4 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/ItemMatcher.java
@@ -8,9 +8,9 @@
package org.dspace.app.rest.matcher;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
+import static org.dspace.app.rest.matcher.MetadataMatcher.matchMetadata;
import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL;
import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.startsWith;
@@ -34,8 +34,9 @@ public class ItemMatcher {
matchItemProperties(item),
//Check core metadata (the JSON Path expression evaluates to a collection so we have to use contains)
- hasJsonPath("$.metadata[?(@.key=='dc.title')].value", contains(title)),
- hasJsonPath("$.metadata[?(@.key=='dc.date.issued')].value", contains(dateIssued)),
+ hasJsonPath("$.metadata", allOf(
+ matchMetadata("dc.title", title),
+ matchMetadata("dc.date.issued", dateIssued))),
//Check links
matchItemLinks(item)
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
similarity index 56%
rename from dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java
rename to dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
index ec251e86ea..73ed1381b9 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/CommunityMetadataMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
@@ -8,19 +8,20 @@
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.contains;
import static org.hamcrest.Matchers.is;
import org.hamcrest.Matcher;
-public class CommunityMetadataMatcher {
+public class MetadataMatcher {
- private CommunityMetadataMatcher() { }
+ private MetadataMatcher() { }
public static Matcher super Object> matchMetadata(String key, String value) {
- return allOf(
- hasJsonPath("$.key", is(key)),
- hasJsonPath("$.value", is(value))
- );
+ return hasJsonPath("$.['" + key + "'][*].value", contains(value));
+ }
+
+ public static Matcher super Object> matchMetadata(String key, String value, int position) {
+ return hasJsonPath("$.['" + key + "'][" + position + "].value", is(value));
}
}
From 0609a6f0b7321a36eb7225f16de4a6eaa55c03c9 Mon Sep 17 00:00:00 2001
From: Chris Wilper
Date: Thu, 7 Feb 2019 06:12:04 -0500
Subject: [PATCH 61/68] DS-4107 Improve javadocs
---
.../app/rest/converter/MetadataConverter.java | 15 ++++++++++---
.../converter/MetadataValueConverter.java | 21 +++++++++++++------
.../app/rest/model/DSpaceObjectRest.java | 5 +++++
.../dspace/app/rest/model/MetadataRest.java | 14 ++++++++++---
.../app/rest/model/MetadataValueRest.java | 13 ++++++++++++
.../app/rest/matcher/MetadataMatcher.java | 18 ++++++++++++++++
6 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
index ec1835bf07..51710f45af 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataConverter.java
@@ -29,6 +29,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
+/**
+ * Converter to translate between lists of domain {@link MetadataValue}s and {@link MetadataRest} representations.
+ */
@Component
public class MetadataConverter implements Converter, MetadataRest> {
@@ -38,6 +41,12 @@ public class MetadataConverter implements Converter, Metadat
@Autowired
private MetadataValueConverter valueConverter;
+ /**
+ * Gets a rest representation of the given list of domain metadata values.
+ *
+ * @param metadataValueList the domain values.
+ * @return the rest representation.
+ */
@Override
public MetadataRest convert(List metadataValueList) {
// Convert each value to a DTO while retaining place order in a map of key -> SortedSet
@@ -64,11 +73,11 @@ public class MetadataConverter implements Converter, Metadat
}
/**
- * Completely replaces the metadata in the given dso.
+ * Sets a DSpace object's domain metadata values from a rest representation.
*
* @param context the context to use.
- * @param dso the dso whose metadata should be updated.
- * @param metadataRest the new metadata.
+ * @param dso the DSpace object.
+ * @param metadataRest the rest representation of the new metadata.
* @throws SQLException if a database error occurs.
* @throws AuthorizeException if an authorization error occurs.
*/
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java
index 1dfe4ab12f..1095e1870a 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/MetadataValueConverter.java
@@ -12,17 +12,26 @@ import org.dspace.content.MetadataValue;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
+/**
+ * Converter to translate between domain {@link MetadataValue}s and {@link MetadataValueRest} representations.
+ */
@Component
public class MetadataValueConverter implements Converter {
+ /**
+ * Gets a rest representation of the given domain metadata value.
+ *
+ * @param metadataValue the domain value.
+ * @return the rest representation.
+ */
@Override
- public MetadataValueRest convert(MetadataValue model) {
+ public MetadataValueRest convert(MetadataValue metadataValue) {
MetadataValueRest metadataValueRest = new MetadataValueRest();
- metadataValueRest.setValue(model.getValue());
- metadataValueRest.setLanguage(model.getLanguage());
- metadataValueRest.setAuthority(model.getAuthority());
- metadataValueRest.setConfidence(model.getConfidence());
- metadataValueRest.setPlace(model.getPlace());
+ metadataValueRest.setValue(metadataValue.getValue());
+ metadataValueRest.setLanguage(metadataValue.getLanguage());
+ metadataValueRest.setAuthority(metadataValue.getAuthority());
+ metadataValueRest.setConfidence(metadataValue.getConfidence());
+ metadataValueRest.setPlace(metadataValue.getPlace());
return metadataValueRest;
}
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
index c0ef206aa1..1b71eb8957 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/DSpaceObjectRest.java
@@ -51,6 +51,11 @@ public abstract class DSpaceObjectRest extends BaseObjectRest {
this.handle = handle;
}
+ /**
+ * Gets the rest representation of all metadata of the DSpace object.
+ *
+ * @return the metadata.
+ */
public MetadataRest getMetadata() {
return metadata;
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
index 6225843d62..f1f5ec11ce 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
@@ -15,11 +15,19 @@ import java.util.TreeMap;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
+/**
+ * Rest representation of a map of metadata keys to ordered lists of values.
+ */
public class MetadataRest {
@JsonAnySetter
private SortedMap> map = new TreeMap();
+ /**
+ * Gets the map.
+ *
+ * @return the map of keys to ordered values.
+ */
@JsonAnyGetter
public SortedMap> getMap() {
return map;
@@ -30,9 +38,9 @@ public class MetadataRest {
*
* @param key the key.
* @param values the values. The values will be ordered according to their {@code place} value, if
- * nonnegative. Values that are negative (the default is -1) are assume to be non-explicitly
- * set and will will be ordered at the end of the list, after the last value with an order,
- * in the order they are passed to this method.
+ * nonnegative. Values that are negative (the default is -1) are assumed to be non-explicitly
+ * set and will will be ordered at the end of any explicitly ordered values, in the order
+ * they are passed to this method.
* @return this instance, to support chaining calls for easy initialization.
*/
public MetadataRest put(String key, MetadataValueRest... values) {
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 768a81a4ff..013e235847 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,7 +7,10 @@
*/
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
@@ -25,6 +28,16 @@ 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;
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
index 73ed1381b9..ed821d1f60 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/matcher/MetadataMatcher.java
@@ -13,14 +13,32 @@ import static org.hamcrest.Matchers.is;
import org.hamcrest.Matcher;
+/**
+ * Utility class to provide convenient matchers for metadata.
+ */
public class MetadataMatcher {
private MetadataMatcher() { }
+ /**
+ * Gets a matcher to ensure a given value is present among all values for a given metadata key.
+ *
+ * @param key the metadata key.
+ * @param value the value that must be present.
+ * @return the matcher.
+ */
public static Matcher super Object> matchMetadata(String key, String value) {
return hasJsonPath("$.['" + key + "'][*].value", contains(value));
}
+ /**
+ * Gets a matcher to ensure a given value is present at a specific position in the list of values for a given key.
+ *
+ * @param key the metadata key.
+ * @param value the value that must be present.
+ * @param position the position it must be present at.
+ * @return the matcher.
+ */
public static Matcher super Object> matchMetadata(String key, String value, int position) {
return hasJsonPath("$.['" + key + "'][" + position + "].value", is(value));
}
From 644970eba4adb6fb5793b94c182ce9ace64b437d Mon Sep 17 00:00:00 2001
From: Terry Brady
Date: Mon, 25 Feb 2019 08:38:18 -0800
Subject: [PATCH 62/68] set build dir owner to dspace
---
Dockerfile.jdk8 | 3 ++-
Dockerfile.jdk8-test | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/Dockerfile.jdk8 b/Dockerfile.jdk8
index ec465b50b3..afe2285f49 100644
--- a/Dockerfile.jdk8
+++ b/Dockerfile.jdk8
@@ -15,7 +15,8 @@ WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
- && chown -Rv dspace: /install
+ && chown -Rv dspace: /install \
+ && chown -Rv dspace: /app
USER dspace
diff --git a/Dockerfile.jdk8-test b/Dockerfile.jdk8-test
index e4f398d867..01697a045c 100644
--- a/Dockerfile.jdk8-test
+++ b/Dockerfile.jdk8-test
@@ -15,7 +15,8 @@ WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
- && chown -Rv dspace: /install
+ && chown -Rv dspace: /install \
+ && chown -Rv dspace: /app
USER dspace
From 1ad0c88c3c4da81e4534b644eb7b81214314be70 Mon Sep 17 00:00:00 2001
From: Chris Wilper
Date: Sat, 29 Dec 2018 15:22:00 -0500
Subject: [PATCH 63/68] DS-3908 Add PATCH support for DSO metadata
---
dspace-spring-rest/pom.xml | 6 ++
.../rest/converter/JsonPatchConverter.java | 3 +-
.../dspace/app/rest/model/MetadataRest.java | 5 ++
.../rest/model/patch/JsonValueEvaluator.java | 3 +
.../repository/BitstreamRestRepository.java | 29 ++++---
.../repository/CollectionRestRepository.java | 32 ++++---
.../repository/CommunityRestRepository.java | 32 ++++---
.../DSpaceObjectRestRepository.java | 70 ++++++++++++++++
.../repository/EPersonRestRepository.java | 65 +++++----------
.../rest/repository/GroupRestRepository.java | 23 +++--
.../rest/repository/ItemRestRepository.java | 83 +++++++------------
.../rest/repository/SiteRestRepository.java | 31 ++++---
.../patch/AbstractResourcePatch.java | 2 +-
.../repository/patch/DSpaceObjectPatch.java | 66 +++++++++++++++
.../rest/repository/patch/EPersonPatch.java | 2 +-
.../app/rest/repository/patch/ItemPatch.java | 2 +-
16 files changed, 304 insertions(+), 150 deletions(-)
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceObjectRestRepository.java
create mode 100644 dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/DSpaceObjectPatch.java
diff --git a/dspace-spring-rest/pom.xml b/dspace-spring-rest/pom.xml
index 3ea878747b..0e9e03f034 100644
--- a/dspace-spring-rest/pom.xml
+++ b/dspace-spring-rest/pom.xml
@@ -226,6 +226,12 @@
test
+
+ com.flipkart.zjsonpatch
+ zjsonpatch
+ 0.4.6
+
+
org.springframework.data
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/JsonPatchConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/JsonPatchConverter.java
index c9d387b591..aba4d6a995 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/JsonPatchConverter.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/JsonPatchConverter.java
@@ -116,7 +116,8 @@ public class JsonPatchConverter implements PatchConverter {
Object value = operation.getValue();
if (value != null) {
- opNode.set("value", mapper.valueToTree(value));
+ opNode.set("value", value instanceof JsonValueEvaluator ? ((JsonValueEvaluator) value).getValueNode()
+ : mapper.valueToTree(value));
}
patchNode.add(opNode);
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
index f1f5ec11ce..23474e793e 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/MetadataRest.java
@@ -61,4 +61,9 @@ public class MetadataRest {
map.put(key, Arrays.asList(values));
return this;
}
+
+ @Override
+ public boolean equals(Object object) {
+ return object instanceof MetadataRest && ((MetadataRest) object).getMap().equals(map);
+ }
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/patch/JsonValueEvaluator.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/patch/JsonValueEvaluator.java
index 596fa3049b..76802d9aa0 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/patch/JsonValueEvaluator.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/patch/JsonValueEvaluator.java
@@ -45,4 +45,7 @@ public class JsonValueEvaluator implements LateObjectEvaluator {
}
}
+ public JsonNode getValueNode() {
+ return this.valueNode;
+ }
}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
index 18233a3906..d1ce46a719 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
@@ -14,11 +14,14 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
+import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.BitstreamConverter;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
+import org.dspace.app.rest.model.patch.Patch;
+import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.service.BitstreamService;
@@ -39,16 +42,15 @@ import org.springframework.stereotype.Component;
*/
@Component(BitstreamRest.CATEGORY + "." + BitstreamRest.NAME)
-public class BitstreamRestRepository extends DSpaceRestRepository {
+public class BitstreamRestRepository extends DSpaceObjectRestRepository {
+
+ private final BitstreamService bs;
@Autowired
- BitstreamService bs;
-
- @Autowired
- BitstreamConverter converter;
-
- public BitstreamRestRepository() {
- System.out.println("Repository initialized by Spring");
+ public BitstreamRestRepository(BitstreamService dsoService,
+ BitstreamConverter dsoConverter) {
+ super(dsoService, dsoConverter, new DSpaceObjectPatch() { });
+ this.bs = dsoService;
}
@Override
@@ -70,7 +72,7 @@ public class BitstreamRestRepository extends DSpaceRestRepository page = new PageImpl(bit, pageable, total).map(converter);
+ Page page = new PageImpl(bit, pageable, total).map(dsoConverter);
return page;
}
+ @Override
+ @PreAuthorize("hasPermission(#id, 'BITSTREAM', 'WRITE')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
+ }
+
@Override
public Class getDomainClass() {
return BitstreamRest.class;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index c00b7d3b07..a7ba1a5552 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -12,7 +12,6 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
-
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.BadRequestException;
@@ -29,6 +28,8 @@ import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.hateoas.CollectionResource;
+import org.dspace.app.rest.model.patch.Patch;
+import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
import org.dspace.app.rest.utils.CollectionRestEqualityUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
@@ -53,14 +54,13 @@ import org.springframework.stereotype.Component;
*/
@Component(CollectionRest.CATEGORY + "." + CollectionRest.NAME)
-public class CollectionRestRepository extends DSpaceRestRepository {
+public class CollectionRestRepository extends DSpaceObjectRestRepository {
+
+ private final CollectionService cs;
@Autowired
CommunityService communityService;
- @Autowired
- CollectionService cs;
-
@Autowired
CollectionConverter converter;
@@ -71,8 +71,10 @@ public class CollectionRestRepository extends DSpaceRestRepository() {});
+ this.cs = dsoService;
}
@Override
@@ -87,7 +89,7 @@ public class CollectionRestRepository extends DSpaceRestRepository page = new PageImpl(collections, pageable, total).map(converter);
+ Page page = new PageImpl(collections, pageable, total).map(dsoConverter);
return page;
}
@@ -128,7 +130,7 @@ public class CollectionRestRepository extends DSpaceRestRepository page = utils.getPage(collections, pageable).map(converter);
+ Page page = utils.getPage(collections, pageable).map(dsoConverter);
return page;
}
@@ -145,10 +147,17 @@ public class CollectionRestRepository extends DSpaceRestRepository page = utils.getPage(collections, pageable).map(converter);
+ Page page = utils.getPage(collections, pageable).map(dsoConverter);
return page;
}
+ @Override
+ @PreAuthorize("hasPermission(#id, 'COLLECTION', 'WRITE')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
+ }
+
@Override
public Class getDomainClass() {
return CollectionRest.class;
@@ -252,5 +261,4 @@ public class CollectionRestRepository extends DSpaceRestRepository {
+public class CommunityRestRepository extends DSpaceObjectRestRepository {
- @Autowired
- CommunityService cs;
+ private final CommunityService cs;
@Autowired
CommunityConverter converter;
@@ -63,8 +63,10 @@ public class CommunityRestRepository extends DSpaceRestRepository() {});
+ this.cs = dsoService;
}
@Override
@@ -107,7 +109,7 @@ public class CommunityRestRepository extends DSpaceRestRepository page = new PageImpl(communities, pageable, total).map(converter);
+ Page page = new PageImpl(communities, pageable, total).map(dsoConverter);
return page;
}
@@ -153,7 +155,7 @@ public class CommunityRestRepository extends DSpaceRestRepository page = utils.getPage(topCommunities, pageable).map(converter);
+ Page page = utils.getPage(topCommunities, pageable).map(dsoConverter);
return page;
}
@@ -174,10 +176,17 @@ public class CommunityRestRepository extends DSpaceRestRepository page = utils.getPage(subCommunities, pageable).map(converter);
+ Page page = utils.getPage(subCommunities, pageable).map(dsoConverter);
return page;
}
+ @Override
+ @PreAuthorize("hasPermission(#id, 'COMMUNITY', 'WRITE')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
+ }
+
@Override
public Class getDomainClass() {
return CommunityRest.class;
@@ -233,5 +242,4 @@ public class CommunityRestRepository extends DSpaceRestRepository
+ extends DSpaceRestRepository {
+
+ final DSpaceObjectService dsoService;
+ final DSpaceObjectPatch dsoPatch;
+ final DSpaceObjectConverter dsoConverter;
+
+ @Autowired
+ MetadataConverter metadataConverter;
+
+ DSpaceObjectRestRepository(DSpaceObjectService dsoService,
+ DSpaceObjectConverter dsoConverter,
+ DSpaceObjectPatch dsoPatch) {
+ this.dsoService = dsoService;
+ this.dsoPatch = dsoPatch;
+ this.dsoConverter = dsoConverter;
+ }
+
+ protected void patchDSpaceObject(String apiCategory, String model, UUID id, Patch patch)
+ throws AuthorizeException, PatchBadRequestException, ResourceNotFoundException,
+ SQLException, UnprocessableEntityException {
+ M dso = dsoService.find(obtainContext(), id);
+ if (dso == null) {
+ throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found");
+ }
+ R dsoRest = dsoPatch.patch(findOne(id), patch.getOperations());
+ updateDSpaceObject(dso, dsoRest);
+ }
+
+ /**
+ * Applies the changes in the given rest DSpace object to the model DSpace object.
+ * The default implementation updates metadata if needed. Subclasses should extend
+ * to support updates of additional properties.
+ *
+ * @param dso the dso to apply changes to.
+ * @param dsoRest the rest representation of the new desired state.
+ */
+ protected void updateDSpaceObject(M dso, R dsoRest)
+ throws AuthorizeException, SQLException {
+ R origDsoRest = dsoConverter.fromModel(dso);
+ if (!origDsoRest.getMetadata().equals(dsoRest.getMetadata())) {
+ metadataConverter.setMetadata(obtainContext(), dso, dsoRest.getMetadata());
+ }
+ }
+}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
index 37853dfb88..f672e64077 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/EPersonRestRepository.java
@@ -12,7 +12,6 @@ import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
-
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -21,25 +20,21 @@ import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.converter.EPersonConverter;
import org.dspace.app.rest.converter.MetadataConverter;
-import org.dspace.app.rest.exception.PatchBadRequestException;
import org.dspace.app.rest.exception.RESTAuthorizationException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.EPersonRest;
import org.dspace.app.rest.model.hateoas.EPersonResource;
-import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.EPersonPatch;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
-import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
-import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -51,14 +46,12 @@ import org.springframework.stereotype.Component;
*/
@Component(EPersonRest.CATEGORY + "." + EPersonRest.NAME)
-public class EPersonRestRepository extends DSpaceRestRepository {
- EPersonService es = EPersonServiceFactory.getInstance().getEPersonService();
+public class EPersonRestRepository extends DSpaceObjectRestRepository {
@Autowired
AuthorizeService authorizeService;
- @Autowired
- EPersonConverter converter;
+ private final EPersonService es;
@Autowired
MetadataConverter metadataConverter;
@@ -66,6 +59,13 @@ public class EPersonRestRepository extends DSpaceRestRepository page = new PageImpl(epersons, pageable, total).map(converter);
+ Page page = new PageImpl(epersons, pageable, total).map(dsoConverter);
return page;
}
@@ -156,7 +156,7 @@ public class EPersonRestRepository extends DSpaceRestRepository page = new PageImpl(epersons, pageable, total).map(converter);
+ Page page = new PageImpl(epersons, pageable, total).map(dsoConverter);
return page;
}
@@ -182,42 +182,22 @@ public class EPersonRestRepository extends DSpaceRestRepository operations = patch.getOperations();
- EPersonRest ePersonRest = findOne(context, uuid);
- EPersonRest patchedModel = (EPersonRest) epersonPatch.patch(ePersonRest, operations);
- updatePatchedValues(context, patchedModel, eperson);
-
- } catch (SQLException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, uuid, patch);
}
- /**
- * Applies changes in the rest model.
- * @param context
- * @param ePersonRest the updated eperson rest
- * @param ePerson the eperson content object
- * @throws SQLException
- * @throws AuthorizeException
- */
- private void updatePatchedValues(Context context, EPersonRest ePersonRest, EPerson ePerson)
- throws SQLException, AuthorizeException {
+ @Override
+ protected void updateDSpaceObject(EPerson ePerson, EPersonRest ePersonRest)
+ throws AuthorizeException, SQLException {
+ super.updateDSpaceObject(ePerson, ePersonRest);
+ Context context = obtainContext();
if (ePersonRest.getPassword() != null) {
es.setPassword(ePerson, ePersonRest.getPassword());
}
@@ -232,7 +212,6 @@ public class EPersonRestRepository extends DSpaceRestRepository {
+public class GroupRestRepository extends DSpaceObjectRestRepository {
@Autowired
GroupService gs;
@Autowired
- GroupConverter converter;
+ GroupRestRepository(GroupService dsoService,
+ GroupConverter dsoConverter) {
+ super(dsoService, dsoConverter, new DSpaceObjectPatch() {});
+ this.gs = dsoService;
+ }
@Autowired
MetadataConverter metadataConverter;
@@ -73,7 +79,7 @@ public class GroupRestRepository extends DSpaceRestRepository {
throw new RuntimeException(excSQL.getMessage(), excSQL);
}
- return converter.convert(group);
+ return dsoConverter.convert(group);
}
@Override
@@ -88,7 +94,7 @@ public class GroupRestRepository extends DSpaceRestRepository {
if (group == null) {
return null;
}
- return converter.fromModel(group);
+ return dsoConverter.fromModel(group);
}
@PreAuthorize("hasAuthority('ADMIN')")
@@ -102,10 +108,17 @@ public class GroupRestRepository extends DSpaceRestRepository {
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
- Page page = new PageImpl(groups, pageable, total).map(converter);
+ Page page = new PageImpl(groups, pageable, total).map(dsoConverter);
return page;
}
+ @Override
+ @PreAuthorize("hasPermission(#id, 'GROUP', 'WRITE')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
+ }
+
@Override
public Class getDomainClass() {
return GroupRest.class;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
index 44ab659fe1..514c200333 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/ItemRestRepository.java
@@ -23,12 +23,10 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.rest.converter.ItemConverter;
import org.dspace.app.rest.converter.MetadataConverter;
-import org.dspace.app.rest.exception.PatchBadRequestException;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.hateoas.ItemResource;
-import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.Patch;
import org.dspace.app.rest.repository.patch.ItemPatch;
import org.dspace.authorize.AuthorizeException;
@@ -56,15 +54,11 @@ import org.springframework.stereotype.Component;
*/
@Component(ItemRest.CATEGORY + "." + ItemRest.NAME)
-public class ItemRestRepository extends DSpaceRestRepository {
+public class ItemRestRepository extends DSpaceObjectRestRepository- {
private static final Logger log = Logger.getLogger(ItemRestRepository.class);
- @Autowired
- ItemService is;
-
- @Autowired
- ItemConverter converter;
+ private final ItemService is;
@Autowired
MetadataConverter metadataConverter;
@@ -84,8 +78,11 @@ public class ItemRestRepository extends DSpaceRestRepository {
@Autowired
InstallItemService installItemService;
- public ItemRestRepository() {
- System.out.println("Repository initialized by Spring");
+ public ItemRestRepository(ItemService dsoService,
+ ItemConverter dsoConverter,
+ ItemPatch dsoPatch) {
+ super(dsoService, dsoConverter, dsoPatch);
+ this.is = dsoService;
}
@Override
@@ -100,7 +97,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
if (item == null) {
return null;
}
- return converter.fromModel(item);
+ return dsoConverter.fromModel(item);
}
@Override
@@ -119,55 +116,33 @@ public class ItemRestRepository extends DSpaceRestRepository {
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
- Page page = new PageImpl
- (items, pageable, total).map(converter);
+ Page page = new PageImpl
- (items, pageable, total).map(dsoConverter);
return page;
}
@Override
- public void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
- Patch patch)
- throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException,
- ResourceNotFoundException {
-
- Item item = is.find(context, uuid);
-
- if (item == null) {
- throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
- }
-
- List operations = patch.getOperations();
- ItemRest itemRest = findOne(uuid);
-
- ItemRest patchedModel = (ItemRest) itemPatch.patch(itemRest, operations);
- updatePatchedValues(context, patchedModel, item);
+ @PreAuthorize("hasPermission(#id, 'ITEM', 'WRITE')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
}
- /**
- * Persists changes to the rest model.
- * @param context
- * @param itemRest the updated item rest resource
- * @param item the item content object
- * @throws SQLException
- * @throws AuthorizeException
- */
- private void updatePatchedValues(Context context, ItemRest itemRest, Item item)
- throws SQLException, AuthorizeException {
+ @Override
+ protected void updateDSpaceObject(Item item, ItemRest itemRest)
+ throws AuthorizeException, SQLException {
+ super.updateDSpaceObject(item, itemRest);
- try {
- if (itemRest.getWithdrawn() != item.isWithdrawn()) {
- if (itemRest.getWithdrawn()) {
- is.withdraw(context, item);
- } else {
- is.reinstate(context, item);
- }
+ Context context = obtainContext();
+ if (itemRest.getWithdrawn() != item.isWithdrawn()) {
+ if (itemRest.getWithdrawn()) {
+ is.withdraw(context, item);
+ } else {
+ is.reinstate(context, item);
}
- if (itemRest.getDiscoverable() != item.isDiscoverable()) {
- item.setDiscoverable(itemRest.getDiscoverable());
- is.update(context, item);
- }
- } catch (SQLException | AuthorizeException e) {
- e.printStackTrace();
- throw e;
+ }
+ if (itemRest.getDiscoverable() != item.isDiscoverable()) {
+ item.setDiscoverable(itemRest.getDiscoverable());
+ is.update(context, item);
}
}
@@ -242,7 +217,7 @@ public class ItemRestRepository extends DSpaceRestRepository {
Item itemToReturn = installItemService.installItem(context, workspaceItem);
- return converter.fromModel(itemToReturn);
+ return dsoConverter.fromModel(itemToReturn);
}
@Override
@@ -271,6 +246,6 @@ public class ItemRestRepository extends DSpaceRestRepository {
+ uuid + ", "
+ itemRest.getId());
}
- return converter.fromModel(item);
+ return dsoConverter.fromModel(item);
}
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/SiteRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/SiteRestRepository.java
index 5586090c2e..e374df7fca 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/SiteRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/SiteRestRepository.java
@@ -11,10 +11,14 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.SiteConverter;
import org.dspace.app.rest.model.SiteRest;
import org.dspace.app.rest.model.hateoas.SiteResource;
+import org.dspace.app.rest.model.patch.Patch;
+import org.dspace.app.rest.repository.patch.DSpaceObjectPatch;
+import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Site;
import org.dspace.content.service.SiteService;
import org.dspace.core.Context;
@@ -22,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
@@ -31,16 +36,15 @@ import org.springframework.stereotype.Component;
*/
@Component(SiteRest.CATEGORY + "." + SiteRest.NAME)
-public class SiteRestRepository extends DSpaceRestRepository {
+public class SiteRestRepository extends DSpaceObjectRestRepository {
+
+ private final SiteService sitesv;
@Autowired
- SiteService sitesv;
-
- @Autowired
- SiteConverter converter;
-
-
- public SiteRestRepository() {
+ public SiteRestRepository(SiteService dsoService,
+ SiteConverter dsoConverter) {
+ super(dsoService, dsoConverter, new DSpaceObjectPatch() {});
+ this.sitesv = dsoService;
}
@Override
@@ -54,7 +58,7 @@ public class SiteRestRepository extends DSpaceRestRepository {
if (site == null) {
return null;
}
- return converter.fromModel(site);
+ return dsoConverter.fromModel(site);
}
@Override
@@ -66,10 +70,17 @@ public class SiteRestRepository extends DSpaceRestRepository {
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
- Page page = new PageImpl(sites, pageable, total).map(converter);
+ Page page = new PageImpl(sites, pageable, total).map(dsoConverter);
return page;
}
+ @Override
+ @PreAuthorize("hasAuthority('ADMIN')")
+ protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID id,
+ Patch patch) throws AuthorizeException, SQLException {
+ patchDSpaceObject(apiCategory, model, id, patch);
+ }
+
@Override
public Class getDomainClass() {
return SiteRest.class;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/AbstractResourcePatch.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/AbstractResourcePatch.java
index 4033718941..547e33842d 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/AbstractResourcePatch.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/AbstractResourcePatch.java
@@ -30,7 +30,7 @@ public abstract class AbstractResourcePatch {
* @throws UnprocessableEntityException
* @throws PatchBadRequestException
*/
- public RestModel patch(R restModel, List operations) {
+ public R patch(R restModel, List operations) {
// Note: the list of possible operations is taken from JsonPatchConverter class. Does not implement
// test https://tools.ietf.org/html/rfc6902#section-4.6
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/DSpaceObjectPatch.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/DSpaceObjectPatch.java
new file mode 100644
index 0000000000..568b3abaf8
--- /dev/null
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/DSpaceObjectPatch.java
@@ -0,0 +1,66 @@
+/**
+ * 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.patch;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.flipkart.zjsonpatch.JsonPatch;
+import org.dspace.app.rest.converter.JsonPatchConverter;
+import org.dspace.app.rest.model.DSpaceObjectRest;
+import org.dspace.app.rest.model.MetadataRest;
+import org.dspace.app.rest.model.patch.Operation;
+import org.dspace.app.rest.model.patch.Patch;
+
+public abstract class DSpaceObjectPatch extends AbstractResourcePatch {
+
+ private static final String METADATA_PATH = "/metadata";
+
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ private JsonPatchConverter jsonPatchConverter = new JsonPatchConverter(objectMapper);
+
+ @Override
+ public R patch(R dsoRest, List operations) {
+ List metadataOperations = new ArrayList<>();
+ List otherOperations = new ArrayList<>();
+
+ for (Operation operation : operations) {
+ String path = operation.getPath();
+ if (path.equals(METADATA_PATH) || path.startsWith(METADATA_PATH + "/")) {
+ metadataOperations.add(operation);
+ } else {
+ otherOperations.add(operation);
+ }
+ }
+
+ if (!metadataOperations.isEmpty()) {
+ dsoRest.setMetadata(applyMetadataPatch(
+ jsonPatchConverter.convert(new Patch(metadataOperations)),
+ dsoRest.getMetadata()));
+ }
+
+ return super.patch(dsoRest, otherOperations);
+ }
+
+ private MetadataRest applyMetadataPatch(JsonNode patch, MetadataRest metadataRest) {
+ try {
+ ObjectNode objectNode = objectMapper.createObjectNode();
+ JsonNode metadataNode = objectMapper.valueToTree(metadataRest);
+ objectNode.replace("metadata", metadataNode);
+ JsonPatch.applyInPlace(patch, objectNode);
+ return objectMapper.treeToValue(objectNode.get("metadata"), MetadataRest.class);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+}
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/EPersonPatch.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/EPersonPatch.java
index 2204c98cc8..bb9ce69090 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/EPersonPatch.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/EPersonPatch.java
@@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
* Provides patch operations for eperson updates.
*/
@Component
-public class EPersonPatch extends AbstractResourcePatch {
+public class EPersonPatch extends DSpaceObjectPatch {
@Autowired
EPersonOperationFactory patchFactory;
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/ItemPatch.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/ItemPatch.java
index d68edbf444..b34a62d1ea 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/ItemPatch.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/patch/ItemPatch.java
@@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
* Provides PATCH operations for item updates.
*/
@Component
-public class ItemPatch extends AbstractResourcePatch {
+public class ItemPatch extends DSpaceObjectPatch {
@Autowired
ItemOperationFactory patchFactory;
From 185766d8d242a9b855005e33bcc1f32e0d0f2206 Mon Sep 17 00:00:00 2001
From: Chris Wilper
Date: Sat, 29 Dec 2018 15:22:47 -0500
Subject: [PATCH 64/68] DS-3908 Add DSO metadata PATCH tests
---
.../app/rest/BitstreamRestRepositoryIT.java | 22 +++
.../app/rest/CollectionRestRepositoryIT.java | 20 +++
.../app/rest/CommunityRestRepositoryIT.java | 19 +++
.../app/rest/EPersonRestRepositoryIT.java | 19 +++
.../app/rest/GroupRestRepositoryIT.java | 20 +++
.../dspace/app/rest/ItemRestRepositoryIT.java | 22 ++-
.../dspace/app/rest/SiteRestRepositoryIT.java | 21 +++
.../app/rest/test/MetadataPatchSuite.java | 64 ++++++++
.../app/rest/test/metadata-patch-suite.json | 152 ++++++++++++++++++
9 files changed, 358 insertions(+), 1 deletion(-)
create mode 100644 dspace-spring-rest/src/test/java/org/dspace/app/rest/test/MetadataPatchSuite.java
create mode 100644 dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
index 49cc5f2bdd..fad2be9f78 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
@@ -27,11 +27,13 @@ import org.dspace.app.rest.builder.ItemBuilder;
import org.dspace.app.rest.matcher.BitstreamFormatMatcher;
import org.dspace.app.rest.matcher.BitstreamMatcher;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.app.rest.test.MetadataPatchSuite;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.service.BitstreamService;
+import org.dspace.eperson.EPerson;
import org.hamcrest.Matchers;
import org.junit.Ignore;
import org.junit.Test;
@@ -587,4 +589,24 @@ public class BitstreamRestRepositoryIT extends AbstractControllerIntegrationTest
getClient(token).perform(delete("/api/core/bitstreams/" + col.getLogo().getID()))
.andExpect(status().is(422));
}
+
+ @Test
+ public void patchBitstreamMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchBitstreamMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").withLogo("logo_community")
+ .build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/core/bitstreams/"
+ + parentCommunity.getLogo().getID(), expectedStatus);
+ }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index 7b160710d5..94d9e0d463 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -31,10 +31,12 @@ import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.MetadataRest;
import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+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.core.Constants;
+import org.dspace.eperson.EPerson;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -624,6 +626,24 @@ public class CollectionRestRepositoryIT extends AbstractControllerIntegrationTes
;
authorizeService.removePoliciesActionFilter(context, eperson, Constants.WRITE);
+ }
+ public void patchCollectionMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchCollectionMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").build();
+ Collection col = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection").build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/core/collections/"
+ + col.getID(), expectedStatus);
}
}
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 b5c7178d52..17c3e49145 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
@@ -33,10 +33,12 @@ import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.model.MetadataRest;
import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+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.core.Constants;
+import org.dspace.eperson.EPerson;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -852,4 +854,21 @@ public class CommunityRestRepositoryIT extends AbstractControllerIntegrationTest
}
+ public void patchCommunityMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchCommunityMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ parentCommunity = CommunityBuilder.createCommunity(context).withName("Community").build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/core/communities/"
+ + parentCommunity.getID(), expectedStatus);
+ }
}
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 82dc0e6a3b..3f48a031cc 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
@@ -38,6 +38,7 @@ import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.app.rest.test.MetadataPatchSuite;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.eperson.EPerson;
@@ -1032,4 +1033,22 @@ public class EPersonRestRepositoryIT extends AbstractControllerIntegrationTest {
}
+ @Test
+ public void patchEPersonMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchEPersonMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ EPerson ePerson = EPersonBuilder.createEPerson(context).withEmail("user@test.com").build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/eperson/epersons/" + ePerson.getID(), expectedStatus);
+ }
+
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java
index b75c9cf7bb..c057c11c72 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/GroupRestRepositoryIT.java
@@ -22,6 +22,8 @@ import org.dspace.app.rest.builder.GroupBuilder;
import org.dspace.app.rest.matcher.GroupMatcher;
import org.dspace.app.rest.model.GroupRest;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.app.rest.test.MetadataPatchSuite;
+import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.hamcrest.Matchers;
import org.junit.Test;
@@ -234,4 +236,22 @@ public class GroupRestRepositoryIT extends AbstractControllerIntegrationTest {
;
}
+ @Test
+ public void patchGroupMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchGroupMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ Group group = GroupBuilder.createGroup(context).withName("Group").build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/eperson/groups/"
+ + group.getID(), expectedStatus);
+ }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
index 872e09a655..0743d3cd79 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/ItemRestRepositoryIT.java
@@ -43,6 +43,7 @@ import org.dspace.app.rest.model.MetadataValueRest;
import org.dspace.app.rest.model.patch.Operation;
import org.dspace.app.rest.model.patch.ReplaceOperation;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.app.rest.test.MetadataPatchSuite;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -919,7 +920,6 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
}
-
@Test
public void useStringForBooleanTest() throws Exception {
context.turnOffAuthorisationSystem();
@@ -1744,7 +1744,27 @@ public class ItemRestRepositoryIT extends AbstractControllerIntegrationTest {
//Delete public item
getClient(token).perform(delete("/api/core/items/" + parentCommunity.getID()))
.andExpect(status().is(404));
+ }
+ public void patchItemMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchItemMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) 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();
+ Item item = ItemBuilder.createItem(context, col1).build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/core/items/" + item.getID(), expectedStatus);
}
}
\ No newline at end of file
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java
index 33ada54c97..6d9f9980b3 100644
--- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/SiteRestRepositoryIT.java
@@ -17,7 +17,9 @@ import java.util.UUID;
import org.dspace.app.rest.builder.SiteBuilder;
import org.dspace.app.rest.matcher.SiteMatcher;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.dspace.app.rest.test.MetadataPatchSuite;
import org.dspace.content.Site;
+import org.dspace.eperson.EPerson;
import org.hamcrest.Matchers;
import org.junit.Test;
@@ -67,4 +69,23 @@ public class SiteRestRepositoryIT extends AbstractControllerIntegrationTest {
.andExpect(status().isNotFound());
}
+
+ @Test
+ public void patchSiteMetadataAuthorized() throws Exception {
+ runPatchMetadataTests(admin, 200);
+ }
+
+ @Test
+ public void patchSiteMetadataUnauthorized() throws Exception {
+ runPatchMetadataTests(eperson, 403);
+ }
+
+ private void runPatchMetadataTests(EPerson asUser, int expectedStatus) throws Exception {
+ context.turnOffAuthorisationSystem();
+ Site site = SiteBuilder.createSite(context).build();
+ String token = getAuthToken(asUser.getEmail(), password);
+
+ new MetadataPatchSuite().runWith(getClient(token), "/api/core/sites/" + site.getID(), expectedStatus);
+
+ }
}
diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/MetadataPatchSuite.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/MetadataPatchSuite.java
new file mode 100644
index 0000000000..db1a9193c6
--- /dev/null
+++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/test/MetadataPatchSuite.java
@@ -0,0 +1,64 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.test;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import javax.ws.rs.core.MediaType;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Assert;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
+
+public class MetadataPatchSuite {
+ private final ObjectMapper objectMapper = new ObjectMapper();
+ private final JsonNode suite;
+
+ public MetadataPatchSuite() throws Exception {
+ suite = objectMapper.readTree(getClass().getResourceAsStream("metadata-patch-suite.json"));
+ }
+
+ public void runWith(MockMvc client, String url, int expectedStatus) {
+ for (JsonNode testNode: suite.get("tests")) {
+ String requestBody = testNode.get("patch").toString();
+ String expectedMetadata = testNode.get("expect").toString();
+ try {
+ System.out.println("Running patch test: " + testNode.get("name") + "\nRequest: " + requestBody);
+ checkResponse("PATCH", client, patch(url).content(requestBody), expectedMetadata, expectedStatus);
+ if (expectedStatus >= 200 && expectedStatus < 300) {
+ checkResponse("GET", client, get(url), expectedMetadata, expectedStatus);
+ }
+ } catch (Throwable t) {
+ Assert.fail("Metadata patch test '" + testNode.get("name") + "' failed.\n" + "Request body: "
+ + requestBody + "\n" + "Error: " + (t instanceof AssertionError ? "" : t.getClass().getName())
+ + t.getMessage());
+ }
+ }
+ }
+
+ private void checkResponse(String verb, MockMvc client, MockHttpServletRequestBuilder requestBuilder,
+ String expectedMetadata, int expectedStatus) throws Exception {
+ ResultActions resultActions = client.perform(requestBuilder
+ .contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
+ .andExpect(status().is(expectedStatus));
+ if (expectedStatus >= 200 && expectedStatus < 300) {
+ String responseBody = resultActions.andReturn().getResponse().getContentAsString();
+ JsonNode responseJson = objectMapper.readTree(responseBody);
+ String responseMetadata = responseJson.get("metadata").toString();
+ if (!responseMetadata.equals(expectedMetadata)) {
+ Assert.fail("Expected metadata in " + verb + " response: " + expectedMetadata
+ + "\nGot metadata in " + verb + " response: " + responseMetadata);
+ }
+ }
+ }
+}
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
new file mode 100644
index 0000000000..cff452fe91
--- /dev/null
+++ b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/test/metadata-patch-suite.json
@@ -0,0 +1,152 @@
+{
+ "tests": [
+ {
+ "name": "clear metadata",
+ "patch": [
+ { "op": "replace",
+ "path": "/metadata",
+ "value": {}
+ }
+ ],
+ "expect": {}
+ },
+ {
+ "name": "add first title",
+ "patch": [
+ {
+ "op": "add",
+ "path": "/metadata/dc.title",
+ "value": [
+ { "value": "title 1" }
+ ]
+ }
+ ],
+ "expect": {
+ "dc.title": [
+ { "value": "title 1", "language": null, "authority": null, "confidence": -1 }
+ ]
+ }
+ },
+ {
+ "name": "add second title",
+ "patch": [
+ {
+ "op": "add",
+ "path": "/metadata/dc.title/-",
+ "value": { "value": "最後のタイトル", "language": "ja_JP" }
+ }
+ ],
+ "expect": {
+ "dc.title": [
+ { "value": "title 1", "language": null, "authority": null, "confidence": -1 },
+ { "value": "最後のタイトル", "language": "ja_JP", "authority": null, "confidence": -1 }
+ ]
+ }
+ },
+ {
+ "name": "insert zeroth title",
+ "patch": [
+ {
+ "op": "add",
+ "path": "/metadata/dc.title/0",
+ "value": {
+ "value": "title 0"
+ }
+ }
+ ],
+ "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 }
+ ]
+ }
+ },
+ {
+ "name": "move last title up one",
+ "patch": [
+ {
+ "op": "move",
+ "from": "/metadata/dc.title/2",
+ "path": "/metadata/dc.title/1"
+ }
+ ],
+ "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 }
+ ]
+ }
+ },
+ {
+ "name": "replace title 2 value and language in two operations",
+ "patch": [
+ {
+ "op": "replace",
+ "path": "/metadata/dc.title/1/value",
+ "value": "title A"
+ },
+ {
+ "op": "replace",
+ "path": "/metadata/dc.title/1/language",
+ "value": "en_US"
+ }
+ ],
+ "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 }
+ ]
+ }
+ },
+ {
+ "name": "copy title A to end of list",
+ "patch": [
+ {
+ "op": "copy",
+ "from": "/metadata/dc.title/1",
+ "path": "/metadata/dc.title/-"
+ }
+ ],
+ "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 }
+ ]
+ }
+ },
+ {
+ "name": "remove both title A copies",
+ "patch": [
+ {
+ "op": "remove",
+ "path": "/metadata/dc.title/1"
+ },
+ {
+ "op": "remove",
+ "path": "/metadata/dc.title/2"
+ }
+ ],
+ "expect": {
+ "dc.title": [
+ { "value": "title 0", "language": null, "authority": null, "confidence": -1 },
+ { "value": "title 1", "language": null, "authority": null, "confidence": -1 }
+ ]
+ }
+ },
+ {
+ "name": "remove all titles",
+ "patch": [
+ {
+ "op": "remove",
+ "path": "/metadata/dc.title"
+ }
+ ],
+ "expect": {}
+ }
+ ]
+}
From 96d544d0755b6b93b051ba5ba3e17f704b9ec793 Mon Sep 17 00:00:00 2001
From: Chris Wilper
Date: Thu, 7 Mar 2019 09:54:24 -0500
Subject: [PATCH 65/68] DS-3908 Improve javadocs
---
.../DSpaceObjectRestRepository.java | 21 +++++++++++++--
.../repository/patch/DSpaceObjectPatch.java | 15 +++++++++++
.../app/rest/test/MetadataPatchSuite.java | 26 +++++++++++++++++++
3 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceObjectRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceObjectRestRepository.java
index faba78c578..fabebc70d2 100644
--- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceObjectRestRepository.java
+++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceObjectRestRepository.java
@@ -23,6 +23,12 @@ import org.dspace.content.service.DSpaceObjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+/**
+ * Base class for DSpaceObject-based Rest Repositories, providing common functionality.
+ *
+ * @param the specific type of DSpaceObject.
+ * @param the corresponding DSpaceObjectRest.
+ */
public abstract class DSpaceObjectRestRepository
extends DSpaceRestRepository {
@@ -41,9 +47,20 @@ public abstract class DSpaceObjectRestRepository the type of DSpaceObjectRest object the class is applicable to.
+ */
public abstract class DSpaceObjectPatch extends AbstractResourcePatch {
private static final String METADATA_PATH = "/metadata";
@@ -29,6 +34,16 @@ public abstract class DSpaceObjectPatch