mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge pull request #8357 from 4Science/main-duracom-70
Add compatibility for DSpace 7 with the Remote Handle Resolver
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -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();
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -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();
|
||||
}
|
||||
|
@@ -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 #
|
||||
#####################
|
||||
|
@@ -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.
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -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 #####
|
||||
|
@@ -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'
|
||||
|
Reference in New Issue
Block a user