Merge pull request #8357 from 4Science/main-duracom-70

Add compatibility for DSpace 7 with the Remote Handle Resolver
This commit is contained in:
Tim Donohue
2022-10-04 14:48:07 -05:00
committed by GitHub
11 changed files with 812 additions and 9 deletions

View File

@@ -405,7 +405,7 @@ public class HandleServiceImpl implements HandleService {
}
// Check additional prefixes supported in the config file
String[] additionalPrefixes = configurationService.getArrayProperty("handle.additional.prefixes");
String[] additionalPrefixes = getAdditionalPrefixes();
for (String additionalPrefix : additionalPrefixes) {
if (identifier.startsWith(additionalPrefix + "/")) {
// prefix is the equivalent of 123456789 in 123456789/???; don't strip
@@ -415,4 +415,9 @@ public class HandleServiceImpl implements HandleService {
return null;
}
@Override
public String[] getAdditionalPrefixes() {
return configurationService.getArrayProperty("handle.additional.prefixes");
}
}

View File

@@ -0,0 +1,87 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.handle.hdlresolver;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Objects;
import org.apache.commons.lang3.Validate;
import org.dspace.core.Constants;
/**
* Maps the URL of the request to an handle identifier
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.it)
*
*/
public class HdlResolverDTO {
private final String[] splittedString;
private final String handle;
/**
* Decode a given URL
* @param url URL
* @return decoded URL
*/
private static String decode(String url) {
try {
return URLDecoder.decode(url, Constants.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
return url;
}
}
/**
* Default Constructor
*
* @param requestURL is the complete Request URL
* @param resolverSubPath is the rest service Sub-path
*/
public HdlResolverDTO(final String requestURL, final String resolverSubPath) {
Validate.notBlank(requestURL, "RequestURI not specified");
Validate.notBlank(resolverSubPath, "fullPath not specified");
this.splittedString = requestURL.split(resolverSubPath);
if (Objects.nonNull(splittedString) && splittedString.length > 1) {
// Decodes the URL-encoded characters of the String
this.handle = decode(splittedString[1]);
} else {
this.handle = null;
}
}
/**
* Returns the splitted String of the resource-path
*
* @return
*/
public final String[] getSplittedString() {
return this.splittedString;
}
/**
* Returns the handle identifier
*
* @return
*/
public final String getHandle() {
return this.handle;
}
/**
* Checks if the handle identifier is valid.
*
* @return
*/
public boolean isValid() {
return Objects.nonNull(this.handle) &&
!"null".equalsIgnoreCase(this.handle) &&
!this.handle.trim().isEmpty();
}
}

View File

@@ -0,0 +1,69 @@
/**
* 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.handle.hdlresolver;
import java.util.List;
import org.dspace.core.Context;
/**
* Service used to for utilities involving {@code HdlResolverDTO} and its
* resolution to handle URI and vice-versa.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.it)
*
*/
/**
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
*
*/
public interface HdlResolverService {
/**
* Method that creates an <code>HdlResovlerDTO</code> using the requestURI (full
* requested handle URI) and the path (REST handler URI)
*
* @param requestURI
* @param path
* @return <code>HdlResolverDTO</code>
*/
HdlResolverDTO resolveBy(String requestURI, String path);
/**
* Converts the hdlResovler into URL fetching it from repository using the DSpace context
*
* @param context
* @param hdlResolver
* @return URL found or null
*/
String resolveToURL(Context context, HdlResolverDTO hdlResolver);
/**
* List all available prefixes for this installation
*
* @return `List<String>` of Handle prefixes
*/
List<String> listPrefixes();
/**
* List all available handles with `prefix`
*
* @param context DSpace context
* @param prefix prefix to search
* @return `List<String>` of handles
*/
List<String> listHandles(Context context, String prefix);
/**
* Verifies status of handle controller
*
* @return `true` if enabled, `false` otherwise
*/
boolean isListhandlesEnabled();
}

View File

@@ -0,0 +1,87 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.handle.hdlresolver;
import java.sql.SQLException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.core.Context;
import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*
* Handle Resolver that uses an <code>HandleService</code> to retrieve the right
* URL of a target Handle.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.it)
*
*/
@Service
public class HdlResolverServiceImpl implements HdlResolverService {
public static final String LISTHANDLES_HIDE_PROP = "handle.hide.listhandles";
private static final Logger log = LogManager.getLogger();
@Autowired(required = true)
private HandleService handleService;
@Autowired(required = true)
private ConfigurationService configurationService;
@Override
public HdlResolverDTO resolveBy(String requestURI, String path) {
return new HdlResolverDTO(requestURI, path);
}
@Override
public String resolveToURL(Context context, HdlResolverDTO hdlResolver) {
try {
return this.handleService.resolveToURL(context, hdlResolver.getHandle());
} catch (SQLException e) {
log.error("Error while resolving Handle: " + hdlResolver.getHandle(), e);
throw new RuntimeException("Error while resolving Handle: " + hdlResolver.getHandle(), e);
}
}
@Override
public List<String> listPrefixes() {
return Stream.concat(
Stream.of(this.handleService.getAdditionalPrefixes()),
Stream.of(this.handleService.getPrefix())
)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toList());
}
@Override
public List<String> listHandles(Context context, String prefix) {
List<String> handlesForPrefix = List.of();
try {
handlesForPrefix = this.handleService.getHandlesForPrefix(context, prefix);
} catch (SQLException e) {
log.error("Error while listing handles for prefix: " + prefix, e);
throw new RuntimeException("Error while listing handles for prefix: " + prefix, e);
}
return handlesForPrefix;
}
@Override
public boolean isListhandlesEnabled() {
return !this.configurationService.getBooleanProperty(LISTHANDLES_HIDE_PROP);
}
}

View File

@@ -101,16 +101,18 @@ public interface HandleService {
throws SQLException, IllegalStateException;
/**
* Creates a handle entry, but with a handle supplied by the caller (new
* Handle not generated)
* Creates a handle entry, but with a handle supplied by the caller (new Handle
* not generated)
*
* @param context DSpace context
* @param dso DSpaceObject
* @param suppliedHandle existing handle value
* @param force FIXME: currently unused
* @return the Handle
* @throws SQLException An exception that provides information on a database access error or other errors.
* @throws IllegalStateException if specified handle is already in use by another object
* @throws SQLException An exception that provides information on a
* database access error or other errors.
* @throws IllegalStateException if specified handle is already in use by
* another object
*/
public String createHandle(Context context, DSpaceObject dso, String suppliedHandle, boolean force)
throws SQLException, IllegalStateException;
@@ -190,4 +192,12 @@ public interface HandleService {
* @return
*/
String parseHandle(String identifier);
/**
* Gets the additional prefixes used for handles,
* mapped in configuration file.
*
* @return `String[]` array of prefixes
*/
String[] getAdditionalPrefixes();
}

View File

@@ -70,6 +70,17 @@ mail.server.disabled = true
# (Defaults to a dummy/fake prefix of 123456789)
handle.prefix = 123456789
# Whether to enable the DSpace handle resolver endpoints necessary for
# https://github.com/DSpace/Remote-Handle-Resolver
# Defaults to "false" which means these handle resolver endpoints are not available.
handle.remote-resolver.enabled = true
# Whether to enable the DSpace listhandles resolver that lists all available
# handles for this DSpace installation.
# Defaults to "false" which means is possible to obtain the list of handles
# of this DSpace installation, whenever the `handle.remote-resolver.enabled = true`.
handle.hide.listhandles = false
#####################
# LOGLEVEL SETTINGS #
#####################

View File

@@ -39,10 +39,10 @@ import org.dspace.profile.OrcidSynchronizationMode;
public class ItemBuilder extends AbstractDSpaceObjectBuilder<Item> {
private boolean withdrawn = false;
private String handle = null;
private WorkspaceItem workspaceItem;
private Item item;
private Group readerGroup = null;
private String handle = null;
protected ItemBuilder(Context context) {
super(context);
@@ -371,7 +371,7 @@ public class ItemBuilder extends AbstractDSpaceObjectBuilder<Item> {
@Override
public Item build() {
try {
installItemService.installItem(context, workspaceItem, handle);
installItemService.installItem(context, workspaceItem, this.handle);
itemService.update(context, item);
//Check if we need to make this item private. This has to be done after item install.

View File

@@ -0,0 +1,198 @@
/**
* 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.hdlresolver;
import java.text.MessageFormat;
import java.util.List;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.handle.hdlresolver.HdlResolverDTO;
import org.dspace.handle.hdlresolver.HdlResolverService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* This controller is public and is useful for handle resolving,
* whether a target handle identifier will be resolved into the
* corresponding URL (if found), otherwise will respond a null string.
*
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.it)
*
*/
@RestController
@ConditionalOnProperty("handle.remote-resolver.enabled")
@RequestMapping(path = "/{hdlService:hdlresolver|resolve|listhandles|listprefixes}/")
public class HdlResolverRestController {
static final String HDL_RESOLVER = "/hdlresolver/";
static final String RESOLVE = "/resolve/";
static final String LISTHANDLES = "/listhandles/";
static final String LISTPREFIXES = "/listprefixes/";
private static final Logger log = LogManager.getLogger();
@Autowired
private HdlResolverService hdlResolverService;
@GetMapping(
value = "**",
produces = "application/json;charset=UTF-8"
)
public ResponseEntity<String> handleController(HttpServletRequest request, @PathVariable String hdlService) {
if (HDL_RESOLVER.contains(hdlService) || RESOLVE.contains(hdlService)) {
return resolveHandle(request, hdlService);
} else if (LISTHANDLES.contains(hdlService)) {
return this.listHandles(
request,
Optional.ofNullable(request.getRequestURI().split(LISTHANDLES))
.filter(split -> split.length > 1)
.map(splitted -> splitted[1])
.orElse(null)
);
} else if (LISTPREFIXES.contains(hdlService)) {
return this.listPrefixes(request);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
/**
* REST GET Method used to find and retrieve the URL of a target Handle. It
* should return only one item, if found, else a null body value.
* </br>
* Generate an <code>HttpStatus.BAD_REQUEST</code> 400 Error if the handle used
* in path isn't valid.
* </br>
* The response type will be (<code>application/json;charset=UTF-8</code>)
* a string representing an array-like list of handles:
* </br>
* Example:
* <ul>
* <li>Request: GET - http://{dspace.url}/hdlresolver/handleIdExample/1</li>
* <li>Response: 200 - ["http://localhost/handle/hanldeIdExample1"]
* </ul>
*
* @param request {@code HttpServletRequest}
* @return One element List or <code>null</code> with status 200 - <code>HttpStatus.OK</code>
* or 400 - <code>HttpStatus.BAD_REQUEST</code> error
*/
public ResponseEntity<String> resolveHandle(HttpServletRequest request, String hdlService) {
HdlResolverDTO handleResolver =
this.hdlResolverService.resolveBy(
request.getRequestURI(),
MessageFormat.format("{0}/{1}/", request.getContextPath(), hdlService)
);
if (!handleResolver.isValid()) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(this.resolveToURL(request, handleResolver), HttpStatus.OK);
}
}
/**
* REST GET Method used to list all available prefixes for handles. It
* should return a list of prefixes, at least the default one.
* </br>
* The response type will be (<code>application/json;charset=UTF-8</code>)
* a string representing an array-like list of handles:
* </br>
* Example:
* <ul>
* <li>Request: GET - http://{dspace.url}/listprefixes</li>
* <li>Response: 200 - ["123456789","prefix1","prefix2"]
* </ul>
*
* @param request {@code HttpServletRequest}
* @return List of valid prefixes with status 200 <code>HttpStatus.OK</code>
*/
public ResponseEntity<String> listPrefixes(HttpServletRequest request) {
return new ResponseEntity<>(this.mapAsJson(this.hdlResolverService.listPrefixes()), HttpStatus.OK);
}
/**
* REST GET Method used to list all available handles starting with target prefix.
* It should return a list of handles.
* </br>
* If the controller is disabled `handle.hide.listhandles = true`,
* then 400 - <code>HttpStatus.NOT_FOUND</code> is returned.
* </br>
* If the requested prefix is blank,
* then 404 - <code>HttpStatus.BAD_REQUEST</code> is returned.
* </br>
* The response type will be (<code>application/json;charset=UTF-8</code>)
* a string representing an array-like list of handles:
* </br>
* Example:
* <ul>
* <li>Request: GET - http://{dspace.url}/listhandles/prefix</li>
* <li>Response: 200 - ["prefix/zero","prefix1/one","prefix2/two"]
* </ul>
*
* @param request {@code HttpServletRequest}
* @param prefix {@code String} representing the prefix that will be searched
* @return List of valid prefixes with status 200 <code>HttpStatus.OK</code>
* or status 400 <code>HttpStatus.NOT_FOUND</code> if disabled by properties
* or status 404 <code>HttpStatus.BAD_REQUEST</code> if blank prefix is requested.
*/
public ResponseEntity<String> listHandles(HttpServletRequest request, @PathVariable String prefix) {
if (!this.hdlResolverService.isListhandlesEnabled()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
if (StringUtils.isBlank(prefix)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(
this.mapAsJson(this.hdlResolverService.listHandles(ContextUtil.obtainContext(request), prefix)),
HttpStatus.OK
);
}
/**
* Maps the handle to a correct response.
*
* @param request HttpServletRequest
* @param handleResolver HdlResolverDTO - Handle resolver
* @return One element list using String if found, else null String.
*/
private String resolveToURL(HttpServletRequest request, HdlResolverDTO handleResolver) {
return mapAsJson(this.hdlResolverService.resolveToURL(ContextUtil.obtainContext(request), handleResolver));
}
protected String mapAsJson(final String resolvedUrl) {
String json = "null";
if (StringUtils.isNotEmpty(resolvedUrl)) {
json = mapAsJson(List.of(resolvedUrl));
}
return json;
}
protected String mapAsJson(final List<String> jsonList) {
String json = "null";
if (jsonList != null && !jsonList.isEmpty()) {
try {
json = new ObjectMapper().writeValueAsString(jsonList);
} catch (JsonProcessingException e) {
log.error("Error during conversion of response!", e);
}
}
return json;
}
}

View File

@@ -0,0 +1,327 @@
/**
* 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.hdlresolver;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.not;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
import org.dspace.builder.ItemBuilder;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.handle.hdlresolver.HdlResolverServiceImpl;
import org.dspace.services.ConfigurationService;
import org.hamcrest.core.StringContains;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.ResultMatcher;
/**
* @author Vincenzo Mecca (vins01-4science - vincenzo.mecca@4science.com)
*
*/
public class HdlResolverRestControllerIT extends AbstractControllerIntegrationTest {
@Autowired
private ConfigurationService configurationService;
/**
* Verifies that any mapped <code>hdlIdentifier</code> returns the
* corresponding <code>handle URL</code>
*
* @throws Exception
*
*/
@Test
public void givenMappedIdentifierWhenCallHdlresolverThenReturnsMappedURL() throws Exception {
context.turnOffAuthorisationSystem();
// ** START GIVEN **
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1")
.withLogo("TestingContentForLogo").build();
Item publicItem1 = ItemBuilder.createItem(context, col1).withTitle("Public item 1").withIssueDate("2017-10-17")
.withAuthor("Smith, Donald").withAuthor("Doe, John").withSubject("ExtraEntry")
.withHandle("123456789/testHdlResolver").build();
context.restoreAuthSystemState();
// ** END GIVEN **
ResultMatcher matchHandleResponse = jsonPath("$[0]",
StringContains.containsString("123456789/testHdlResolver"));
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES + publicItem1.getHandle()))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
getClient()
.perform(get(HdlResolverRestController.RESOLVE + publicItem1.getHandle()))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
getClient()
.perform(get(HdlResolverRestController.HDL_RESOLVER + publicItem1.getHandle()))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
getClient()
.perform(get("/wrongController/" + publicItem1.getHandle()))
.andExpect(status().isNotFound());
}
@Test
public void givenAnyHandlesWhenDisabledListhandleThenReturnsNotFoundResp()
throws Exception {
this.configurationService.setProperty(HdlResolverServiceImpl.LISTHANDLES_HIDE_PROP, true);
try {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1")
.withLogo("TestingContentForLogo").build();
String handlePrefix = "123456789/PREFIX";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(handlePrefix)
.build();
context.restoreAuthSystemState();
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES))
.andExpect(status().isNotFound());
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES + handlePrefix))
.andExpect(status().isNotFound());
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES + "anyHandlePrefixHere"))
.andExpect(status().isNotFound());
} catch (Exception e) {
e.printStackTrace();
} finally {
this.configurationService.setProperty(HdlResolverServiceImpl.LISTHANDLES_HIDE_PROP, false);
}
}
@Test
public void givenMappedHandlesWhenCalledListHandlesWithoutPrefixThenReturnsBadRequestResp()
throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1")
.withLogo("TestingContentForLogo").build();
String handlePrefix = "123456789/PREFIX";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(handlePrefix)
.build();
context.restoreAuthSystemState();
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES))
.andExpect(status().isBadRequest());
}
@Test
public void givenMappedHandlesWhenCalledListHandlesWithPrefixThenReturnsAllHandlesWithThatPrefix()
throws Exception {
context.turnOffAuthorisationSystem();
// ** START GIVEN **
parentCommunity = CommunityBuilder.createCommunity(context).withName("Parent Community").build();
Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1")
.withLogo("TestingContentForLogo").build();
String handlePrefix = "123456789/PREFIX";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(handlePrefix)
.build();
String handlePrefix1 = "123456789/PREFIX1";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(handlePrefix1)
.build();
String noHandle = "123456789/NOPREFIX";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(noHandle)
.build();
String testHandle = "123456789/TEST";
ItemBuilder.createItem(context, col1)
.withTitle("Public item 1")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("ExtraEntry")
.withHandle(testHandle)
.build();
context.restoreAuthSystemState();
// ** END GIVEN **
ResultMatcher matchHandleResponse =
jsonPath("$[*]",
allOf(
containsInAnyOrder(handlePrefix, handlePrefix1),
not(containsInAnyOrder(noHandle, testHandle))
)
);
getClient()
.perform(get(HdlResolverRestController.LISTHANDLES + handlePrefix))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
}
/**
* Verifies that a null hdlIdentifier returns a
*
* <code>HttpStatus.BAD_REQUEST</code>
*
* @throws Exception
* @throws SQLException
*
*/
@Test
public void givenNullHdlIdentifierWhenCallHdlresolverThenReturnsBadRequest() throws Exception {
getClient().perform(
get(HdlResolverRestController.HDL_RESOLVER + "null"))
.andExpect(status().isBadRequest());
getClient().perform(
get(HdlResolverRestController.RESOLVE + "null"))
.andExpect(status().isBadRequest());
}
/**
* Verifies that an empty hdlIdentifier returns a
* <code>HttpStatus.BAD_REQUEST</code>
*
* @throws Exception
* @throws SQLException
*
*/
@Test
public void givenEmptyHdlIdentifierWhenCallHdlresolverThenReturnsNull() throws Exception {
getClient()
.perform(get(HdlResolverRestController.HDL_RESOLVER + " "))
.andExpect(status().isBadRequest());
getClient()
.perform(get(HdlResolverRestController.RESOLVE + " "))
.andExpect(status().isBadRequest());
}
/**
* Verifies that any unmapped hdlIdentifier returns a null response
*
* @throws Exception
*
*/
@Test
public void givenIdentifierNotMappedWhenCallHdlresolverThenReturnsNull() throws Exception {
getClient()
.perform(get(HdlResolverRestController.HDL_RESOLVER + "testHdlResolver/2"))
.andExpect(status().isOk()).andExpect(content().string("null"));
getClient()
.perform(get(HdlResolverRestController.RESOLVE + "testHdlResolver/2"))
.andExpect(status().isOk()).andExpect(content().string("null"));
}
@Test
public void givenMappedPrefixWhenNoAdditionalPrefixesConfThenReturnsHandlePrefix() throws Exception {
String handlePrefix = this.configurationService.getProperty("handle.prefix");
ResultMatcher matchHandleResponse =
jsonPath("$[*]",
allOf(
containsInAnyOrder(handlePrefix)
)
);
getClient()
.perform(get(HdlResolverRestController.LISTPREFIXES))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
}
@Test
public void givenMappedPrefixWhenAdditionalPrefixesConfThenReturnsAllOfThem() throws Exception {
String handlePrefix = this.configurationService.getProperty("handle.prefix");
String[] defaultValue = this.configurationService.getArrayProperty("handle.additional.prefixes");
try {
String additionalPrefixes = "additional1,additional2";
this.configurationService.setProperty("handle.additional.prefixes", additionalPrefixes);
List<String> validPrefixes = Arrays.asList(additionalPrefixes.split(","));
validPrefixes.add(handlePrefix);
ResultMatcher matchHandleResponse =
jsonPath("$[*]",
allOf(
containsInAnyOrder(validPrefixes)
)
);
getClient()
.perform(get(HdlResolverRestController.LISTPREFIXES))
.andExpect(status().isOk())
.andExpect(matchHandleResponse);
} catch (Exception e) {
e.printStackTrace();
} finally {
this.configurationService.setProperty("handle.additional.prefixse", defaultValue);
}
}
}

View File

@@ -330,8 +330,15 @@ handle.dir = ${dspace.dir}/handle-server
# that repository)
# handle.additional.prefixes = prefix1[, prefix2]
# By default we hide the list handles method in the JSON endpoint as it could
# produce heavy load for large repository
# Whether to enable the DSpace handle resolver endpoints necessary for
# https://github.com/DSpace/Remote-Handle-Resolver
# Defaults to "false" which means these handle resolver endpoints are not available.
# handle.remote-resolver.enabled = false
# Whether to enable the DSpace listhandles resolver that lists all available
# handles for this DSpace installation.
# Defaults to "false" which means is possible to obtain the list of handles
# of this DSpace installation, whenever the `handle.remote-resolver.enabled = true`.
# handle.hide.listhandles = false
##### Authorization system configuration - Delegate ADMIN #####

View File

@@ -67,6 +67,8 @@
<bean class="org.dspace.profile.OrcidMetadataCopyingAction"/>
<bean class="org.dspace.handle.hdlresolver.HdlResolverServiceImpl"/>
<bean class='org.dspace.service.impl.HttpConnectionPoolService'
id='solrHttpConnectionPoolService'
scope='singleton'