mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 15:03:18 +00:00
Merge pull request #2792 from 4Science/draft_vocabulary
Refactoring authority framework, value pairs and controlled vocabulary
This commit is contained in:
@@ -33,21 +33,62 @@ public class Choice {
|
||||
*/
|
||||
public String value = null;
|
||||
|
||||
/**
|
||||
* A boolean representing if choice entry value can selected (usually true).
|
||||
* Hierarchical authority can flag some choice as not selectable to force the
|
||||
* use to choice a more detailed terms in the tree, such a leaf or a deeper
|
||||
* branch
|
||||
*/
|
||||
public boolean selectable = true;
|
||||
|
||||
public Map<String, String> extras = new HashMap<String, String>();
|
||||
|
||||
public Choice() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal constructor for this data object. It assumes an empty map of extras
|
||||
* information and a selected choice
|
||||
*
|
||||
* @param authority the authority key
|
||||
* @param value the text value to store in the metadata
|
||||
* @param label the value to display to the user
|
||||
*/
|
||||
public Choice(String authority, String value, String label) {
|
||||
this.authority = authority;
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to quickly setup the data object for basic authorities. The choice is assumed to be selectable.
|
||||
*
|
||||
* @param authority the authority key
|
||||
* @param value the text value to store in the metadata
|
||||
* @param label the value to display to the user
|
||||
* @param extras a key value map of extra information related to this choice
|
||||
*/
|
||||
public Choice(String authority, String label, String value, Map<String, String> extras) {
|
||||
this.authority = authority;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.extras = extras;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for common need of Hierarchical authorities that want to
|
||||
* explicitely set the selectable flag
|
||||
*
|
||||
* @param authority the authority key
|
||||
* @param value the text value to store in the metadata
|
||||
* @param label the value to display to the user
|
||||
* @param selectable true if the choice can be selected, false if the a more
|
||||
* accurate choice should be preferred
|
||||
*/
|
||||
public Choice(String authority, String label, String value, boolean selectable) {
|
||||
this.authority = authority;
|
||||
this.label = label;
|
||||
this.value = value;
|
||||
this.selectable = selectable;
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,10 @@
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dspace.core.NameAwarePlugin;
|
||||
|
||||
/**
|
||||
* Plugin interface that supplies an authority control mechanism for
|
||||
@@ -17,7 +20,7 @@ import org.dspace.content.Collection;
|
||||
* @see ChoiceAuthorityServiceImpl
|
||||
* @see MetadataAuthorityServiceImpl
|
||||
*/
|
||||
public interface ChoiceAuthority {
|
||||
public interface ChoiceAuthority extends NameAwarePlugin {
|
||||
/**
|
||||
* Get all values from the authority that match the preferred value.
|
||||
* Note that the offering was entered by the user and may contain
|
||||
@@ -32,15 +35,13 @@ public interface ChoiceAuthority {
|
||||
* defaultSelected index in the Choices instance to the choice, if any,
|
||||
* that matches the value.
|
||||
*
|
||||
* @param field being matched for
|
||||
* @param text user's value to match
|
||||
* @param collection database ID of Collection for context (owner of Item)
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
*/
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale);
|
||||
public Choices getMatches(String text, int start, int limit, String locale);
|
||||
|
||||
/**
|
||||
* Get the single "best" match (if any) of a value in the authority
|
||||
@@ -51,13 +52,11 @@ public interface ChoiceAuthority {
|
||||
* This call is typically used in non-interactive metadata ingest
|
||||
* where there is no interactive agent to choose from among options.
|
||||
*
|
||||
* @param field being matched for
|
||||
* @param text user's value to match
|
||||
* @param collection database ID of Collection for context (owner of Item)
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null) with 1 or 0 values.
|
||||
*/
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale);
|
||||
public Choices getBestMatch(String text, String locale);
|
||||
|
||||
/**
|
||||
* Get the canonical user-visible "label" (i.e. short descriptive text)
|
||||
@@ -67,31 +66,97 @@ public interface ChoiceAuthority {
|
||||
* This may get called many times while populating a Web page so it should
|
||||
* be implemented as efficiently as possible.
|
||||
*
|
||||
* @param field being matched for
|
||||
* @param key authority key known to this authority.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return descriptive label - should always return something, never null.
|
||||
*/
|
||||
public String getLabel(String field, String key, String locale);
|
||||
public String getLabel(String key, String locale);
|
||||
|
||||
/**
|
||||
* Get the canonical value to store for a key in the authority. Can be localized
|
||||
* given the implicit or explicit locale specification.
|
||||
*
|
||||
* @param key authority key known to this authority.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return value to store - should always return something, never null.
|
||||
*/
|
||||
default String getValue(String key, String locale) {
|
||||
return getLabel(key, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of additional information related to the specified key in the
|
||||
* authority.
|
||||
*
|
||||
* @param key the key of the entry
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a map of additional information related to the key
|
||||
*/
|
||||
default Map<String, String> getExtra(String key, String locale) {
|
||||
return new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true for hierarchical authorities
|
||||
*
|
||||
* @return <code>true</code> if hierarchical, default <code>false</code>
|
||||
*/
|
||||
default boolean isHierarchical() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrollable authorities allows the scroll of the entries without applying
|
||||
* filter/query to the
|
||||
* {@link #getMatches(String, String, Collection, int, int, String)}
|
||||
*
|
||||
* @return <code>true</code> if scrollable, default <code>false</code>
|
||||
*/
|
||||
default boolean isScrollable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean hasIdentifier() {
|
||||
return true;
|
||||
/**
|
||||
* Hierarchical authority can provide an hint for the UI about how many levels
|
||||
* preload to improve the UX. It provides a valid default for hierarchical
|
||||
* authorities
|
||||
*
|
||||
* @return <code>0</code> if hierarchical, null otherwise
|
||||
*/
|
||||
default Integer getPreloadLevel() {
|
||||
return isHierarchical() ? 0 : null;
|
||||
}
|
||||
|
||||
default public Choice getChoice(String fieldKey, String authKey, String locale) {
|
||||
/**
|
||||
* Build the preferred choice associated with the authKey. The default
|
||||
* implementation delegate the creato to the {@link #getLabel(String, String)}
|
||||
* {@link #getValue(String, String)} and {@link #getExtra(String, String)}
|
||||
* methods but can be directly overriden for better efficiency or special
|
||||
* scenario
|
||||
*
|
||||
* @param authKey authority key known to this authority.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return the preferred choice for this authKey and locale
|
||||
*/
|
||||
default public Choice getChoice(String authKey, String locale) {
|
||||
Choice result = new Choice();
|
||||
result.authority = authKey;
|
||||
result.label = getLabel(fieldKey, authKey, locale);
|
||||
result.value = getLabel(fieldKey, authKey, locale);
|
||||
result.label = getLabel(authKey, locale);
|
||||
result.value = getValue(authKey, locale);
|
||||
result.extras.putAll(getExtra(authKey, locale));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a recommendation to store the authority in the metadata value if
|
||||
* available in the in the provided choice(s). Usually ChoiceAuthority should
|
||||
* recommend that so the default is true and it only need to be implemented in
|
||||
* the unusual scenario
|
||||
*
|
||||
* @return <code>true</code> if the authority provided in any choice of this
|
||||
* authority should be stored in the metadata value
|
||||
*/
|
||||
default public boolean storeAuthorityInMetadata() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,13 @@
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -19,6 +22,9 @@ import org.dspace.app.util.DCInput;
|
||||
import org.dspace.app.util.DCInputSet;
|
||||
import org.dspace.app.util.DCInputsReader;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.app.util.SubmissionConfig;
|
||||
import org.dspace.app.util.SubmissionConfigReader;
|
||||
import org.dspace.app.util.SubmissionConfigReaderException;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
@@ -54,23 +60,37 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
// map of field key to authority plugin
|
||||
protected Map<String, ChoiceAuthority> controller = new HashMap<String, ChoiceAuthority>();
|
||||
|
||||
// map of field key, form definition to authority plugin
|
||||
protected Map<String, Map<String, ChoiceAuthority>> controllerFormDefinitions =
|
||||
new HashMap<String, Map<String, ChoiceAuthority>>();
|
||||
|
||||
// map of field key to presentation type
|
||||
protected Map<String, String> presentation = new HashMap<String, String>();
|
||||
|
||||
// map of field key to closed value
|
||||
protected Map<String, Boolean> closed = new HashMap<String, Boolean>();
|
||||
|
||||
// map of authority name to field key
|
||||
protected Map<String, String> authorities = new HashMap<String, String>();
|
||||
// flag to track the initialization status of the service
|
||||
private boolean initialized = false;
|
||||
|
||||
// map of authority name to field keys (the same authority can be configured over multiple metadata)
|
||||
protected Map<String, List<String>> authorities = new HashMap<String, List<String>>();
|
||||
|
||||
// map of authority name to form definition and field keys
|
||||
protected Map<String, Map<String, List<String>>> authoritiesFormDefinitions =
|
||||
new HashMap<String, Map<String, List<String>>>();
|
||||
|
||||
// the item submission reader
|
||||
private SubmissionConfigReader itemSubmissionConfigReader;
|
||||
|
||||
@Autowired(required = true)
|
||||
protected ConfigurationService configurationService;
|
||||
@Autowired(required = true)
|
||||
protected PluginService pluginService;
|
||||
|
||||
private final String CHOICES_PLUGIN_PREFIX = "choices.plugin.";
|
||||
private final String CHOICES_PRESENTATION_PREFIX = "choices.presentation.";
|
||||
private final String CHOICES_CLOSED_PREFIX = "choices.closed.";
|
||||
final static String CHOICES_PLUGIN_PREFIX = "choices.plugin.";
|
||||
final static String CHOICES_PRESENTATION_PREFIX = "choices.presentation.";
|
||||
final static String CHOICES_CLOSED_PREFIX = "choices.closed.";
|
||||
|
||||
protected ChoiceAuthorityServiceImpl() {
|
||||
}
|
||||
@@ -96,10 +116,25 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
|
||||
@Override
|
||||
public Set<String> getChoiceAuthoritiesNames() {
|
||||
if (authorities.keySet().isEmpty()) {
|
||||
init();
|
||||
Set<String> authoritiesNames = new HashSet<String>();
|
||||
authoritiesNames.addAll(authorities.keySet());
|
||||
authoritiesNames.addAll(authoritiesFormDefinitions.keySet());
|
||||
return authoritiesNames;
|
||||
}
|
||||
|
||||
private synchronized void init() {
|
||||
if (!initialized) {
|
||||
try {
|
||||
itemSubmissionConfigReader = new SubmissionConfigReader();
|
||||
} catch (SubmissionConfigReaderException e) {
|
||||
// the system is in an illegal state as the submission definition is not valid
|
||||
throw new IllegalStateException("Error reading the item submission configuration: " + e.getMessage(),
|
||||
e);
|
||||
}
|
||||
loadChoiceAuthorityConfigurations();
|
||||
initialized = true;
|
||||
}
|
||||
return authorities.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,59 +147,62 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
@Override
|
||||
public Choices getMatches(String fieldKey, String query, Collection collection,
|
||||
int start, int limit, String locale) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
||||
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"No choices plugin was configured for field \"" + fieldKey
|
||||
+ "\".");
|
||||
+ "\", collection=" + collection.getID().toString() + ".");
|
||||
}
|
||||
return ma.getMatches(fieldKey, query, collection, start, limit, locale);
|
||||
return ma.getMatches(query, start, limit, locale);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale,
|
||||
boolean externalInput) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
||||
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"No choices plugin was configured for field \"" + fieldKey
|
||||
+ "\".");
|
||||
+ "\", collection=" + collection.getID().toString() + ".");
|
||||
}
|
||||
if (externalInput && ma instanceof SolrAuthority) {
|
||||
((SolrAuthority) ma).addExternalResultsInNextMatches();
|
||||
}
|
||||
return ma.getMatches(fieldKey, query, collection, start, limit, locale);
|
||||
return ma.getMatches(query, start, limit, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String fieldKey, String query, Collection collection,
|
||||
String locale) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
||||
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"No choices plugin was configured for field \"" + fieldKey
|
||||
+ "\".");
|
||||
+ "\", collection=" + collection.getID().toString() + ".");
|
||||
}
|
||||
return ma.getBestMatch(fieldKey, query, collection, locale);
|
||||
return ma.getBestMatch(query, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(MetadataValue metadataValue, String locale) {
|
||||
return getLabel(metadataValue.getMetadataField().toString(), metadataValue.getAuthority(), locale);
|
||||
public String getLabel(MetadataValue metadataValue, Collection collection, String locale) {
|
||||
return getLabel(metadataValue.getMetadataField().toString(), collection, metadataValue.getAuthority(), locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String fieldKey, String authKey, String locale) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
||||
public String getLabel(String fieldKey, Collection collection, String authKey, String locale) {
|
||||
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException("No choices plugin was configured for field \"" + fieldKey + "\".");
|
||||
throw new IllegalArgumentException(
|
||||
"No choices plugin was configured for field \"" + fieldKey
|
||||
+ "\", collection=" + collection.getID().toString() + ".");
|
||||
}
|
||||
return ma.getLabel(fieldKey, authKey, locale);
|
||||
return ma.getLabel(authKey, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChoicesConfigured(String fieldKey) {
|
||||
return getChoiceAuthorityMap().containsKey(fieldKey);
|
||||
public boolean isChoicesConfigured(String fieldKey, Collection collection) {
|
||||
return getAuthorityByFieldKeyCollection(fieldKey, collection) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,8 +216,14 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getVariants(MetadataValue metadataValue) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(metadataValue.getMetadataField().toString());
|
||||
public List<String> getVariants(MetadataValue metadataValue, Collection collection) {
|
||||
String fieldKey = metadataValue.getMetadataField().toString();
|
||||
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"No choices plugin was configured for field \"" + fieldKey
|
||||
+ "\", collection=" + collection.getID().toString() + ".");
|
||||
}
|
||||
if (ma instanceof AuthorityVariantsSupport) {
|
||||
AuthorityVariantsSupport avs = (AuthorityVariantsSupport) ma;
|
||||
return avs.getVariants(metadataValue.getAuthority(), metadataValue.getLanguage());
|
||||
@@ -189,42 +233,53 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
|
||||
|
||||
@Override
|
||||
public String getChoiceAuthorityName(String schema, String element, String qualifier) {
|
||||
String makeFieldKey = makeFieldKey(schema, element, qualifier);
|
||||
if (getChoiceAuthorityMap().containsKey(makeFieldKey)) {
|
||||
for (String key : this.authorities.keySet()) {
|
||||
if (this.authorities.get(key).equals(makeFieldKey)) {
|
||||
return key;
|
||||
public String getChoiceAuthorityName(String schema, String element, String qualifier, Collection collection) {
|
||||
init();
|
||||
String fieldKey = makeFieldKey(schema, element, qualifier);
|
||||
// check if there is an authority configured for the metadata valid for all the collections
|
||||
if (controller.containsKey(fieldKey)) {
|
||||
for (Entry<String, List<String>> authority2md : authorities.entrySet()) {
|
||||
if (authority2md.getValue().contains(fieldKey)) {
|
||||
return authority2md.getKey();
|
||||
}
|
||||
}
|
||||
} else if (collection != null && controllerFormDefinitions.containsKey(fieldKey)) {
|
||||
// there is an authority configured for the metadata valid for some collections,
|
||||
// check if it is the requested collection
|
||||
Map<String, ChoiceAuthority> controllerFormDef = controllerFormDefinitions.get(fieldKey);
|
||||
SubmissionConfig submissionConfig = itemSubmissionConfigReader
|
||||
.getSubmissionConfigByCollection(collection.getHandle());
|
||||
String submissionName = submissionConfig.getSubmissionName();
|
||||
// check if the requested collection has a submission definition that use an authority for the metadata
|
||||
if (controllerFormDef.containsKey(submissionName)) {
|
||||
for (Entry<String, Map<String, List<String>>> authority2defs2md :
|
||||
authoritiesFormDefinitions.entrySet()) {
|
||||
List<String> mdByDefinition = authority2defs2md.getValue().get(submissionName);
|
||||
if (mdByDefinition != null && mdByDefinition.contains(fieldKey)) {
|
||||
return authority2defs2md.getKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return configurationService.getProperty(
|
||||
CHOICES_PLUGIN_PREFIX + schema + "." + element + (qualifier != null ? "." + qualifier : ""));
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String makeFieldKey(String schema, String element, String qualifier) {
|
||||
return Utils.standardize(schema, element, qualifier, "_");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return map of key to ChoiceAuthority plugin
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Map<String, ChoiceAuthority> getChoiceAuthorityMap() {
|
||||
// If empty, load from configuration
|
||||
if (controller.isEmpty()) {
|
||||
loadChoiceAuthorityConfigurations();
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearCache() {
|
||||
controller.clear();
|
||||
authorities.clear();
|
||||
presentation.clear();
|
||||
closed.clear();
|
||||
controllerFormDefinitions.clear();
|
||||
authoritiesFormDefinitions.clear();
|
||||
itemSubmissionConfigReader = null;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
private void loadChoiceAuthorityConfigurations() {
|
||||
// Get all configuration keys starting with a given prefix
|
||||
List<String> propKeys = configurationService.getPropertyKeys(CHOICES_PLUGIN_PREFIX);
|
||||
@@ -249,71 +304,127 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
"Skipping invalid configuration for " + key + " because named plugin not found: " + authorityName);
|
||||
continue;
|
||||
}
|
||||
if (!authorities.containsKey(authorityName)) {
|
||||
controller.put(fkey, ma);
|
||||
authorities.put(authorityName, fkey);
|
||||
} else {
|
||||
log.warn(
|
||||
"Skipping invalid configuration for " + key + " because plugin is alredy in use: " +
|
||||
authorityName + " used by " + authorities
|
||||
.get(authorityName));
|
||||
continue;
|
||||
}
|
||||
|
||||
controller.put(fkey, ma);
|
||||
List<String> fkeys;
|
||||
if (authorities.containsKey(authorityName)) {
|
||||
fkeys = authorities.get(authorityName);
|
||||
} else {
|
||||
fkeys = new ArrayList<String>();
|
||||
}
|
||||
fkeys.add(fkey);
|
||||
authorities.put(authorityName, fkeys);
|
||||
log.debug("Choice Control: For field=" + fkey + ", Plugin=" + ma);
|
||||
}
|
||||
autoRegisterChoiceAuthorityFromInputReader();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will register all the authorities that are required due to the
|
||||
* submission forms configuration. This includes authorities for value pairs and
|
||||
* xml vocabularies
|
||||
*/
|
||||
private void autoRegisterChoiceAuthorityFromInputReader() {
|
||||
try {
|
||||
List<SubmissionConfig> submissionConfigs = itemSubmissionConfigReader
|
||||
.getAllSubmissionConfigs(Integer.MAX_VALUE, 0);
|
||||
DCInputsReader dcInputsReader = new DCInputsReader();
|
||||
for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) {
|
||||
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput[] dcrows : dcinputs) {
|
||||
for (DCInput dcinput : dcrows) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
|
||||
// loop over all the defined item submission configuration
|
||||
for (SubmissionConfig subCfg : submissionConfigs) {
|
||||
String submissionName = subCfg.getSubmissionName();
|
||||
List<DCInputSet> inputsBySubmissionName = dcInputsReader.getInputsBySubmissionName(submissionName);
|
||||
// loop over the submission forms configuration eventually associated with the submission panel
|
||||
for (DCInputSet dcinputSet : inputsBySubmissionName) {
|
||||
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput[] dcrows : dcinputs) {
|
||||
for (DCInput dcinput : dcrows) {
|
||||
// for each input in the form check if it is associated with a real value pairs
|
||||
// or an xml vocabulary
|
||||
String authorityName = null;
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
&& !StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
authorityName = dcinput.getPairsType();
|
||||
} else if (StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
|
||||
// do we have an authority?
|
||||
if (StringUtils.isNotBlank(authorityName)) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
ChoiceAuthority ca = controller.get(authorityName);
|
||||
if (ca == null) {
|
||||
InputFormSelfRegisterWrapperAuthority ifa = new
|
||||
InputFormSelfRegisterWrapperAuthority();
|
||||
if (controller.containsKey(fieldKey)) {
|
||||
ifa = (InputFormSelfRegisterWrapperAuthority) controller.get(fieldKey);
|
||||
}
|
||||
|
||||
ChoiceAuthority ma = (ChoiceAuthority) pluginService
|
||||
ca = (ChoiceAuthority) pluginService
|
||||
.getNamedPlugin(ChoiceAuthority.class, authorityName);
|
||||
if (ma == null) {
|
||||
log.warn("Skipping invalid configuration for " + fieldKey
|
||||
+ " because named plugin not found: " + authorityName);
|
||||
continue;
|
||||
if (ca == null) {
|
||||
throw new IllegalStateException("Invalid configuration for " + fieldKey
|
||||
+ " in submission definition " + submissionName
|
||||
+ ", form definition " + dcinputSet.getFormName()
|
||||
+ " no named plugin found: " + authorityName);
|
||||
}
|
||||
ifa.getDelegates().put(dcinputSet.getFormName(), ma);
|
||||
controller.put(fieldKey, ifa);
|
||||
}
|
||||
|
||||
if (!authorities.containsKey(authorityName)) {
|
||||
authorities.put(authorityName, fieldKey);
|
||||
}
|
||||
|
||||
addAuthorityToFormCacheMap(submissionName, fieldKey, ca);
|
||||
addFormDetailsToAuthorityCacheMap(submissionName, authorityName, fieldKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
// the system is in an illegal state as the submission definition is not valid
|
||||
throw new IllegalStateException("Error reading the item submission configuration: " + e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the form/field to the cache map keeping track of which form/field are
|
||||
* associated with the specific authority name
|
||||
*
|
||||
* @param submissionName the form definition name
|
||||
* @param authorityName the name of the authority plugin
|
||||
* @param fieldKey the field key that use the authority
|
||||
*/
|
||||
private void addFormDetailsToAuthorityCacheMap(String submissionName, String authorityName, String fieldKey) {
|
||||
Map<String, List<String>> submissionDefinitionNames2fieldKeys;
|
||||
if (authoritiesFormDefinitions.containsKey(authorityName)) {
|
||||
submissionDefinitionNames2fieldKeys = authoritiesFormDefinitions.get(authorityName);
|
||||
} else {
|
||||
submissionDefinitionNames2fieldKeys = new HashMap<String, List<String>>();
|
||||
}
|
||||
|
||||
List<String> fields;
|
||||
if (submissionDefinitionNames2fieldKeys.containsKey(submissionName)) {
|
||||
fields = submissionDefinitionNames2fieldKeys.get(submissionName);
|
||||
} else {
|
||||
fields = new ArrayList<String>();
|
||||
}
|
||||
fields.add(fieldKey);
|
||||
submissionDefinitionNames2fieldKeys.put(submissionName, fields);
|
||||
authoritiesFormDefinitions.put(authorityName, submissionDefinitionNames2fieldKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the authority plugin to the cache map keeping track of which authority is
|
||||
* used by a specific form/field
|
||||
*
|
||||
* @param submissionName the submission definition name
|
||||
* @param fieldKey the field key that require the authority
|
||||
* @param ca the authority plugin
|
||||
*/
|
||||
private void addAuthorityToFormCacheMap(String submissionName, String fieldKey, ChoiceAuthority ca) {
|
||||
Map<String, ChoiceAuthority> definition2authority;
|
||||
if (controllerFormDefinitions.containsKey(fieldKey)) {
|
||||
definition2authority = controllerFormDefinitions.get(fieldKey);
|
||||
} else {
|
||||
definition2authority = new HashMap<String, ChoiceAuthority>();
|
||||
}
|
||||
definition2authority.put(submissionName, ca);
|
||||
controllerFormDefinitions.put(fieldKey, definition2authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return map of key to presentation
|
||||
*
|
||||
@@ -370,26 +481,6 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
return closed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getChoiceMetadatabyAuthorityName(String name) {
|
||||
if (authorities.isEmpty()) {
|
||||
loadChoiceAuthorityConfigurations();
|
||||
}
|
||||
if (authorities.containsKey(name)) {
|
||||
return authorities.get(name);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choice getChoice(String fieldKey, String authKey, String locale) {
|
||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
||||
if (ma == null) {
|
||||
throw new IllegalArgumentException("No choices plugin was configured for field \"" + fieldKey + "\".");
|
||||
}
|
||||
return ma.getChoice(fieldKey, authKey, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName) {
|
||||
ChoiceAuthority ma = (ChoiceAuthority)
|
||||
@@ -401,4 +492,68 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
|
||||
private ChoiceAuthority getAuthorityByFieldKeyCollection(String fieldKey, Collection collection) {
|
||||
init();
|
||||
ChoiceAuthority ma = controller.get(fieldKey);
|
||||
if (ma == null && collection != null) {
|
||||
SubmissionConfigReader configReader;
|
||||
try {
|
||||
configReader = new SubmissionConfigReader();
|
||||
SubmissionConfig submissionName = configReader.getSubmissionConfigByCollection(collection.getHandle());
|
||||
ma = controllerFormDefinitions.get(fieldKey).get(submissionName.getSubmissionName());
|
||||
} catch (SubmissionConfigReaderException e) {
|
||||
// the system is in an illegal state as the submission definition is not valid
|
||||
throw new IllegalStateException("Error reading the item submission configuration: " + e.getMessage(),
|
||||
e);
|
||||
}
|
||||
}
|
||||
return ma;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storeAuthority(String fieldKey, Collection collection) {
|
||||
// currently only named authority can eventually provide real authority
|
||||
return controller.containsKey(fieldKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper that calls getChoicesByParent method of the plugin.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param parentId parent Id
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
* @see org.dspace.content.authority.ChoiceAuthority#getChoicesByParent(java.lang.String, java.lang.String,
|
||||
* int, int, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Choices getChoicesByParent(String authorityName, String parentId, int start, int limit, String locale) {
|
||||
HierarchicalAuthority ma = (HierarchicalAuthority) getChoiceAuthorityByAuthorityName(authorityName);
|
||||
return ma.getChoicesByParent(authorityName, parentId, start, limit, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper that calls getTopChoices method of the plugin.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
* @see org.dspace.content.authority.ChoiceAuthority#getTopChoices(java.lang.String, int, int, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Choices getTopChoices(String authorityName, int start, int limit, String locale) {
|
||||
HierarchicalAuthority ma = (HierarchicalAuthority) getChoiceAuthorityByAuthorityName(authorityName);
|
||||
return ma.getTopChoices(authorityName, start, limit, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choice getParentChoice(String authorityName, String vocabularyId, String locale) {
|
||||
HierarchicalAuthority ma = (HierarchicalAuthority) getChoiceAuthorityByAuthorityName(authorityName);
|
||||
return ma.getParentChoice(authorityName, vocabularyId, locale);
|
||||
}
|
||||
}
|
||||
|
@@ -9,14 +9,20 @@ package org.dspace.content.authority;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.DCInputsReader;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.dspace.core.SelfNamedPlugin;
|
||||
|
||||
/**
|
||||
@@ -44,16 +50,38 @@ import org.dspace.core.SelfNamedPlugin;
|
||||
public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority {
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DCInputAuthority.class);
|
||||
|
||||
private String values[] = null;
|
||||
private String labels[] = null;
|
||||
/**
|
||||
* The map of the values available for a specific language. Examples of keys are
|
||||
* "en", "it", "uk"
|
||||
*/
|
||||
private Map<String, String[]> values = null;
|
||||
|
||||
private static DCInputsReader dci = null;
|
||||
/**
|
||||
* The map of the labels available for a specific language. Examples of keys are
|
||||
* "en", "it", "uk"
|
||||
*/
|
||||
private Map<String, String[]> labels = null;
|
||||
|
||||
/**
|
||||
* The map of the input form reader associated to use for a specific java locale
|
||||
*/
|
||||
private static Map<Locale, DCInputsReader> dcis = null;
|
||||
private static String pluginNames[] = null;
|
||||
|
||||
public DCInputAuthority() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storeAuthorityInMetadata() {
|
||||
// For backward compatibility value pairs don't store authority in
|
||||
// the metadatavalue
|
||||
return false;
|
||||
}
|
||||
public static void reset() {
|
||||
pluginNames = null;
|
||||
}
|
||||
|
||||
public static String[] getPluginNames() {
|
||||
if (pluginNames == null) {
|
||||
initPluginNames();
|
||||
@@ -63,20 +91,28 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
|
||||
}
|
||||
|
||||
private static synchronized void initPluginNames() {
|
||||
Locale[] locales = I18nUtil.getSupportedLocales();
|
||||
Set<String> names = new HashSet<String>();
|
||||
if (pluginNames == null) {
|
||||
try {
|
||||
if (dci == null) {
|
||||
dci = new DCInputsReader();
|
||||
dcis = new HashMap<Locale, DCInputsReader>();
|
||||
for (Locale locale : locales) {
|
||||
dcis.put(locale, new DCInputsReader(I18nUtil.getInputFormsFileName(locale)));
|
||||
}
|
||||
for (Locale l : locales) {
|
||||
Iterator pi = dcis.get(l).getPairsNameIterator();
|
||||
while (pi.hasNext()) {
|
||||
names.add((String) pi.next());
|
||||
}
|
||||
}
|
||||
DCInputsReader dcirDefault = new DCInputsReader();
|
||||
Iterator pi = dcirDefault.getPairsNameIterator();
|
||||
while (pi.hasNext()) {
|
||||
names.add((String) pi.next());
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error("Failed reading DCInputs initialization: ", e);
|
||||
}
|
||||
List<String> names = new ArrayList<String>();
|
||||
Iterator pi = dci.getPairsNameIterator();
|
||||
while (pi.hasNext()) {
|
||||
names.add((String) pi.next());
|
||||
}
|
||||
|
||||
pluginNames = names.toArray(new String[names.size()]);
|
||||
log.debug("Got plugin names = " + Arrays.deepToString(pluginNames));
|
||||
}
|
||||
@@ -85,45 +121,65 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
|
||||
// once-only load of values and labels
|
||||
private void init() {
|
||||
if (values == null) {
|
||||
values = new HashMap<String, String[]>();
|
||||
labels = new HashMap<String, String[]>();
|
||||
String pname = this.getPluginInstanceName();
|
||||
List<String> pairs = dci.getPairs(pname);
|
||||
if (pairs != null) {
|
||||
values = new String[pairs.size() / 2];
|
||||
labels = new String[pairs.size() / 2];
|
||||
for (int i = 0; i < pairs.size(); i += 2) {
|
||||
labels[i / 2] = pairs.get(i);
|
||||
values[i / 2] = pairs.get(i + 1);
|
||||
for (Locale l : dcis.keySet()) {
|
||||
DCInputsReader dci = dcis.get(l);
|
||||
List<String> pairs = dci.getPairs(pname);
|
||||
if (pairs != null) {
|
||||
String[] valuesLocale = new String[pairs.size() / 2];
|
||||
String[]labelsLocale = new String[pairs.size() / 2];
|
||||
for (int i = 0; i < pairs.size(); i += 2) {
|
||||
labelsLocale[i / 2] = pairs.get(i);
|
||||
valuesLocale[i / 2] = pairs.get(i + 1);
|
||||
}
|
||||
values.put(l.getLanguage(), valuesLocale);
|
||||
labels.put(l.getLanguage(), labelsLocale);
|
||||
log.debug("Found pairs for name=" + pname + ",locale=" + l);
|
||||
} else {
|
||||
log.error("Failed to find any pairs for name=" + pname, new IllegalStateException());
|
||||
}
|
||||
log.debug("Found pairs for name=" + pname);
|
||||
} else {
|
||||
log.error("Failed to find any pairs for name=" + pname, new IllegalStateException());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) {
|
||||
public Choices getMatches(String query, int start, int limit, String locale) {
|
||||
init();
|
||||
|
||||
Locale currentLocale = I18nUtil.getSupportedLocale(locale);
|
||||
String[] valuesLocale = values.get(currentLocale.getLanguage());
|
||||
String[] labelsLocale = labels.get(currentLocale.getLanguage());
|
||||
int dflt = -1;
|
||||
Choice v[] = new Choice[values.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
v[i] = new Choice(values[i], values[i], labels[i]);
|
||||
if (values[i].equalsIgnoreCase(query)) {
|
||||
dflt = i;
|
||||
int found = 0;
|
||||
List<Choice> v = new ArrayList<Choice>();
|
||||
for (int i = 0; i < valuesLocale.length; ++i) {
|
||||
if (query == null || StringUtils.containsIgnoreCase(valuesLocale[i], query)) {
|
||||
if (found >= start && v.size() < limit) {
|
||||
v.add(new Choice(null, valuesLocale[i], labelsLocale[i]));
|
||||
if (valuesLocale[i].equalsIgnoreCase(query)) {
|
||||
dflt = i;
|
||||
}
|
||||
}
|
||||
found++;
|
||||
}
|
||||
}
|
||||
return new Choices(v, 0, v.length, Choices.CF_AMBIGUOUS, false, dflt);
|
||||
Choice[] vArray = new Choice[v.size()];
|
||||
return new Choices(v.toArray(vArray), start, found, Choices.CF_AMBIGUOUS, false, dflt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
public Choices getBestMatch(String text, String locale) {
|
||||
init();
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
if (text.equalsIgnoreCase(values[i])) {
|
||||
Locale currentLocale = I18nUtil.getSupportedLocale(locale);
|
||||
String[] valuesLocale = values.get(currentLocale.getLanguage());
|
||||
String[] labelsLocale = labels.get(currentLocale.getLanguage());
|
||||
for (int i = 0; i < valuesLocale.length; ++i) {
|
||||
if (text.equalsIgnoreCase(valuesLocale[i])) {
|
||||
Choice v[] = new Choice[1];
|
||||
v[0] = new Choice(String.valueOf(i), values[i], labels[i]);
|
||||
v[0] = new Choice(String.valueOf(i), valuesLocale[i], labelsLocale[i]);
|
||||
return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0);
|
||||
}
|
||||
}
|
||||
@@ -131,19 +187,31 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
public String getLabel(String key, String locale) {
|
||||
init();
|
||||
|
||||
// Get default if locale is empty
|
||||
if (StringUtils.isBlank(locale)) {
|
||||
locale = I18nUtil.getDefaultLocale().getLanguage();
|
||||
}
|
||||
|
||||
String[] labelsLocale = labels.get(locale);
|
||||
int pos = -1;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (values[i].equals(key)) {
|
||||
for (int i = 0; i < labelsLocale.length; i++) {
|
||||
if (labelsLocale[i].equals(key)) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos != -1) {
|
||||
return labels[pos];
|
||||
return labelsLocale[pos];
|
||||
} else {
|
||||
return "UNKNOWN KEY " + key;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScrollable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,9 @@ package org.dspace.content.authority;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
@@ -19,7 +21,6 @@ import javax.xml.xpath.XPathFactory;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.core.SelfNamedPlugin;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
@@ -54,25 +55,35 @@ import org.xml.sax.InputSource;
|
||||
* @author Michael B. Klein
|
||||
*/
|
||||
|
||||
public class DSpaceControlledVocabulary extends SelfNamedPlugin implements ChoiceAuthority {
|
||||
public class DSpaceControlledVocabulary extends SelfNamedPlugin implements HierarchicalAuthority {
|
||||
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DSpaceControlledVocabulary.class);
|
||||
protected static String xpathTemplate = "//node[contains(translate(@label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'," +
|
||||
"'abcdefghijklmnopqrstuvwxyz'),'%s')]";
|
||||
protected static String idTemplate = "//node[@id = '%s']";
|
||||
protected static String idParentTemplate = "//node[@id = '%s']/parent::isComposedBy";
|
||||
protected static String labelTemplate = "//node[@label = '%s']";
|
||||
protected static String idParentTemplate = "//node[@id = '%s']/parent::isComposedBy/parent::node";
|
||||
protected static String rootTemplate = "/node";
|
||||
protected static String pluginNames[] = null;
|
||||
|
||||
protected String vocabularyName = null;
|
||||
protected InputSource vocabulary = null;
|
||||
protected Boolean suggestHierarchy = true;
|
||||
protected Boolean suggestHierarchy = false;
|
||||
protected Boolean storeHierarchy = true;
|
||||
protected String hierarchyDelimiter = "::";
|
||||
protected Integer preloadLevel = 1;
|
||||
|
||||
public DSpaceControlledVocabulary() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean storeAuthorityInMetadata() {
|
||||
// For backward compatibility controlled vocabularies don't store the node id in
|
||||
// the metadatavalue
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String[] getPluginNames() {
|
||||
if (pluginNames == null) {
|
||||
initPluginNames();
|
||||
@@ -112,6 +123,7 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
||||
String configurationPrefix = "vocabulary.plugin." + vocabularyName;
|
||||
storeHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.store", storeHierarchy);
|
||||
suggestHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.suggest", suggestHierarchy);
|
||||
preloadLevel = config.getIntProperty(configurationPrefix + ".hierarchy.preloadLevel", preloadLevel);
|
||||
String configuredDelimiter = config.getProperty(configurationPrefix + ".delimiter");
|
||||
if (configuredDelimiter != null) {
|
||||
hierarchyDelimiter = configuredDelimiter.replaceAll("(^\"|\"$)", "");
|
||||
@@ -142,7 +154,7 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
|
||||
public Choices getMatches(String text, int start, int limit, String locale) {
|
||||
init();
|
||||
log.debug("Getting matches for '" + text + "'");
|
||||
String xpathExpression = "";
|
||||
@@ -151,59 +163,60 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
||||
xpathExpression += String.format(xpathTemplate, textHierarchy[i].replaceAll("'", "'").toLowerCase());
|
||||
}
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
Choice[] choices;
|
||||
int total = 0;
|
||||
List<Choice> choices = new ArrayList<Choice>();
|
||||
try {
|
||||
NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET);
|
||||
String[] authorities = new String[results.getLength()];
|
||||
String[] values = new String[results.getLength()];
|
||||
String[] labels = new String[results.getLength()];
|
||||
String[] parent = new String[results.getLength()];
|
||||
String[] notes = new String[results.getLength()];
|
||||
for (int i = 0; i < results.getLength(); i++) {
|
||||
Node node = results.item(i);
|
||||
readNode(authorities, values, labels, parent, notes, i, node);
|
||||
}
|
||||
int resultCount = labels.length - start;
|
||||
// limit = 0 means no limit
|
||||
if ((limit > 0) && (resultCount > limit)) {
|
||||
resultCount = limit;
|
||||
}
|
||||
choices = new Choice[resultCount];
|
||||
if (resultCount > 0) {
|
||||
for (int i = 0; i < resultCount; i++) {
|
||||
choices[i] = new Choice(authorities[start + i], values[start + i], labels[start + i]);
|
||||
if (StringUtils.isNotBlank(parent[i])) {
|
||||
choices[i].extras.put("parent", parent[i]);
|
||||
}
|
||||
if (StringUtils.isNotBlank(notes[i])) {
|
||||
choices[i].extras.put("note", notes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
total = results.getLength();
|
||||
choices = getChoicesFromNodeList(results, start, limit);
|
||||
} catch (XPathExpressionException e) {
|
||||
choices = new Choice[0];
|
||||
log.warn(e.getMessage(), e);
|
||||
return new Choices(true);
|
||||
}
|
||||
return new Choices(choices, 0, choices.length, Choices.CF_AMBIGUOUS, false);
|
||||
return new Choices(choices.toArray(new Choice[choices.size()]), start, total, Choices.CF_AMBIGUOUS,
|
||||
total > start + limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
public Choices getBestMatch(String text, String locale) {
|
||||
init();
|
||||
log.debug("Getting best match for '" + text + "'");
|
||||
return getMatches(field, text, collection, 0, 2, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
init();
|
||||
String xpathExpression = String.format(idTemplate, key);
|
||||
log.debug("Getting best matches for '" + text + "'");
|
||||
String xpathExpression = "";
|
||||
String[] textHierarchy = text.split(hierarchyDelimiter, -1);
|
||||
for (int i = 0; i < textHierarchy.length; i++) {
|
||||
xpathExpression += String.format(labelTemplate, textHierarchy[i].replaceAll("'", "'"));
|
||||
}
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
List<Choice> choices = new ArrayList<Choice>();
|
||||
try {
|
||||
Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE);
|
||||
return node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET);
|
||||
choices = getChoicesFromNodeList(results, 0, 1);
|
||||
} catch (XPathExpressionException e) {
|
||||
return ("");
|
||||
log.warn(e.getMessage(), e);
|
||||
return new Choices(true);
|
||||
}
|
||||
return new Choices(choices.toArray(new Choice[choices.size()]), 0, choices.size(), Choices.CF_AMBIGUOUS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String key, String locale) {
|
||||
return getNodeLabel(key, this.suggestHierarchy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue(String key, String locale) {
|
||||
return getNodeLabel(key, this.storeHierarchy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choice getChoice(String authKey, String locale) {
|
||||
Node node;
|
||||
try {
|
||||
node = getNode(authKey);
|
||||
} catch (XPathExpressionException e) {
|
||||
return null;
|
||||
}
|
||||
return createChoiceFromNode(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -212,81 +225,227 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choice getChoice(String fieldKey, String authKey, String locale) {
|
||||
public Choices getTopChoices(String authorityName, int start, int limit, String locale) {
|
||||
init();
|
||||
log.debug("Getting matches for '" + authKey + "'");
|
||||
String xpathExpression = String.format(idTemplate, authKey);
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
try {
|
||||
Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE);
|
||||
if (node != null) {
|
||||
String[] authorities = new String[1];
|
||||
String[] values = new String[1];
|
||||
String[] labels = new String[1];
|
||||
String[] parent = new String[1];
|
||||
String[] note = new String[1];
|
||||
readNode(authorities, values, labels, parent, note, 0, node);
|
||||
|
||||
if (values.length > 0) {
|
||||
Choice choice = new Choice(authorities[0], values[0], labels[0]);
|
||||
if (StringUtils.isNotBlank(parent[0])) {
|
||||
choice.extras.put("parent", parent[0]);
|
||||
}
|
||||
if (StringUtils.isNotBlank(note[0])) {
|
||||
choice.extras.put("note", note[0]);
|
||||
}
|
||||
return choice;
|
||||
}
|
||||
}
|
||||
} catch (XPathExpressionException e) {
|
||||
log.warn(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
String xpathExpression = rootTemplate;
|
||||
return getChoicesByXpath(xpathExpression, start, limit);
|
||||
}
|
||||
|
||||
private void readNode(String[] authorities, String[] values, String[] labels, String[] parent, String[] notes,
|
||||
int i, Node node) {
|
||||
@Override
|
||||
public Choices getChoicesByParent(String authorityName, String parentId, int start, int limit, String locale) {
|
||||
init();
|
||||
String xpathExpression = String.format(idTemplate, parentId);
|
||||
return getChoicesByXpath(xpathExpression, start, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choice getParentChoice(String authorityName, String childId, String locale) {
|
||||
init();
|
||||
try {
|
||||
String xpathExpression = String.format(idParentTemplate, childId);
|
||||
Choice choice = createChoiceFromNode(getNodeFromXPath(xpathExpression));
|
||||
return choice;
|
||||
} catch (XPathExpressionException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPreloadLevel() {
|
||||
return preloadLevel;
|
||||
}
|
||||
|
||||
private boolean isRootElement(Node node) {
|
||||
if (node != null && node.getOwnerDocument().getDocumentElement().equals(node)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Node getNode(String key) throws XPathExpressionException {
|
||||
init();
|
||||
String xpathExpression = String.format(idTemplate, key);
|
||||
Node node = getNodeFromXPath(xpathExpression);
|
||||
return node;
|
||||
}
|
||||
|
||||
private Node getNodeFromXPath(String xpathExpression) throws XPathExpressionException {
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE);
|
||||
return node;
|
||||
}
|
||||
|
||||
private List<Choice> getChoicesFromNodeList(NodeList results, int start, int limit) {
|
||||
List<Choice> choices = new ArrayList<Choice>();
|
||||
for (int i = 0; i < results.getLength(); i++) {
|
||||
if (i < start) {
|
||||
continue;
|
||||
}
|
||||
if (choices.size() == limit) {
|
||||
break;
|
||||
}
|
||||
Node node = results.item(i);
|
||||
Choice choice = new Choice(getAuthority(node), getLabel(node), getValue(node),
|
||||
isSelectable(node));
|
||||
choice.extras = addOtherInformation(getParent(node), getNote(node), getChildren(node), getAuthority(node));
|
||||
choices.add(choice);
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
|
||||
private Map<String, String> addOtherInformation(String parentCurr, String noteCurr,
|
||||
List<String> childrenCurr, String authorityCurr) {
|
||||
Map<String, String> extras = new HashMap<String, String>();
|
||||
if (StringUtils.isNotBlank(parentCurr)) {
|
||||
extras.put("parent", parentCurr);
|
||||
}
|
||||
if (StringUtils.isNotBlank(noteCurr)) {
|
||||
extras.put("note", noteCurr);
|
||||
}
|
||||
if (childrenCurr.size() > 0) {
|
||||
extras.put("hasChildren", "true");
|
||||
} else {
|
||||
extras.put("hasChildren", "false");
|
||||
}
|
||||
extras.put("id", authorityCurr);
|
||||
return extras;
|
||||
}
|
||||
|
||||
private String getNodeLabel(String key, boolean useHierarchy) {
|
||||
try {
|
||||
Node node = getNode(key);
|
||||
if (useHierarchy) {
|
||||
return this.buildString(node);
|
||||
} else {
|
||||
return node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
}
|
||||
} catch (XPathExpressionException e) {
|
||||
return ("");
|
||||
}
|
||||
}
|
||||
|
||||
private String getLabel(Node node) {
|
||||
String hierarchy = this.buildString(node);
|
||||
if (this.suggestHierarchy) {
|
||||
labels[i] = hierarchy;
|
||||
return hierarchy;
|
||||
} else {
|
||||
labels[i] = node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
}
|
||||
if (this.storeHierarchy) {
|
||||
values[i] = hierarchy;
|
||||
} else {
|
||||
values[i] = node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
return node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
}
|
||||
}
|
||||
|
||||
private String getValue(Node node) {
|
||||
String hierarchy = this.buildString(node);
|
||||
if (this.storeHierarchy) {
|
||||
return hierarchy;
|
||||
} else {
|
||||
return node.getAttributes().getNamedItem("label").getNodeValue();
|
||||
}
|
||||
}
|
||||
|
||||
private String getNote(Node node) {
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int ci = 0; ci < childNodes.getLength(); ci++) {
|
||||
Node firstChild = childNodes.item(ci);
|
||||
if (firstChild != null && "hasNote".equals(firstChild.getNodeName())) {
|
||||
String nodeValue = firstChild.getTextContent();
|
||||
if (StringUtils.isNotBlank(nodeValue)) {
|
||||
notes[i] = nodeValue;
|
||||
return nodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
Node idAttr = node.getAttributes().getNamedItem("id");
|
||||
if (null != idAttr) { // 'id' is optional
|
||||
authorities[i] = idAttr.getNodeValue();
|
||||
if (isHierarchical()) {
|
||||
Node parentN = node.getParentNode();
|
||||
if (parentN != null) {
|
||||
parentN = parentN.getParentNode();
|
||||
if (parentN != null) {
|
||||
Node parentIdAttr = parentN.getAttributes().getNamedItem("id");
|
||||
if (null != parentIdAttr) {
|
||||
parent[i] = parentIdAttr.getNodeValue();
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getChildren(Node node) {
|
||||
List<String> children = new ArrayList<String>();
|
||||
NodeList childNodes = node.getChildNodes();
|
||||
for (int ci = 0; ci < childNodes.getLength(); ci++) {
|
||||
Node firstChild = childNodes.item(ci);
|
||||
if (firstChild != null && "isComposedBy".equals(firstChild.getNodeName())) {
|
||||
for (int cii = 0; cii < firstChild.getChildNodes().getLength(); cii++) {
|
||||
Node childN = firstChild.getChildNodes().item(cii);
|
||||
if (childN != null && "node".equals(childN.getNodeName())) {
|
||||
Node childIdAttr = childN.getAttributes().getNamedItem("id");
|
||||
if (null != childIdAttr) {
|
||||
children.add(childIdAttr.getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
authorities[i] = null;
|
||||
parent[i] = null;
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
private boolean isSelectable(Node node) {
|
||||
Node selectableAttr = node.getAttributes().getNamedItem("selectable");
|
||||
if (null != selectableAttr) {
|
||||
return Boolean.valueOf(selectableAttr.getNodeValue());
|
||||
} else { // Default is true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private String getParent(Node node) {
|
||||
Node parentN = node.getParentNode();
|
||||
if (parentN != null) {
|
||||
parentN = parentN.getParentNode();
|
||||
if (parentN != null && !isRootElement(parentN)) {
|
||||
return buildString(parentN);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getAuthority(Node node) {
|
||||
Node idAttr = node.getAttributes().getNamedItem("id");
|
||||
if (null != idAttr) { // 'id' is optional
|
||||
return idAttr.getNodeValue();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Choices getChoicesByXpath(String xpathExpression, int start, int limit) {
|
||||
List<Choice> choices = new ArrayList<Choice>();
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
try {
|
||||
Node parentNode = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE);
|
||||
int count = 0;
|
||||
if (parentNode != null) {
|
||||
NodeList childNodes = (NodeList) xpath.evaluate(".//isComposedBy", parentNode, XPathConstants.NODE);
|
||||
if (null != childNodes) {
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node childNode = childNodes.item(i);
|
||||
if (childNode != null && "node".equals(childNode.getNodeName())) {
|
||||
if (count < start || choices.size() >= limit) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
count++;
|
||||
choices.add(createChoiceFromNode(childNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Choices(choices.toArray(new Choice[choices.size()]), start, count,
|
||||
Choices.CF_AMBIGUOUS, false);
|
||||
}
|
||||
} catch (XPathExpressionException e) {
|
||||
log.warn(e.getMessage(), e);
|
||||
return new Choices(true);
|
||||
}
|
||||
return new Choices(false);
|
||||
}
|
||||
|
||||
private Choice createChoiceFromNode(Node node) {
|
||||
if (node != null && !isRootElement(node)) {
|
||||
Choice choice = new Choice(getAuthority(node), getLabel(node), getValue(node),
|
||||
isSelectable(node));
|
||||
choice.extras = addOtherInformation(getParent(node), getNote(node),getChildren(node), getAuthority(node));
|
||||
return choice;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
|
||||
/**
|
||||
* Plugin interface that supplies an authority control mechanism for
|
||||
* one metadata field.
|
||||
*
|
||||
* @author Larry Stone
|
||||
* @see ChoiceAuthority
|
||||
*/
|
||||
public interface HierarchicalAuthority extends ChoiceAuthority {
|
||||
|
||||
/**
|
||||
* Get all values from the authority that match the preferred value.
|
||||
* Note that the offering was entered by the user and may contain
|
||||
* mixed/incorrect case, whitespace, etc so the plugin should be careful
|
||||
* to clean up user data before making comparisons.
|
||||
*
|
||||
* Value of a "Name" field will be in canonical DSpace person name format,
|
||||
* which is "Lastname, Firstname(s)", e.g. "Smith, John Q.".
|
||||
*
|
||||
* Some authorities with a small set of values may simply return the whole
|
||||
* set for any sample value, although it's a good idea to set the
|
||||
* defaultSelected index in the Choices instance to the choice, if any,
|
||||
* that matches the value.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
*/
|
||||
public Choices getTopChoices(String authorityName, int start, int limit, String locale);
|
||||
|
||||
/**
|
||||
* Get all values from the authority that match the preferred value.
|
||||
* Note that the offering was entered by the user and may contain
|
||||
* mixed/incorrect case, whitespace, etc so the plugin should be careful
|
||||
* to clean up user data before making comparisons.
|
||||
*
|
||||
* Value of a "Name" field will be in canonical DSpace person name format,
|
||||
* which is "Lastname, Firstname(s)", e.g. "Smith, John Q.".
|
||||
*
|
||||
* Some authorities with a small set of values may simply return the whole
|
||||
* set for any sample value, although it's a good idea to set the
|
||||
* defaultSelected index in the Choices instance to the choice, if any,
|
||||
* that matches the value.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param parentId user's value to match
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
*/
|
||||
public Choices getChoicesByParent(String authorityName, String parentId, int start, int limit, String locale);
|
||||
|
||||
/**
|
||||
* It returns the parent choice in the hierarchy if any
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param vocabularyId user's value to match
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choice object
|
||||
*/
|
||||
public Choice getParentChoice(String authorityName, String vocabularyId, String locale);
|
||||
|
||||
/**
|
||||
* Provides an hint for the UI to preload some levels to improve the UX. It
|
||||
* usually mean that these preloaded level will be shown expanded by default
|
||||
*/
|
||||
public Integer getPreloadLevel();
|
||||
|
||||
@Override
|
||||
default boolean isHierarchical() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@@ -1,166 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.DCInputsReader;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.content.Collection;
|
||||
|
||||
/**
|
||||
* This authority is registered automatically by the ChoiceAuthorityService for
|
||||
* all the metadata that use a value-pair or a vocabulary in the submission-form.xml
|
||||
*
|
||||
* It keeps a map of form-name vs ChoiceAuthority to delegate the execution of
|
||||
* the method to the specific ChoiceAuthority configured for the collection when
|
||||
* the same metadata have different vocabulary or value-pair on a collection
|
||||
* basis
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class InputFormSelfRegisterWrapperAuthority implements ChoiceAuthority {
|
||||
|
||||
private static Logger log =
|
||||
org.apache.logging.log4j.LogManager.getLogger(InputFormSelfRegisterWrapperAuthority.class);
|
||||
|
||||
private Map<String, ChoiceAuthority> delegates = new HashMap<String, ChoiceAuthority>();
|
||||
|
||||
private static DCInputsReader dci = null;
|
||||
|
||||
private void init() {
|
||||
try {
|
||||
if (dci == null) {
|
||||
dci = new DCInputsReader();
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error("Failed reading DCInputs initialization: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) {
|
||||
String formName;
|
||||
try {
|
||||
init();
|
||||
if (collection == null) {
|
||||
Set<Choice> choices = new HashSet<Choice>();
|
||||
//workaround search in all authority configured
|
||||
for (ChoiceAuthority ca : delegates.values()) {
|
||||
Choices tmp = ca.getMatches(field, query, null, start, limit, locale);
|
||||
if (tmp.total > 0) {
|
||||
Set<Choice> mySet = new HashSet<Choice>(Arrays.asList(tmp.values));
|
||||
choices.addAll(mySet);
|
||||
}
|
||||
}
|
||||
if (!choices.isEmpty()) {
|
||||
Choice[] results = new Choice[choices.size()];
|
||||
choices.toArray(results);
|
||||
return new Choices(results, 0, choices.size(), Choices.CF_AMBIGUOUS, false);
|
||||
}
|
||||
} else {
|
||||
formName = dci.getInputFormNameByCollectionAndField(collection, field);
|
||||
return delegates.get(formName).getMatches(field, query, collection, start, limit, locale);
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return new Choices(Choices.CF_NOTFOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
String formName;
|
||||
try {
|
||||
init();
|
||||
if (collection == null) {
|
||||
Set<Choice> choices = new HashSet<Choice>();
|
||||
//workaround search in all authority configured
|
||||
for (ChoiceAuthority ca : delegates.values()) {
|
||||
Choices tmp = ca.getBestMatch(field, text, null, locale);
|
||||
if (tmp.total > 0) {
|
||||
Set<Choice> mySet = new HashSet<Choice>(Arrays.asList(tmp.values));
|
||||
choices.addAll(mySet);
|
||||
}
|
||||
}
|
||||
if (!choices.isEmpty()) {
|
||||
Choice[] results = new Choice[choices.size() - 1];
|
||||
choices.toArray(results);
|
||||
return new Choices(results, 0, choices.size(), Choices.CF_UNCERTAIN, false);
|
||||
}
|
||||
} else {
|
||||
formName = dci.getInputFormNameByCollectionAndField(collection, field);
|
||||
return delegates.get(formName).getBestMatch(field, text, collection, locale);
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return new Choices(Choices.CF_NOTFOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
// TODO we need to manage REALLY the authority
|
||||
// WRONG BEHAVIOUR: now in each delegates can exists the same key with
|
||||
// different value
|
||||
for (ChoiceAuthority delegate : delegates.values()) {
|
||||
String label = delegate.getLabel(field, key, locale);
|
||||
if (StringUtils.isNotBlank(label)) {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
return "UNKNOWN KEY " + key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHierarchical() {
|
||||
// TODO we need to manage REALLY the authority
|
||||
// WRONG BEHAVIOUR: now in each delegates can exists the same key with
|
||||
// different value
|
||||
for (ChoiceAuthority delegate : delegates.values()) {
|
||||
return delegate.isHierarchical();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScrollable() {
|
||||
// TODO we need to manage REALLY the authority
|
||||
// WRONG BEHAVIOUR: now in each delegates can exists the same key with
|
||||
// different value
|
||||
for (ChoiceAuthority delegate : delegates.values()) {
|
||||
return delegate.isScrollable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasIdentifier() {
|
||||
// TODO we need to manage REALLY the authority
|
||||
// WRONG BEHAVIOUR: now in each delegates can exists the same key with
|
||||
// different value
|
||||
for (ChoiceAuthority delegate : delegates.values()) {
|
||||
return delegate.hasIdentifier();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Map<String, ChoiceAuthority> getDelegates() {
|
||||
return delegates;
|
||||
}
|
||||
|
||||
public void setDelegates(Map<String, ChoiceAuthority> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
}
|
@@ -14,12 +14,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.DCInput;
|
||||
import org.dspace.app.util.DCInputSet;
|
||||
import org.dspace.app.util.DCInputsReader;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.authority.service.MetadataAuthorityService;
|
||||
import org.dspace.content.service.MetadataFieldService;
|
||||
@@ -144,8 +139,6 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
||||
if (dmc >= Choices.CF_UNSET) {
|
||||
defaultMinConfidence = dmc;
|
||||
}
|
||||
|
||||
autoRegisterAuthorityFromInputReader();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +198,6 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Give the minimal level of confidence required to consider valid an authority value
|
||||
* for the given metadata.
|
||||
@@ -229,35 +221,4 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
private void autoRegisterAuthorityFromInputReader() {
|
||||
try {
|
||||
DCInputsReader dcInputsReader = new DCInputsReader();
|
||||
for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) {
|
||||
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput[] dcrows : dcinputs) {
|
||||
for (DCInput dcinput : dcrows) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
boolean req = ConfigurationManager
|
||||
.getBooleanProperty("authority.required." + fieldKey, false);
|
||||
controlled.put(fieldKey, true);
|
||||
isAuthorityRequired.put(fieldKey, req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
throw new IllegalStateException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,13 +7,13 @@
|
||||
*/
|
||||
package org.dspace.content.authority;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
|
||||
/**
|
||||
* This is a *very* stupid test fixture for authority control, and also
|
||||
* serves as a trivial example of an authority plugin implementation.
|
||||
*/
|
||||
public class SampleAuthority implements ChoiceAuthority {
|
||||
private String pluginInstanceName;
|
||||
|
||||
protected static String values[] = {
|
||||
"sun",
|
||||
"mon",
|
||||
@@ -35,7 +35,7 @@ public class SampleAuthority implements ChoiceAuthority {
|
||||
};
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String query, Collection collection, int start, int limit, String locale) {
|
||||
public Choices getMatches(String query, int start, int limit, String locale) {
|
||||
int dflt = -1;
|
||||
Choice v[] = new Choice[values.length];
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
@@ -48,7 +48,7 @@ public class SampleAuthority implements ChoiceAuthority {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
public Choices getBestMatch(String text, String locale) {
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
if (text.equalsIgnoreCase(values[i])) {
|
||||
Choice v[] = new Choice[1];
|
||||
@@ -60,7 +60,17 @@ public class SampleAuthority implements ChoiceAuthority {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
public String getLabel(String key, String locale) {
|
||||
return labels[Integer.parseInt(key)];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginInstanceName() {
|
||||
return pluginInstanceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginInstanceName(String name) {
|
||||
this.pluginInstanceName = name;
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -24,8 +25,9 @@ import org.dspace.authority.AuthorityValue;
|
||||
import org.dspace.authority.SolrAuthorityInterface;
|
||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
||||
import org.dspace.authority.service.AuthorityValueService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.NameAwarePlugin;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
@@ -35,7 +37,14 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
*/
|
||||
public class SolrAuthority implements ChoiceAuthority {
|
||||
/** the name assigned to the specific instance by the PluginService, @see {@link NameAwarePlugin} **/
|
||||
private String authorityName;
|
||||
|
||||
/**
|
||||
* the metadata managed by the plugin instance, derived from its authority name
|
||||
* in the form schema_element_qualifier
|
||||
*/
|
||||
private String field;
|
||||
protected SolrAuthorityInterface source =
|
||||
DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("AuthoritySource", SolrAuthorityInterface.class);
|
||||
@@ -45,8 +54,9 @@ public class SolrAuthority implements ChoiceAuthority {
|
||||
protected boolean externalResults = false;
|
||||
protected final AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance()
|
||||
.getAuthorityValueService();
|
||||
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale,
|
||||
protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance()
|
||||
.getConfigurationService();
|
||||
public Choices getMatches(String text, int start, int limit, String locale,
|
||||
boolean bestMatch) {
|
||||
if (limit == 0) {
|
||||
limit = 10;
|
||||
@@ -193,13 +203,13 @@ public class SolrAuthority implements ChoiceAuthority {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
|
||||
return getMatches(field, text, collection, start, limit, locale, true);
|
||||
public Choices getMatches(String text, int start, int limit, String locale) {
|
||||
return getMatches(text, start, limit, locale, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
||||
Choices matches = getMatches(field, text, collection, 0, 1, locale, false);
|
||||
public Choices getBestMatch(String text, String locale) {
|
||||
Choices matches = getMatches(text, 0, 1, locale, false);
|
||||
if (matches.values.length != 0 && !matches.values[0].value.equalsIgnoreCase(text)) {
|
||||
matches = new Choices(false);
|
||||
}
|
||||
@@ -207,7 +217,7 @@ public class SolrAuthority implements ChoiceAuthority {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
public String getLabel(String key, String locale) {
|
||||
try {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("requesting label for key " + key + " using locale " + locale);
|
||||
@@ -276,4 +286,23 @@ public class SolrAuthority implements ChoiceAuthority {
|
||||
public void addExternalResultsInNextMatches() {
|
||||
this.externalResults = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginInstanceName(String name) {
|
||||
authorityName = name;
|
||||
for (Entry conf : configurationService.getProperties().entrySet()) {
|
||||
if (StringUtils.startsWith((String) conf.getKey(), ChoiceAuthorityServiceImpl.CHOICES_PLUGIN_PREFIX)
|
||||
&& StringUtils.equals((String) conf.getValue(), authorityName)) {
|
||||
field = ((String) conf.getKey()).substring(ChoiceAuthorityServiceImpl.CHOICES_PLUGIN_PREFIX.length())
|
||||
.replace(".", "_");
|
||||
// exit the look immediately as we have found it
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginInstanceName() {
|
||||
return authorityName;
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.content.Collection;
|
||||
|
||||
/**
|
||||
* This is a *very* stupid test fixture for authority control with AuthorityVariantsSupport.
|
||||
@@ -19,6 +18,7 @@ import org.dspace.content.Collection;
|
||||
* @author Andrea Bollini (CILEA)
|
||||
*/
|
||||
public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport {
|
||||
private String pluginInstanceName;
|
||||
|
||||
@Override
|
||||
public List<String> getVariants(String key, String locale) {
|
||||
@@ -33,8 +33,7 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getMatches(String field, String text, Collection collection,
|
||||
int start, int limit, String locale) {
|
||||
public Choices getMatches(String text, int start, int limit, String locale) {
|
||||
Choices choices = new Choices(false);
|
||||
if (StringUtils.isNotBlank(text)) {
|
||||
|
||||
@@ -52,8 +51,7 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
||||
}
|
||||
|
||||
@Override
|
||||
public Choices getBestMatch(String field, String text, Collection collection,
|
||||
String locale) {
|
||||
public Choices getBestMatch(String text, String locale) {
|
||||
Choices choices = new Choices(false);
|
||||
if (StringUtils.isNotBlank(text)) {
|
||||
|
||||
@@ -70,10 +68,20 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel(String field, String key, String locale) {
|
||||
public String getLabel(String key, String locale) {
|
||||
if (StringUtils.isNotBlank(key)) {
|
||||
return key.replaceAll("authority", "label");
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginInstanceName() {
|
||||
return pluginInstanceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPluginInstanceName(String name) {
|
||||
this.pluginInstanceName = name;
|
||||
}
|
||||
}
|
||||
|
@@ -48,10 +48,10 @@ public interface ChoiceAuthorityService {
|
||||
* @param element element of metadata field
|
||||
* @param qualifier qualifier of metadata field
|
||||
* @return the name of the choice authority associated with the specified
|
||||
* metadata. Throw IllegalArgumentException if the supplied metadat
|
||||
* metadata. Throw IllegalArgumentException if the supplied metadata
|
||||
* is not associated with an authority choice
|
||||
*/
|
||||
public String getChoiceAuthorityName(String schema, String element, String qualifier);
|
||||
public String getChoiceAuthorityName(String schema, String element, String qualifier, Collection collection);
|
||||
|
||||
/**
|
||||
* Wrapper that calls getMatches method of the plugin corresponding to
|
||||
@@ -112,30 +112,33 @@ public interface ChoiceAuthorityService {
|
||||
* the metadata field defined by schema,element,qualifier.
|
||||
*
|
||||
* @param metadataValue metadata value
|
||||
* @param collection Collection owner of Item
|
||||
* @param locale explicit localization key if available
|
||||
* @return label
|
||||
*/
|
||||
public String getLabel(MetadataValue metadataValue, String locale);
|
||||
public String getLabel(MetadataValue metadataValue, Collection collection, String locale);
|
||||
|
||||
/**
|
||||
* Wrapper that calls getLabel method of the plugin corresponding to
|
||||
* the metadata field defined by single field key.
|
||||
*
|
||||
* @param fieldKey single string identifying metadata field
|
||||
* @param collection Collection owner of Item
|
||||
* @param locale explicit localization key if available
|
||||
* @param authKey authority key
|
||||
* @return label
|
||||
*/
|
||||
public String getLabel(String fieldKey, String authKey, String locale);
|
||||
public String getLabel(String fieldKey, Collection collection, String authKey, String locale);
|
||||
|
||||
/**
|
||||
* Predicate, is there a Choices configuration of any kind for the
|
||||
* given metadata field?
|
||||
*
|
||||
* @param fieldKey single string identifying metadata field
|
||||
* @param collection Collection owner of Item
|
||||
* @return true if choices are configured for this field.
|
||||
*/
|
||||
public boolean isChoicesConfigured(String fieldKey);
|
||||
public boolean isChoicesConfigured(String fieldKey, Collection collection);
|
||||
|
||||
/**
|
||||
* Get the presentation keyword (should be "lookup", "select" or "suggest", but this
|
||||
@@ -160,12 +163,14 @@ public interface ChoiceAuthorityService {
|
||||
* @param metadataValue metadata value
|
||||
* @return List of variants
|
||||
*/
|
||||
public List<String> getVariants(MetadataValue metadataValue);
|
||||
|
||||
public String getChoiceMetadatabyAuthorityName(String name);
|
||||
|
||||
public Choice getChoice(String fieldKey, String authKey, String locale);
|
||||
public List<String> getVariants(MetadataValue metadataValue, Collection collection);
|
||||
|
||||
/**
|
||||
* Return the ChoiceAuthority instance identified by the specified name
|
||||
*
|
||||
* @param authorityName the ChoiceAuthority instance name
|
||||
* @return the ChoiceAuthority identified by the specified name
|
||||
*/
|
||||
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName);
|
||||
|
||||
/**
|
||||
@@ -173,4 +178,49 @@ public interface ChoiceAuthorityService {
|
||||
*/
|
||||
public void clearCache();
|
||||
|
||||
/**
|
||||
* Should we store the authority key (if any) for such field key and collection?
|
||||
*
|
||||
* @param fieldKey single string identifying metadata field
|
||||
* @param collection Collection owner of Item or where the item is submitted to
|
||||
* @return true if the configuration allows to store the authority value
|
||||
*/
|
||||
public boolean storeAuthority(String fieldKey, Collection collection);
|
||||
|
||||
/**
|
||||
* Wrapper that calls getChoicesByParent method of the plugin.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param parentId parent Id
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
* @see org.dspace.content.authority.ChoiceAuthority#getChoicesByParent(java.lang.String, java.lang.String,
|
||||
* int, int, java.lang.String)
|
||||
*/
|
||||
public Choices getChoicesByParent(String authorityName, String parentId, int start, int limit, String locale);
|
||||
|
||||
/**
|
||||
* Wrapper that calls getTopChoices method of the plugin.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param start choice at which to start, 0 is first.
|
||||
* @param limit maximum number of choices to return, 0 for no limit.
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return a Choices object (never null).
|
||||
* @see org.dspace.content.authority.ChoiceAuthority#getTopChoices(java.lang.String, int, int, java.lang.String)
|
||||
*/
|
||||
public Choices getTopChoices(String authorityName, int start, int limit, String locale);
|
||||
|
||||
/**
|
||||
* Return the direct parent of an entry identified by its id in an hierarchical
|
||||
* authority.
|
||||
*
|
||||
* @param authorityName authority name
|
||||
* @param vocabularyId child id
|
||||
* @param locale explicit localization key if available, or null
|
||||
* @return the parent Choice object if any
|
||||
*/
|
||||
public Choice getParentChoice(String authorityName, String vocabularyId, String locale);
|
||||
}
|
||||
|
@@ -191,6 +191,23 @@ public class I18nUtil {
|
||||
return supportedLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate supported Locale according for a given Locale If
|
||||
* no appropriate supported locale is found, the DEFAULTLOCALE is used
|
||||
*
|
||||
* @param locale String to find the corresponding Locale
|
||||
* @return supportedLocale
|
||||
* Locale for session according to locales supported by this DSpace instance as set in dspace.cfg
|
||||
*/
|
||||
public static Locale getSupportedLocale(String locale) {
|
||||
Locale currentLocale = null;
|
||||
if (locale != null) {
|
||||
currentLocale = I18nUtil.getSupportedLocale(new Locale(locale));
|
||||
} else {
|
||||
currentLocale = I18nUtil.getDefaultLocale();
|
||||
}
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the appropriate localized version of submission-forms.xml according to language settings
|
||||
|
@@ -345,8 +345,8 @@ public class LegacyPluginServiceImpl implements PluginService {
|
||||
" for interface=" + iname +
|
||||
" pluginName=" + name);
|
||||
Object result = pluginClass.newInstance();
|
||||
if (result instanceof SelfNamedPlugin) {
|
||||
((SelfNamedPlugin) result).setPluginInstanceName(name);
|
||||
if (result instanceof NameAwarePlugin) {
|
||||
((NameAwarePlugin) result).setPluginInstanceName(name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.core;
|
||||
|
||||
/**
|
||||
* This is the interface that should be implemented by all the named plugin that
|
||||
* like to be aware of their name
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
* @version $Revision$
|
||||
* @see org.dspace.core.service.PluginService
|
||||
*/
|
||||
public interface NameAwarePlugin {
|
||||
|
||||
/**
|
||||
* Get the instance's particular name.
|
||||
* Returns the name by which the class was chosen when
|
||||
* this instance was created. Only works for instances created
|
||||
* by <code>PluginService</code>, or if someone remembers to call <code>setPluginName.</code>
|
||||
* <p>
|
||||
* Useful when the implementation class wants to be configured differently
|
||||
* when it is invoked under different names.
|
||||
*
|
||||
* @return name or null if not available.
|
||||
*/
|
||||
public String getPluginInstanceName();
|
||||
|
||||
/**
|
||||
* Set the name under which this plugin was instantiated.
|
||||
* Not to be invoked by application code, it is
|
||||
* called automatically by <code>PluginService.getNamedPlugin()</code>
|
||||
* when the plugin is instantiated.
|
||||
*
|
||||
* @param name -- name used to select this class.
|
||||
*/
|
||||
public void setPluginInstanceName(String name);
|
||||
}
|
@@ -28,7 +28,7 @@ package org.dspace.core;
|
||||
* @version $Revision$
|
||||
* @see org.dspace.core.service.PluginService
|
||||
*/
|
||||
public abstract class SelfNamedPlugin {
|
||||
public abstract class SelfNamedPlugin implements NameAwarePlugin {
|
||||
// the specific alias used to find the class that created this instance.
|
||||
private String myName = null;
|
||||
|
||||
@@ -52,30 +52,13 @@ public abstract class SelfNamedPlugin {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance's particular name.
|
||||
* Returns the name by which the class was chosen when
|
||||
* this instance was created. Only works for instances created
|
||||
* by <code>PluginService</code>, or if someone remembers to call <code>setPluginName.</code>
|
||||
* <p>
|
||||
* Useful when the implementation class wants to be configured differently
|
||||
* when it is invoked under different names.
|
||||
*
|
||||
* @return name or null if not available.
|
||||
*/
|
||||
@Override
|
||||
public String getPluginInstanceName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name under which this plugin was instantiated.
|
||||
* Not to be invoked by application code, it is
|
||||
* called automatically by <code>PluginService.getNamedPlugin()</code>
|
||||
* when the plugin is instantiated.
|
||||
*
|
||||
* @param name -- name used to select this class.
|
||||
*/
|
||||
protected void setPluginInstanceName(String name) {
|
||||
@Override
|
||||
public void setPluginInstanceName(String name) {
|
||||
myName = name;
|
||||
}
|
||||
}
|
||||
|
@@ -17,6 +17,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.common.SolrInputDocument;
|
||||
import org.dspace.browse.BrowseException;
|
||||
import org.dspace.browse.BrowseIndex;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
@@ -63,7 +64,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
||||
return;
|
||||
}
|
||||
Item item = ((IndexableItem) indexableObject).getIndexedObject();
|
||||
|
||||
Collection collection = item.getOwningCollection();
|
||||
// Get the currently configured browse indexes
|
||||
BrowseIndex[] bis;
|
||||
try {
|
||||
@@ -175,7 +176,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
||||
true);
|
||||
if (!ignorePrefered) {
|
||||
preferedLabel = choiceAuthorityService
|
||||
.getLabel(values.get(x), values.get(x).getLanguage());
|
||||
.getLabel(values.get(x), collection, values.get(x).getLanguage());
|
||||
}
|
||||
List<String> variants = null;
|
||||
|
||||
@@ -195,7 +196,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
||||
if (!ignoreVariants) {
|
||||
variants = choiceAuthorityService
|
||||
.getVariants(
|
||||
values.get(x));
|
||||
values.get(x), collection);
|
||||
}
|
||||
|
||||
if (StringUtils
|
||||
|
@@ -173,6 +173,8 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
||||
public void addDiscoveryFields(SolrInputDocument doc, Context context, Item item,
|
||||
List<DiscoveryConfiguration> discoveryConfigurations)
|
||||
throws SQLException, IOException {
|
||||
// use the item service to retrieve the owning collection also for inprogress submission
|
||||
Collection collection = (Collection) itemService.getParentObject(context, item);
|
||||
//Keep a list of our sort values which we added, sort values can only be added once
|
||||
List<String> sortFieldsAdded = new ArrayList<>();
|
||||
Map<String, List<DiscoverySearchFilter>> searchFilters = null;
|
||||
@@ -359,7 +361,7 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
||||
if (!ignorePrefered) {
|
||||
|
||||
preferedLabel = choiceAuthorityService
|
||||
.getLabel(meta, meta.getLanguage());
|
||||
.getLabel(meta, collection, meta.getLanguage());
|
||||
}
|
||||
|
||||
boolean ignoreVariants =
|
||||
@@ -375,7 +377,7 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
||||
true);
|
||||
if (!ignoreVariants) {
|
||||
variants = choiceAuthorityService
|
||||
.getVariants(meta);
|
||||
.getVariants(meta, collection);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -109,6 +109,11 @@ plugin.sequence.java.util.Collection = \
|
||||
java.util.Stack, \
|
||||
java.util.TreeSet
|
||||
|
||||
# Enable a test authority control on dc.language.iso field
|
||||
choices.plugin.dc.language.iso = common_iso_languages
|
||||
choices.presentation.dc.language.iso = select
|
||||
authority.controlled.dc.language.iso = true
|
||||
|
||||
###########################################
|
||||
# PROPERTIES USED TO TEST CONFIGURATION #
|
||||
# PROPERTY EXPOSURE VIA REST #
|
||||
|
@@ -282,6 +282,70 @@ it, please enter the types and the actual numbers or codes.</hint>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="languagetest">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<label>Author</label>
|
||||
<input-type>name</input-type>
|
||||
<repeatable>false</repeatable>
|
||||
<required>You must enter at least the author.</required>
|
||||
<hint>Enter the names of the authors of this item in the form Lastname, Firstname [i.e. Smith, Josh or Smith, J].</hint>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>person</dc-schema>
|
||||
<dc-element>affiliation</dc-element>
|
||||
<dc-qualifier>name</dc-qualifier>
|
||||
<label>Affiliation</label>
|
||||
<input-type>onebox</input-type>
|
||||
<repeatable>false</repeatable>
|
||||
<required />
|
||||
<hint>Enter the affiliation of the author as stated on the publication.</hint>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="sampleauthority">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Author</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Author field that can be associated with an authority providing suggestion</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>editor</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Editor</label>
|
||||
<input-type>name</input-type>
|
||||
<hint>Editor field that can be associated with an authority providing the special name lookup</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>subject</dc-element>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Subject</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Subject field that can be associated with an authority providing lookup</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
</form-definitions>
|
||||
|
||||
|
||||
|
@@ -490,8 +490,8 @@ public class ItemTest extends AbstractDSpaceObjectTest {
|
||||
// Set the item to have two pieces of metadata for dc.type and dc2.type
|
||||
String dcType = "DC-TYPE";
|
||||
String testType = "TEST-TYPE";
|
||||
itemService.addMetadata(context, it, "dc", "type", null, null, dcType, "accepted", 0);
|
||||
itemService.addMetadata(context, it, "test", "type", null, null, testType, "accepted", 0);
|
||||
itemService.addMetadata(context, it, "dc", "type", null, null, dcType);
|
||||
itemService.addMetadata(context, it, "test", "type", null, null, testType);
|
||||
|
||||
// Check that only one is returned when we ask for all dc.type values
|
||||
List<MetadataValue> values = itemService.getMetadata(it, "dc", "type", null, null);
|
||||
|
@@ -78,7 +78,7 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest {
|
||||
String text = "north 40";
|
||||
Collection collection = null;
|
||||
int start = 0;
|
||||
int limit = 0;
|
||||
int limit = 10;
|
||||
String locale = null;
|
||||
// This "farm" Controlled Vocab is included in TestEnvironment data
|
||||
// (under /src/test/data/dspaceFolder/) and it should be auto-loaded
|
||||
@@ -86,8 +86,7 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest {
|
||||
DSpaceControlledVocabulary instance = (DSpaceControlledVocabulary)
|
||||
CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(Class.forName(PLUGIN_INTERFACE), "farm");
|
||||
assertNotNull(instance);
|
||||
Choices result = instance.getMatches(field, text, collection, start,
|
||||
limit, locale);
|
||||
Choices result = instance.getMatches(text, start, limit, locale);
|
||||
assertEquals("the farm::north 40", result.values[0].value);
|
||||
}
|
||||
|
||||
|
@@ -149,7 +149,7 @@ public class RestResourceController implements InitializingBean {
|
||||
* @return single DSpaceResource
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT)
|
||||
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
public HALResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
@PathVariable Integer id) {
|
||||
return findOneInternal(apiCategory, model, id);
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public class RestResourceController implements InitializingBean {
|
||||
* @return single DSpaceResource
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG)
|
||||
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
public HALResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
@PathVariable String id) {
|
||||
return findOneInternal(apiCategory, model, id);
|
||||
}
|
||||
@@ -200,7 +200,7 @@ public class RestResourceController implements InitializingBean {
|
||||
* @return single DSpaceResource
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
|
||||
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
public HALResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
|
||||
@PathVariable UUID uuid) {
|
||||
return findOneInternal(apiCategory, model, uuid);
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public class RestResourceController implements InitializingBean {
|
||||
* @param id Identifier from request
|
||||
* @return single DSpaceResource
|
||||
*/
|
||||
private <ID extends Serializable> DSpaceResource<RestAddressableModel> findOneInternal(String apiCategory,
|
||||
private <ID extends Serializable> HALResource<RestAddressableModel> findOneInternal(String apiCategory,
|
||||
String model, ID id) {
|
||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
Optional<RestAddressableModel> modelObject = Optional.empty();
|
||||
@@ -799,7 +799,7 @@ public class RestResourceController implements InitializingBean {
|
||||
Method linkMethod = utils.requireMethod(linkRepository.getClass(), linkRest.method());
|
||||
try {
|
||||
if (Page.class.isAssignableFrom(linkMethod.getReturnType())) {
|
||||
Page<? extends RestModel> pageResult = (Page<? extends RestAddressableModel>) linkMethod
|
||||
Page<? extends RestModel> pageResult = (Page<? extends RestModel>) linkMethod
|
||||
.invoke(linkRepository, request, uuid, page, utils.obtainProjection());
|
||||
|
||||
if (pageResult == null) {
|
||||
@@ -823,8 +823,8 @@ public class RestResourceController implements InitializingBean {
|
||||
return new EntityModel(new EmbeddedPage(link.getHref(),
|
||||
pageResult.map(converter::toResource), null, subpath));
|
||||
} else {
|
||||
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request, uuid, page,
|
||||
utils.obtainProjection());
|
||||
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request,
|
||||
uuid, page, utils.obtainProjection());
|
||||
if (object == null) {
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
return null;
|
||||
@@ -846,7 +846,7 @@ public class RestResourceController implements InitializingBean {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
RestAddressableModel modelObject = repository.findById(uuid).orElse(null);
|
||||
RestModel modelObject = repository.findById(uuid).orElse(null);
|
||||
|
||||
if (modelObject == null) {
|
||||
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
|
||||
|
@@ -115,14 +115,16 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
||||
String inputType = dcinput.getInputType();
|
||||
|
||||
SelectableMetadata selMd = new SelectableMetadata();
|
||||
if (authorityUtils.isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier())) {
|
||||
if (isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(),
|
||||
dcinput.getPairsType(), dcinput.getVocabulary())) {
|
||||
inputRest.setType(getPresentation(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier(), inputType));
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
selMd.setControlledVocabulary(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier(), dcinput.getPairsType(),
|
||||
dcinput.getVocabulary()));
|
||||
selMd.setClosed(
|
||||
authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier()));
|
||||
isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(),
|
||||
dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||
} else {
|
||||
inputRest.setType(inputType);
|
||||
}
|
||||
@@ -139,10 +141,10 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
||||
selMd.setMetadata(org.dspace.core.Utils
|
||||
.standardize(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1), "."));
|
||||
if (authorityUtils.isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier())) {
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
selMd.setControlledVocabulary(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
pairs.get(idx + 1), dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||
selMd.setClosed(authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier()));
|
||||
selMd.setClosed(isClosed(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier(), null, dcinput.getVocabulary()));
|
||||
}
|
||||
selectableMetadata.add(selMd);
|
||||
}
|
||||
@@ -185,7 +187,8 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
||||
return INPUT_TYPE_LOOKUP;
|
||||
}
|
||||
} else if (INPUT_TYPE_NAME.equals(inputType)) {
|
||||
if (AuthorityUtils.PRESENTATION_TYPE_LOOKUP.equals(presentation)) {
|
||||
if (AuthorityUtils.PRESENTATION_TYPE_LOOKUP.equals(presentation) ||
|
||||
AuthorityUtils.PRESENTATION_TYPE_AUTHORLOOKUP.equals(presentation)) {
|
||||
return INPUT_TYPE_LOOKUP_NAME;
|
||||
}
|
||||
}
|
||||
@@ -203,6 +206,22 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
||||
return authorityUtils.getAuthorityName(schema, element, qualifier);
|
||||
}
|
||||
|
||||
private boolean isClosed(String schema, String element, String qualifier, String valuePairsName,
|
||||
String vocabularyName) {
|
||||
if (StringUtils.isNotBlank(valuePairsName) || StringUtils.isNotBlank(vocabularyName)) {
|
||||
return true;
|
||||
}
|
||||
return authorityUtils.isClosed(schema, element, qualifier);
|
||||
}
|
||||
|
||||
private boolean isChoice(String schema, String element, String qualifier, String valuePairsName,
|
||||
String vocabularyName) {
|
||||
if (StringUtils.isNotBlank(valuePairsName) || StringUtils.isNotBlank(vocabularyName)) {
|
||||
return true;
|
||||
}
|
||||
return authorityUtils.isChoice(schema, element, qualifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<DCInputSet> getModelClass() {
|
||||
return DCInputSet.class;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
@@ -22,16 +22,17 @@ import org.springframework.stereotype.Component;
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component
|
||||
public class AuthorityEntryRestConverter implements DSpaceConverter<Choice, AuthorityEntryRest> {
|
||||
public class VocabularyEntryDetailsRestConverter implements DSpaceConverter<Choice, VocabularyEntryDetailsRest> {
|
||||
|
||||
@Override
|
||||
public AuthorityEntryRest convert(Choice choice, Projection projection) {
|
||||
AuthorityEntryRest entry = new AuthorityEntryRest();
|
||||
public VocabularyEntryDetailsRest convert(Choice choice, Projection projection) {
|
||||
VocabularyEntryDetailsRest entry = new VocabularyEntryDetailsRest();
|
||||
entry.setProjection(projection);
|
||||
entry.setValue(choice.value);
|
||||
entry.setDisplay(choice.label);
|
||||
entry.setId(choice.authority);
|
||||
entry.setOtherInformation(choice.extras);
|
||||
entry.setSelectable(choice.selectable);
|
||||
return entry;
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.rest.converter;
|
||||
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
@@ -23,15 +23,15 @@ import org.springframework.stereotype.Component;
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component
|
||||
public class AuthorityRestConverter implements DSpaceConverter<ChoiceAuthority, AuthorityRest> {
|
||||
public class VocabularyRestConverter implements DSpaceConverter<ChoiceAuthority, VocabularyRest> {
|
||||
|
||||
@Override
|
||||
public AuthorityRest convert(ChoiceAuthority step, Projection projection) {
|
||||
AuthorityRest authorityRest = new AuthorityRest();
|
||||
public VocabularyRest convert(ChoiceAuthority authority, Projection projection) {
|
||||
VocabularyRest authorityRest = new VocabularyRest();
|
||||
authorityRest.setProjection(projection);
|
||||
authorityRest.setHierarchical(step.isHierarchical());
|
||||
authorityRest.setScrollable(step.isScrollable());
|
||||
authorityRest.setIdentifier(step.hasIdentifier());
|
||||
authorityRest.setHierarchical(authority.isHierarchical());
|
||||
authorityRest.setScrollable(authority.isScrollable());
|
||||
authorityRest.setPreloadLevel(authority.getPreloadLevel());
|
||||
return authorityRest;
|
||||
}
|
||||
|
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* This is the exception to capture details about a not existing linked resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "This link is not found in the system")
|
||||
public class LinkNotFoundException extends RuntimeException {
|
||||
String apiCategory;
|
||||
String model;
|
||||
String id;
|
||||
|
||||
public LinkNotFoundException(String apiCategory, String model, String id) {
|
||||
this.apiCategory = apiCategory;
|
||||
this.model = model;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
@@ -1,66 +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.link;
|
||||
|
||||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.atteo.evo.inflector.English;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.hateoas.AuthorityEntryResource;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.IanaLinkRelations;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* This class' purpose is to provide a factory to add links to the AuthorityEntryResource. The addLinks factory will
|
||||
* be called
|
||||
* from the HalLinkService class addLinks method.
|
||||
*/
|
||||
@Component
|
||||
public class AuthorityEntryHalLinkFactory extends HalLinkFactory<AuthorityEntryResource, RestResourceController> {
|
||||
|
||||
protected void addLinks(final AuthorityEntryResource halResource, final Pageable pageable,
|
||||
final LinkedList<Link> list) throws Exception {
|
||||
AuthorityEntryRest entry = halResource.getContent();
|
||||
|
||||
if (entry.getOtherInformation() != null) {
|
||||
if (entry.getOtherInformation().containsKey(AuthorityUtils.RESERVED_KEYMAP_PARENT)) {
|
||||
UriComponentsBuilder uriComponentsBuilder = linkTo(
|
||||
getMethodOn(AuthorityRest.CATEGORY, AuthorityRest.NAME)
|
||||
.findRel(null, null, AuthorityRest.CATEGORY,
|
||||
English.plural(AuthorityRest.NAME),
|
||||
entry.getAuthorityName() + "/" + AuthorityRest.ENTRY,
|
||||
entry.getOtherInformation().get(AuthorityUtils.RESERVED_KEYMAP_PARENT), null, null))
|
||||
.toUriComponentsBuilder();
|
||||
|
||||
list.add(buildLink(AuthorityUtils.RESERVED_KEYMAP_PARENT, uriComponentsBuilder.build().toString()));
|
||||
}
|
||||
}
|
||||
String selfLinkString = linkTo(
|
||||
getMethodOn().findOne(entry.getCategory(), English.plural(entry.getType()), entry.getAuthorityName()))
|
||||
.toUriComponentsBuilder().build().toString() + "/entryValues/" + entry.getId();
|
||||
list.add(buildLink(IanaLinkRelations.SELF.value(), selfLinkString));
|
||||
}
|
||||
|
||||
protected Class<RestResourceController> getControllerClass() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
protected Class<AuthorityEntryResource> getResourceClass() {
|
||||
return AuthorityEntryResource.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -21,7 +21,6 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
public class SubmissionFormInputTypeRest {
|
||||
private String type;
|
||||
private String regex;
|
||||
private AuthorityRest authority;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
@@ -39,11 +38,4 @@ public class SubmissionFormInputTypeRest {
|
||||
this.regex = regex;
|
||||
}
|
||||
|
||||
public AuthorityRest getAuthority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
public void setAuthority(AuthorityRest authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
}
|
||||
|
@@ -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/
|
||||
*/
|
||||
package org.dspace.app.rest.model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* The Vocabulary Entry Details REST Resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@LinksRest(links = {
|
||||
@LinkRest(name = VocabularyEntryDetailsRest.PARENT, method = "getParent"),
|
||||
@LinkRest(name = VocabularyEntryDetailsRest.CHILDREN, method = "getChildren")
|
||||
})
|
||||
public class VocabularyEntryDetailsRest extends BaseObjectRest<String> {
|
||||
public static final String NAME = "vocabularyEntryDetail";
|
||||
public static final String PARENT = "parent";
|
||||
public static final String CHILDREN = "children";
|
||||
private String display;
|
||||
private String value;
|
||||
private Map<String, String> otherInformation;
|
||||
private boolean selectable;
|
||||
@JsonIgnore
|
||||
private boolean inHierarchicalVocabulary = false;
|
||||
|
||||
@JsonIgnore
|
||||
private String vocabularyName;
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(String value) {
|
||||
this.display = value;
|
||||
}
|
||||
|
||||
public Map<String, String> getOtherInformation() {
|
||||
return otherInformation;
|
||||
}
|
||||
|
||||
public void setOtherInformation(Map<String, String> otherInformation) {
|
||||
this.otherInformation = otherInformation;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
public String getVocabularyName() {
|
||||
return vocabularyName;
|
||||
}
|
||||
|
||||
public void setVocabularyName(String vocabularyName) {
|
||||
this.vocabularyName = vocabularyName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return VocabularyRest.CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return VocabularyEntryDetailsRest.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
public Boolean isSelectable() {
|
||||
return selectable;
|
||||
}
|
||||
|
||||
public void setSelectable(Boolean selectable) {
|
||||
this.selectable = selectable;
|
||||
}
|
||||
|
||||
public void setInHierarchicalVocabulary(boolean isInHierarchicalVocabulary) {
|
||||
this.inHierarchicalVocabulary = isInHierarchicalVocabulary;
|
||||
}
|
||||
|
||||
public boolean isInHierarchicalVocabulary() {
|
||||
return inHierarchicalVocabulary;
|
||||
}
|
||||
}
|
@@ -10,30 +10,28 @@ package org.dspace.app.rest.model;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* The Authority Entry REST Resource
|
||||
* An entry in a Vocabulary
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class AuthorityEntryRest extends RestAddressableModel {
|
||||
public static final String NAME = "authorityEntry";
|
||||
private String id;
|
||||
public class VocabularyEntryRest implements RestModel {
|
||||
public static final String NAME = "vocabularyEntry";
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
private String authority;
|
||||
private String display;
|
||||
private String value;
|
||||
private Map<String, String> otherInformation;
|
||||
|
||||
/**
|
||||
* The Vocabulary Entry Details resource if available related to this entry
|
||||
*/
|
||||
@JsonIgnore
|
||||
private String authorityName;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
private VocabularyEntryDetailsRest vocabularyEntryDetailsRest;
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
@@ -59,31 +57,24 @@ public class AuthorityEntryRest extends RestAddressableModel {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static String getName() {
|
||||
return NAME;
|
||||
public void setAuthority(String authority) {
|
||||
this.authority = authority;
|
||||
}
|
||||
|
||||
public String getAuthorityName() {
|
||||
return authorityName;
|
||||
public String getAuthority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
public void setAuthorityName(String authorityName) {
|
||||
this.authorityName = authorityName;
|
||||
public void setVocabularyEntryDetailsRest(VocabularyEntryDetailsRest vocabularyEntryDetailsRest) {
|
||||
this.vocabularyEntryDetailsRest = vocabularyEntryDetailsRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return AuthorityRest.CATEGORY;
|
||||
public VocabularyEntryDetailsRest getVocabularyEntryDetailsRest() {
|
||||
return vocabularyEntryDetailsRest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return AuthorityRest.NAME;
|
||||
return VocabularyEntryRest.NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
|
||||
}
|
@@ -10,25 +10,20 @@ package org.dspace.app.rest.model;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* The authority REST resource
|
||||
* The vocabulary REST resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@LinksRest(links = {
|
||||
@LinkRest(name = AuthorityRest.ENTRIES,
|
||||
method = "query"
|
||||
@LinkRest(name = VocabularyRest.ENTRIES,
|
||||
method = "filter"
|
||||
),
|
||||
@LinkRest(
|
||||
name = AuthorityRest.ENTRY,
|
||||
method = "getResource"
|
||||
)
|
||||
})
|
||||
public class AuthorityRest extends BaseObjectRest<String> {
|
||||
public class VocabularyRest extends BaseObjectRest<String> {
|
||||
|
||||
public static final String NAME = "authority";
|
||||
public static final String CATEGORY = RestAddressableModel.INTEGRATION;
|
||||
public static final String NAME = "vocabulary";
|
||||
public static final String CATEGORY = RestAddressableModel.SUBMISSION;
|
||||
public static final String ENTRIES = "entries";
|
||||
public static final String ENTRY = "entryValues";
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -36,7 +31,7 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
||||
|
||||
private boolean hierarchical;
|
||||
|
||||
private boolean identifier;
|
||||
private Integer preloadLevel;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
@@ -67,6 +62,14 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
||||
this.hierarchical = hierarchical;
|
||||
}
|
||||
|
||||
public Integer getPreloadLevel() {
|
||||
return preloadLevel;
|
||||
}
|
||||
|
||||
public void setPreloadLevel(Integer preloadLevel) {
|
||||
this.preloadLevel = preloadLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return NAME;
|
||||
@@ -81,12 +84,4 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
||||
public String getCategory() {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
public boolean hasIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public void setIdentifier(boolean identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
}
|
@@ -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.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
|
||||
/**
|
||||
* Authority Rest HAL Resource. The HAL Resource wraps the REST Resource adding
|
||||
* support for the links and embedded resources
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@RelNameDSpaceResource(AuthorityEntryRest.NAME)
|
||||
public class AuthorityEntryResource extends HALResource<AuthorityEntryRest> {
|
||||
|
||||
|
||||
public AuthorityEntryResource(AuthorityEntryRest entry) {
|
||||
super(entry);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
|
||||
/**
|
||||
* Vocabulary Entry Details Rest HAL Resource. The HAL Resource wraps the REST Resource adding
|
||||
* support for the links and embedded resources
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@RelNameDSpaceResource(VocabularyEntryDetailsRest.NAME)
|
||||
public class VocabularyEntryDetailsResource extends DSpaceResource<VocabularyEntryDetailsRest> {
|
||||
|
||||
public VocabularyEntryDetailsResource(VocabularyEntryDetailsRest entry, Utils utils) {
|
||||
super(entry, utils);
|
||||
if (entry.isInHierarchicalVocabulary()) {
|
||||
add(utils.linkToSubResource(entry, VocabularyEntryDetailsRest.PARENT));
|
||||
add(utils.linkToSubResource(entry, VocabularyEntryDetailsRest.CHILDREN));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.VocabularyEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
|
||||
/**
|
||||
* Vocabulary Entry Rest HAL Resource. The HAL Resource wraps the REST Resource
|
||||
* adding support for the links and embedded resources
|
||||
*
|
||||
* @author Mykhaylo Boychuk (mykhaylo.boychuk at 4science.it)
|
||||
*/
|
||||
@RelNameDSpaceResource(VocabularyEntryRest.NAME)
|
||||
public class VocabularyEntryResource extends HALResource<VocabularyEntryRest> {
|
||||
public VocabularyEntryResource(VocabularyEntryRest sd) {
|
||||
super(sd);
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.rest.model.hateoas;
|
||||
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
|
||||
@@ -17,13 +17,10 @@ import org.dspace.app.rest.utils.Utils;
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@RelNameDSpaceResource(AuthorityRest.NAME)
|
||||
public class AuthorityResource extends DSpaceResource<AuthorityRest> {
|
||||
public AuthorityResource(AuthorityRest sd, Utils utils) {
|
||||
@RelNameDSpaceResource(VocabularyRest.NAME)
|
||||
public class VocabularyResource extends DSpaceResource<VocabularyRest> {
|
||||
public VocabularyResource(VocabularyRest sd, Utils utils) {
|
||||
super(sd, utils);
|
||||
if (sd.hasIdentifier()) {
|
||||
add(utils.linkToSubResource(sd, AuthorityRest.ENTRY));
|
||||
}
|
||||
add(utils.linkToSubResource(sd, AuthorityRest.ENTRIES));
|
||||
add(utils.linkToSubResource(sd, VocabularyRest.ENTRIES));
|
||||
}
|
||||
}
|
@@ -7,6 +7,9 @@
|
||||
*/
|
||||
package org.dspace.app.rest.model.submit;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* The SelectableMetadata REST Resource. It is not addressable directly, only
|
||||
* used as inline object in the InputForm resource.
|
||||
@@ -24,7 +27,9 @@ package org.dspace.app.rest.model.submit;
|
||||
public class SelectableMetadata {
|
||||
private String metadata;
|
||||
private String label;
|
||||
private String authority;
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
private String controlledVocabulary;
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
private Boolean closed = false;
|
||||
|
||||
public String getMetadata() {
|
||||
@@ -43,12 +48,12 @@ public class SelectableMetadata {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public void setAuthority(String authority) {
|
||||
this.authority = authority;
|
||||
public void setControlledVocabulary(String vocabularyName) {
|
||||
this.controlledVocabulary = vocabularyName;
|
||||
}
|
||||
|
||||
public String getAuthority() {
|
||||
return authority;
|
||||
public String getControlledVocabulary() {
|
||||
return controlledVocabulary;
|
||||
}
|
||||
|
||||
public Boolean isClosed() {
|
||||
|
@@ -1,82 +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.repository;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.Choices;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.core.Context;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Controller for exposition of authority services
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component(AuthorityRest.CATEGORY + "." + AuthorityRest.NAME + "." + AuthorityRest.ENTRIES)
|
||||
public class AuthorityEntryLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private CollectionService cs;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public Page<AuthorityEntryRest> query(@Nullable HttpServletRequest request, String name,
|
||||
@Nullable Pageable optionalPageable, Projection projection) {
|
||||
Context context = obtainContext();
|
||||
String query = request == null ? null : request.getParameter("query");
|
||||
String metadata = request == null ? null : request.getParameter("metadata");
|
||||
String uuidCollectìon = request == null ? null : request.getParameter("uuid");
|
||||
Collection collection = null;
|
||||
if (StringUtils.isNotBlank(uuidCollectìon)) {
|
||||
try {
|
||||
collection = cs.find(context, UUID.fromString(uuidCollectìon));
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
List<AuthorityEntryRest> results = new ArrayList<>();
|
||||
Pageable pageable = utils.getPageable(optionalPageable);
|
||||
if (StringUtils.isNotBlank(metadata)) {
|
||||
String[] tokens = org.dspace.core.Utils.tokenize(metadata);
|
||||
String fieldKey = org.dspace.core.Utils.standardize(tokens[0], tokens[1], tokens[2], "_");
|
||||
Choices choices = cas.getMatches(fieldKey, query, collection, Math.toIntExact(pageable.getOffset()),
|
||||
pageable.getPageSize(),
|
||||
context.getCurrentLocale().toString());
|
||||
for (Choice value : choices.values) {
|
||||
results.add(authorityUtils.convertEntry(value, name, projection));
|
||||
}
|
||||
}
|
||||
return new PageImpl<>(results, pageable, results.size());
|
||||
}
|
||||
}
|
@@ -1,60 +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.repository;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Controller for exposition of authority services
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component(AuthorityRest.CATEGORY + "." + AuthorityRest.NAME + "." + AuthorityRest.ENTRY)
|
||||
public class AuthorityEntryValueLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public AuthorityEntryRest getResource(HttpServletRequest request, String name, String relId,
|
||||
Pageable pageable, Projection projection) {
|
||||
Context context = obtainContext();
|
||||
ChoiceAuthority choiceAuthority = cas.getChoiceAuthorityByAuthorityName(name);
|
||||
Choice choice = choiceAuthority.getChoice(null, relId, context.getCurrentLocale().toString());
|
||||
if (choice == null) {
|
||||
throw new ResourceNotFoundException("The authority was not found");
|
||||
}
|
||||
return authorityUtils.convertEntry(choice, name, projection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not embeddable because this is not currently a pageable subresource.
|
||||
*/
|
||||
@Override
|
||||
public boolean isEmbeddableRelation(Object data, String name) {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1,82 +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.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.dspace.app.rest.DiscoverableEndpointsService;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.AuthorizationRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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.hateoas.Link;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Controller for exposition of authority services
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component(AuthorityRest.CATEGORY + "." + AuthorityRest.NAME)
|
||||
public class AuthorityRestRepository extends DSpaceRestRepository<AuthorityRest, String>
|
||||
implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@Autowired
|
||||
DiscoverableEndpointsService discoverableEndpointsService;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public AuthorityRest findOne(Context context, String name) {
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(name);
|
||||
return authorityUtils.convertAuthority(source, name, utils.obtainProjection());
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public Page<AuthorityRest> findAll(Context context, Pageable pageable) {
|
||||
Set<String> authoritiesName = cas.getChoiceAuthoritiesNames();
|
||||
List<AuthorityRest> results = new ArrayList<>();
|
||||
Projection projection = utils.obtainProjection();
|
||||
for (String authorityName : authoritiesName) {
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(authorityName);
|
||||
AuthorityRest result = authorityUtils.convertAuthority(source, authorityName, projection);
|
||||
results.add(result);
|
||||
}
|
||||
return new PageImpl<>(results, pageable, results.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<AuthorityRest> getDomainClass() {
|
||||
return AuthorityRest.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + AuthorizationRest.CATEGORY + "/" + AuthorizationRest.NAME + "/search",
|
||||
AuthorizationRest.NAME + "-search")));
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.exception.LinkNotFoundException;
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.Choices;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.Context;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Link repository to expose the parent of a vocabulary entry details in an hierarchical vocabulary
|
||||
*
|
||||
* @author Mykhaylo Boychuk (4Science.it)
|
||||
*/
|
||||
@Component(VocabularyRest.CATEGORY + "." + VocabularyEntryDetailsRest.NAME + "." + VocabularyEntryDetailsRest.CHILDREN)
|
||||
public class VocabularyEntryDetailsChildrenLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService choiceAuthorityService;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public Page<VocabularyEntryDetailsRest> getChildren(@Nullable HttpServletRequest request, String name,
|
||||
@Nullable Pageable optionalPageable, Projection projection) {
|
||||
|
||||
Context context = obtainContext();
|
||||
String[] parts = StringUtils.split(name, ":", 2);
|
||||
if (parts.length != 2) {
|
||||
return null;
|
||||
}
|
||||
String vocabularyName = parts[0];
|
||||
String id = parts[1];
|
||||
Pageable pageable = utils.getPageable(optionalPageable);
|
||||
List<VocabularyEntryDetailsRest> results = new ArrayList<VocabularyEntryDetailsRest>();
|
||||
ChoiceAuthority authority = choiceAuthorityService.getChoiceAuthorityByAuthorityName(vocabularyName);
|
||||
if (StringUtils.isNotBlank(id) && authority.isHierarchical()) {
|
||||
Choices choices = choiceAuthorityService.getChoicesByParent(vocabularyName, id, (int) pageable.getOffset(),
|
||||
pageable.getPageSize(), context.getCurrentLocale().toString());
|
||||
for (Choice value : choices.values) {
|
||||
results.add(authorityUtils.convertEntryDetails(value, vocabularyName, authority.isHierarchical(),
|
||||
utils.obtainProjection()));
|
||||
}
|
||||
Page<VocabularyEntryDetailsRest> resources = new PageImpl<VocabularyEntryDetailsRest>(results, pageable,
|
||||
choices.total);
|
||||
return resources;
|
||||
} else {
|
||||
throw new LinkNotFoundException(VocabularyRest.CATEGORY, VocabularyEntryDetailsRest.NAME, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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.repository;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Link repository to expose the parent of a vocabulary entry details in an hierarchical vocabulary
|
||||
*
|
||||
* @author Mykhaylo Boychuk ($science.it)
|
||||
*/
|
||||
@Component(VocabularyRest.CATEGORY + "." + VocabularyEntryDetailsRest.NAME + "." + VocabularyEntryDetailsRest.PARENT)
|
||||
public class VocabularyEntryDetailsParentLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService choiceAuthorityService;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public VocabularyEntryDetailsRest getParent(@Nullable HttpServletRequest request, String name,
|
||||
@Nullable Pageable optionalPageable, Projection projection) {
|
||||
Context context = obtainContext();
|
||||
String[] parts = StringUtils.split(name, ":", 2);
|
||||
if (parts.length != 2) {
|
||||
return null;
|
||||
}
|
||||
String vocabularyName = parts[0];
|
||||
String id = parts[1];
|
||||
|
||||
ChoiceAuthority authority = choiceAuthorityService.getChoiceAuthorityByAuthorityName(vocabularyName);
|
||||
Choice choice = null;
|
||||
if (StringUtils.isNotBlank(id) && authority != null && authority.isHierarchical()) {
|
||||
choice = choiceAuthorityService.getParentChoice(vocabularyName, id, context.getCurrentLocale().toString());
|
||||
} else {
|
||||
throw new NotFoundException();
|
||||
}
|
||||
return authorityUtils.convertEntryDetails(choice, vocabularyName, authority.isHierarchical(),
|
||||
utils.obtainProjection());
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.atteo.evo.inflector.English;
|
||||
import org.dspace.app.rest.DiscoverableEndpointsService;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.exception.LinkNotFoundException;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.Choices;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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.hateoas.Link;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Controller for exposition of vocabularies entry details for the submission
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@Component(VocabularyRest.CATEGORY + "." + VocabularyEntryDetailsRest.NAME)
|
||||
public class VocabularyEntryDetailsRestRepository extends DSpaceRestRepository<VocabularyEntryDetailsRest, String>
|
||||
implements InitializingBean {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@Autowired
|
||||
private DiscoverableEndpointsService discoverableEndpointsService;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String models = English.plural(VocabularyEntryDetailsRest.NAME);
|
||||
discoverableEndpointsService.register(this, Arrays.asList(
|
||||
new Link("/api/" + VocabularyRest.CATEGORY + "/" + models + "/search",
|
||||
models + "-search")));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public Page<VocabularyEntryDetailsRest> findAll(Context context, Pageable pageable) {
|
||||
throw new RepositoryMethodNotImplementedException(ResourcePolicyRest.NAME, "findAll");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public VocabularyEntryDetailsRest findOne(Context context, String name) {
|
||||
String[] parts = StringUtils.split(name, ":", 2);
|
||||
if (parts.length != 2) {
|
||||
return null;
|
||||
}
|
||||
String vocabularyName = parts[0];
|
||||
String vocabularyId = parts[1];
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(vocabularyName);
|
||||
Choice choice = source.getChoice(vocabularyId, context.getCurrentLocale().toString());
|
||||
return authorityUtils.convertEntryDetails(choice, vocabularyName, source.isHierarchical(),
|
||||
utils.obtainProjection());
|
||||
}
|
||||
|
||||
@SearchRestMethod(name = "top")
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public Page<VocabularyEntryDetailsRest> findAllTop(@Parameter(value = "vocabulary", required = true)
|
||||
String vocabularyId, Pageable pageable) {
|
||||
Context context = obtainContext();
|
||||
List<VocabularyEntryDetailsRest> results = new ArrayList<VocabularyEntryDetailsRest>();
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(vocabularyId);
|
||||
if (source.isHierarchical()) {
|
||||
Choices choices = cas.getTopChoices(vocabularyId, (int)pageable.getOffset(), pageable.getPageSize(),
|
||||
context.getCurrentLocale().toString());
|
||||
for (Choice value : choices.values) {
|
||||
results.add(authorityUtils.convertEntryDetails(value, vocabularyId, source.isHierarchical(),
|
||||
utils.obtainProjection()));
|
||||
}
|
||||
Page<VocabularyEntryDetailsRest> resources = new PageImpl<VocabularyEntryDetailsRest>(results, pageable,
|
||||
choices.total);
|
||||
return resources;
|
||||
}
|
||||
throw new LinkNotFoundException(VocabularyRest.CATEGORY, VocabularyEntryDetailsRest.NAME, vocabularyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<VocabularyEntryDetailsRest> getDomainClass() {
|
||||
return VocabularyEntryDetailsRest.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.VocabularyEntryRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.Choices;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.core.Context;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Controller for exposition of authority services
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@Component(VocabularyRest.CATEGORY + "." + VocabularyRest.NAME + "." + VocabularyRest.ENTRIES)
|
||||
public class VocabularyEntryLinkRepository extends AbstractDSpaceRestRepository
|
||||
implements LinkRestRepository {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private CollectionService cs;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
public Page<VocabularyEntryRest> filter(@Nullable HttpServletRequest request, String name,
|
||||
@Nullable Pageable optionalPageable, Projection projection) {
|
||||
Context context = obtainContext();
|
||||
String exact = request == null ? null : request.getParameter("exact");
|
||||
String filter = request == null ? null : request.getParameter("filter");
|
||||
String entryID = request == null ? null : request.getParameter("entryID");
|
||||
|
||||
if (StringUtils.isNotBlank(filter) && StringUtils.isNotBlank(entryID)) {
|
||||
throw new IllegalArgumentException("the filter and entryID parameters are mutually exclusive");
|
||||
}
|
||||
|
||||
Pageable pageable = utils.getPageable(optionalPageable);
|
||||
List<VocabularyEntryRest> results = new ArrayList<>();
|
||||
ChoiceAuthority ca = cas.getChoiceAuthorityByAuthorityName(name);
|
||||
if (ca == null) {
|
||||
throw new ResourceNotFoundException("the vocabulary named " + name + "doesn't exist");
|
||||
}
|
||||
if (!ca.isScrollable() && StringUtils.isBlank(filter) && StringUtils.isBlank(entryID)) {
|
||||
throw new UnprocessableEntityException(
|
||||
"one of filter or entryID parameter is required for not scrollable vocabularies");
|
||||
}
|
||||
Choices choices = null;
|
||||
if (BooleanUtils.toBoolean(exact)) {
|
||||
choices = ca.getBestMatch(filter, context.getCurrentLocale().toString());
|
||||
} else if (StringUtils.isNotBlank(entryID)) {
|
||||
Choice choice = ca.getChoice(entryID,
|
||||
context.getCurrentLocale().toString());
|
||||
if (choice != null) {
|
||||
choices = new Choices(new Choice[] {choice}, 0, 1, Choices.CF_ACCEPTED, false);
|
||||
} else {
|
||||
choices = new Choices(false);
|
||||
}
|
||||
} else {
|
||||
choices = ca.getMatches(filter, Math.toIntExact(pageable.getOffset()),
|
||||
pageable.getPageSize(), context.getCurrentLocale().toString());
|
||||
}
|
||||
boolean storeAuthority = ca.storeAuthorityInMetadata();
|
||||
for (Choice value : choices.values) {
|
||||
results.add(authorityUtils.convertEntry(value, name, storeAuthority, projection));
|
||||
}
|
||||
return new PageImpl<>(results, pageable, choices.total);
|
||||
}
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.MetadataFieldService;
|
||||
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.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Controller for exposition of vocabularies for the submission
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@Component(VocabularyRest.CATEGORY + "." + VocabularyRest.NAME)
|
||||
public class VocabularyRestRepository extends DSpaceRestRepository<VocabularyRest, String> {
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@Autowired
|
||||
private CollectionService collectionService;
|
||||
|
||||
@Autowired
|
||||
private MetadataFieldService metadataFieldService;
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public VocabularyRest findOne(Context context, String name) {
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(name);
|
||||
return authorityUtils.convertAuthority(source, name, utils.obtainProjection());
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@Override
|
||||
public Page<VocabularyRest> findAll(Context context, Pageable pageable) {
|
||||
Set<String> authoritiesName = cas.getChoiceAuthoritiesNames();
|
||||
List<VocabularyRest> results = new ArrayList<>();
|
||||
Projection projection = utils.obtainProjection();
|
||||
for (String authorityName : authoritiesName) {
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(authorityName);
|
||||
VocabularyRest result = authorityUtils.convertAuthority(source, authorityName, projection);
|
||||
results.add(result);
|
||||
}
|
||||
return utils.getPage(results, pageable);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('AUTHENTICATED')")
|
||||
@SearchRestMethod(name = "byMetadataAndCollection")
|
||||
public VocabularyRest findByMetadataAndCollection(
|
||||
@Parameter(value = "metadata", required = true) String metadataField,
|
||||
@Parameter(value = "collection", required = true) UUID collectionUuid) {
|
||||
|
||||
Collection collection = null;
|
||||
MetadataField metadata = null;
|
||||
String[] tokens = org.dspace.core.Utils.tokenize(metadataField);
|
||||
|
||||
try {
|
||||
collection = collectionService.find(obtainContext(), collectionUuid);
|
||||
metadata = metadataFieldService.findByElement(obtainContext(), tokens[0], tokens[1], tokens[2]);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(
|
||||
"A database error occurs retrieving the metadata and/or the collection information", e);
|
||||
}
|
||||
|
||||
if (metadata == null) {
|
||||
throw new UnprocessableEntityException(metadataField + " is not a valid metadata");
|
||||
}
|
||||
if (collection == null) {
|
||||
throw new UnprocessableEntityException(collectionUuid + " is not a valid collection");
|
||||
}
|
||||
|
||||
String authorityName = cas.getChoiceAuthorityName(tokens[0], tokens[1], tokens[2], collection);
|
||||
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(authorityName);
|
||||
return authorityUtils.convertAuthority(source, authorityName, utils.obtainProjection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<VocabularyRest> getDomainClass() {
|
||||
return VocabularyRest.class;
|
||||
}
|
||||
|
||||
}
|
@@ -7,9 +7,11 @@
|
||||
*/
|
||||
package org.dspace.app.rest.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||
import org.dspace.app.rest.model.VocabularyEntryRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.content.authority.Choice;
|
||||
import org.dspace.content.authority.ChoiceAuthority;
|
||||
@@ -27,6 +29,8 @@ public class AuthorityUtils {
|
||||
|
||||
public static final String PRESENTATION_TYPE_LOOKUP = "lookup";
|
||||
|
||||
public static final String PRESENTATION_TYPE_AUTHORLOOKUP = "authorLookup";
|
||||
|
||||
public static final String PRESENTATION_TYPE_SUGGEST = "suggest";
|
||||
|
||||
public static final String RESERVED_KEYMAP_PARENT = "parent";
|
||||
@@ -39,11 +43,11 @@ public class AuthorityUtils {
|
||||
|
||||
|
||||
public boolean isChoice(String schema, String element, String qualifier) {
|
||||
return cas.isChoicesConfigured(org.dspace.core.Utils.standardize(schema, element, qualifier, "_"));
|
||||
return cas.isChoicesConfigured(org.dspace.core.Utils.standardize(schema, element, qualifier, "_"), null);
|
||||
}
|
||||
|
||||
public String getAuthorityName(String schema, String element, String qualifier) {
|
||||
return cas.getChoiceAuthorityName(schema, element, qualifier);
|
||||
return cas.getChoiceAuthorityName(schema, element, qualifier, null);
|
||||
}
|
||||
|
||||
public boolean isClosed(String schema, String element, String qualifier) {
|
||||
@@ -62,9 +66,45 @@ public class AuthorityUtils {
|
||||
* @param projection the name of the projection to use, or {@code null}.
|
||||
* @return
|
||||
*/
|
||||
public AuthorityEntryRest convertEntry(Choice choice, String authorityName, Projection projection) {
|
||||
AuthorityEntryRest entry = converter.toRest(choice, projection);
|
||||
entry.setAuthorityName(authorityName);
|
||||
public VocabularyEntryDetailsRest convertEntryDetails(Choice choice, String authorityName,
|
||||
boolean isHierarchical, Projection projection) {
|
||||
if (choice == null) {
|
||||
return null;
|
||||
}
|
||||
VocabularyEntryDetailsRest entry = converter.toRest(choice, projection);
|
||||
entry.setVocabularyName(authorityName);
|
||||
entry.setId(authorityName + ":" + entry.getId());
|
||||
entry.setInHierarchicalVocabulary(isHierarchical);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* This utility method is currently a workaround to enrich the REST object with
|
||||
* information from the parent vocabulary that is not referenced by the Choice
|
||||
* model
|
||||
*
|
||||
* @param choice the dspace-api choice to expose as vocabulary entry
|
||||
* @param authorityName the name of the vocabulary
|
||||
* @param storeAuthority <code>true</code> if the entry id should be exposed as
|
||||
* an authority for storing it in the metadatavalue
|
||||
* @param projection the rest projection to apply
|
||||
* @return the vocabulary entry rest reppresentation of the provided choice
|
||||
*/
|
||||
public VocabularyEntryRest convertEntry(Choice choice, String authorityName, boolean storeAuthority,
|
||||
Projection projection) {
|
||||
if (choice == null) {
|
||||
return null;
|
||||
}
|
||||
VocabularyEntryRest entry = new VocabularyEntryRest();
|
||||
entry.setDisplay(choice.label);
|
||||
entry.setValue(choice.value);
|
||||
entry.setOtherInformation(choice.extras);
|
||||
if (storeAuthority) {
|
||||
entry.setAuthority(choice.authority);
|
||||
}
|
||||
if (StringUtils.isNotBlank(choice.authority)) {
|
||||
entry.setVocabularyEntryDetailsRest(converter.toRest(choice, projection));
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -76,8 +116,8 @@ public class AuthorityUtils {
|
||||
* @param projection the projecton to use.
|
||||
* @return
|
||||
*/
|
||||
public AuthorityRest convertAuthority(ChoiceAuthority source, String authorityName, Projection projection) {
|
||||
AuthorityRest result = converter.toRest(source, projection);
|
||||
public VocabularyRest convertAuthority(ChoiceAuthority source, String authorityName, Projection projection) {
|
||||
VocabularyRest result = converter.toRest(source, projection);
|
||||
result.setName(authorityName);
|
||||
return result;
|
||||
}
|
||||
|
@@ -28,7 +28,8 @@ public class RegexUtils {
|
||||
* identifier (digits or uuid)
|
||||
*/
|
||||
public static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG = "/{id:^(?!^\\d+$)" +
|
||||
"(?!^[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}$)[\\w+\\-\\.]+$+}";
|
||||
"(?!^[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}$)"
|
||||
+ "[\\w+\\-\\.:]+$+}";
|
||||
|
||||
/**
|
||||
* Regular expression in the request mapping to accept number as identifier
|
||||
|
@@ -47,7 +47,6 @@ import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.exception.PaginationException;
|
||||
import org.dspace.app.rest.exception.RepositoryNotFoundException;
|
||||
import org.dspace.app.rest.model.AuthorityRest;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.CommunityRest;
|
||||
import org.dspace.app.rest.model.LinkRest;
|
||||
@@ -58,6 +57,7 @@ import org.dspace.app.rest.model.ResourcePolicyRest;
|
||||
import org.dspace.app.rest.model.RestAddressableModel;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.VersionHistoryRest;
|
||||
import org.dspace.app.rest.model.VocabularyRest;
|
||||
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||
import org.dspace.app.rest.projection.CompositeProjection;
|
||||
@@ -254,7 +254,7 @@ public class Utils {
|
||||
return CommunityRest.NAME;
|
||||
}
|
||||
if (modelPlural.equals("authorities")) {
|
||||
return AuthorityRest.NAME;
|
||||
return VocabularyRest.NAME;
|
||||
}
|
||||
if (modelPlural.equals("resourcepolicies")) {
|
||||
return ResourcePolicyRest.NAME;
|
||||
@@ -268,6 +268,9 @@ public class Utils {
|
||||
if (StringUtils.equals(modelPlural, "properties")) {
|
||||
return PropertyRest.NAME;
|
||||
}
|
||||
if (StringUtils.equals(modelPlural, "vocabularies")) {
|
||||
return VocabularyRest.NAME;
|
||||
}
|
||||
return modelPlural.replaceAll("s$", "");
|
||||
}
|
||||
|
||||
|
@@ -1,233 +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;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.solr.client.solrj.SolrQuery;
|
||||
import org.apache.solr.client.solrj.response.QueryResponse;
|
||||
import org.dspace.app.rest.matcher.AuthorityEntryMatcher;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.authority.PersonAuthorityValue;
|
||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.service.PluginService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This class handles all Authority related IT. It alters some config to run the tests, but it gets cleared again
|
||||
* after every test
|
||||
*/
|
||||
public class AuthorityRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
private PluginService pluginService;
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setUp();
|
||||
configurationService.setProperty("plugin.named.org.dspace.content.authority.ChoiceAuthority",
|
||||
"org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority");
|
||||
|
||||
configurationService.setProperty("solr.authority.server",
|
||||
"${solr.server}/authority");
|
||||
configurationService.setProperty("choices.plugin.dc.contributor.author",
|
||||
"SolrAuthorAuthority");
|
||||
configurationService.setProperty("choices.presentation.dc.contributor.author",
|
||||
"authorLookup");
|
||||
configurationService.setProperty("authority.controlled.dc.contributor.author",
|
||||
"true");
|
||||
|
||||
configurationService.setProperty("authority.author.indexer.field.1",
|
||||
"dc.contributor.author");
|
||||
|
||||
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
PersonAuthorityValue person1 = new PersonAuthorityValue();
|
||||
person1.setId(String.valueOf(UUID.randomUUID()));
|
||||
person1.setLastName("Shirasaka");
|
||||
person1.setFirstName("Seiko");
|
||||
person1.setValue("Shirasaka, Seiko");
|
||||
person1.setField("dc_contributor_author");
|
||||
person1.setLastModified(new Date());
|
||||
person1.setCreationDate(new Date());
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().indexContent(person1);
|
||||
|
||||
PersonAuthorityValue person2 = new PersonAuthorityValue();
|
||||
person2.setId(String.valueOf(UUID.randomUUID()));
|
||||
person2.setLastName("Miller");
|
||||
person2.setFirstName("Tyler E");
|
||||
person2.setValue("Miller, Tyler E");
|
||||
person2.setField("dc_contributor_author");
|
||||
person2.setLastModified(new Date());
|
||||
person2.setCreationDate(new Date());
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().indexContent(person2);
|
||||
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().commit();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctSrscQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/srsc/entries")
|
||||
.param("metadata", "dc.subject")
|
||||
.param("query", "Research")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(26)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsSrscQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/srsc/entries")
|
||||
.param("metadata", "dc.subject")
|
||||
.param("query", "Research2")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
/**
|
||||
* This functionality is currently broken, it returns all 22 values
|
||||
*/
|
||||
public void correctCommonTypesTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/common_types/entries")
|
||||
.param("metadata", "dc.type")
|
||||
.param("query", "Book")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctSolrQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/SolrAuthorAuthority/entries")
|
||||
.param("metadata", "dc.contributor.author")
|
||||
.param("query", "Shirasaka")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsSolrQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/SolrAuthorAuthority/entries")
|
||||
.param("metadata", "dc.contributor.author")
|
||||
.param("query", "Smith")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveSrscValueTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
// When full projection is requested, response should include expected properties, links, and embeds.
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/srsc/entryValues/SCB1922").param("projection", "full"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", AuthorityEntryMatcher.matchFullEmbeds()))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsSrscValueTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/srsc/entryValues/DOESNTEXIST"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveCommonTypesValueTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/common_types/entryValues/Book").param("projection", "full"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)))
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveCommonTypesWithSpaceValueTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/common_types/entryValues/Learning+Object"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoverableNestedLinkTest() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._links",Matchers.allOf(
|
||||
hasJsonPath("$.authorizations.href",
|
||||
is("http://localhost/api/authz/authorizations")),
|
||||
hasJsonPath("$.authorization-search.href",
|
||||
is("http://localhost/api/authz/authorization/search"))
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveSolrValueTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
SolrQuery query = new SolrQuery();
|
||||
query.setQuery("*:*");
|
||||
QueryResponse queryResponse = AuthorityServiceFactory.getInstance().getAuthoritySearchService().search(query);
|
||||
String id = String.valueOf(queryResponse.getResults().get(0).getFieldValue("id"));
|
||||
|
||||
getClient(token).perform(
|
||||
get("/api/integration/authorities/SolrAuthorAuthority/entryValues/" + id))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().cleanIndex();
|
||||
super.destroy();
|
||||
}
|
||||
}
|
@@ -49,7 +49,8 @@ public class RootRestResourceControllerIT extends AbstractControllerIntegrationT
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//Check that all required root links are present and that they are absolute
|
||||
.andExpect(jsonPath("$._links.authorities.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
.andExpect(jsonPath("$._links.vocabularies.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
.andExpect(jsonPath("$._links.vocabularyEntryDetails.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
.andExpect(jsonPath("$._links.bitstreamformats.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
.andExpect(jsonPath("$._links.bitstreams.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
.andExpect(jsonPath("$._links.browses.href", startsWith(BASE_REST_SERVER_URL)))
|
||||
|
@@ -23,6 +23,9 @@ import org.dspace.app.rest.repository.SubmissionFormRestRepository;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.builder.EPersonBuilder;
|
||||
import org.dspace.content.authority.DCInputAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.service.PluginService;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.hamcrest.Matchers;
|
||||
@@ -39,6 +42,10 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
private ConfigurationService configurationService;
|
||||
@Autowired
|
||||
private SubmissionFormRestRepository submissionFormRestRepository;
|
||||
@Autowired
|
||||
private PluginService pluginService;
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Test
|
||||
public void findAll() throws Exception {
|
||||
@@ -56,15 +63,15 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//The configuration file for the test env includes 3 forms
|
||||
//The configuration file for the test env includes 6 forms
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", equalTo(4)))
|
||||
.andExpect(jsonPath("$.page.totalElements", equalTo(6)))
|
||||
.andExpect(jsonPath("$.page.totalPages", equalTo(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(
|
||||
jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL + "config/submissionforms")))
|
||||
//The array of submissionforms should have a size of 3
|
||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(4))))
|
||||
//The array of submissionforms should have a size of 6
|
||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(6))))
|
||||
;
|
||||
}
|
||||
|
||||
@@ -75,12 +82,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().contentType(contentType))
|
||||
.andExpect(jsonPath("$.page.size", is(20)))
|
||||
.andExpect(jsonPath("$.page.totalElements", equalTo(4)))
|
||||
.andExpect(jsonPath("$.page.totalElements", equalTo(6)))
|
||||
.andExpect(jsonPath("$.page.totalPages", equalTo(1)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)))
|
||||
.andExpect(jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL
|
||||
+ "config/submissionforms")))
|
||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(4))));
|
||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(6))));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -152,6 +159,121 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
"col-sm-8","dc.publisher"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFieldWithAuthorityConfig() throws Exception {
|
||||
configurationService.setProperty("plugin.named.org.dspace.content.authority.ChoiceAuthority",
|
||||
new String[] {
|
||||
"org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority",
|
||||
"org.dspace.content.authority.SolrAuthority = SolrEditorAuthority",
|
||||
"org.dspace.content.authority.SolrAuthority = SolrSubjectAuthority"
|
||||
});
|
||||
|
||||
configurationService.setProperty("solr.authority.server",
|
||||
"${solr.server}/authority");
|
||||
configurationService.setProperty("choices.plugin.dc.contributor.author",
|
||||
"SolrAuthorAuthority");
|
||||
configurationService.setProperty("choices.presentation.dc.contributor.author",
|
||||
"suggest");
|
||||
configurationService.setProperty("authority.controlled.dc.contributor.author",
|
||||
"true");
|
||||
configurationService.setProperty("authority.author.indexer.field.1",
|
||||
"dc.contributor.author");
|
||||
configurationService.setProperty("choices.plugin.dc.contributor.editor",
|
||||
"SolrEditorAuthority");
|
||||
configurationService.setProperty("choices.presentation.dc.contributor.editor",
|
||||
"authorLookup");
|
||||
configurationService.setProperty("authority.controlled.dc.contributor.editor",
|
||||
"true");
|
||||
configurationService.setProperty("authority.author.indexer.field.2",
|
||||
"dc.contributor.editor");
|
||||
configurationService.setProperty("choices.plugin.dc.subject",
|
||||
"SolrSubjectAuthority");
|
||||
configurationService.setProperty("choices.presentation.dc.subject",
|
||||
"lookup");
|
||||
configurationService.setProperty("authority.controlled.dc.subject",
|
||||
"true");
|
||||
configurationService.setProperty("authority.author.indexer.field.3",
|
||||
"dc.subject");
|
||||
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/config/submissionforms/sampleauthority"))
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//Check that the JSON root matches the expected "sampleauthority" input forms
|
||||
.andExpect(jsonPath("$.id", is("sampleauthority")))
|
||||
.andExpect(jsonPath("$.name", is("sampleauthority")))
|
||||
.andExpect(jsonPath("$.type", is("submissionform")))
|
||||
.andExpect(jsonPath("$._links.self.href", Matchers
|
||||
.startsWith(REST_SERVER_URL + "config/submissionforms/sampleauthority")))
|
||||
// our test configuration include the dc.contributor.author, dc.contributor.editor and
|
||||
// dc.subject fields with in separate rows all linked to an authority with different
|
||||
// presentation modes (suggestion, name-lookup, lookup)
|
||||
.andExpect(jsonPath("$.rows[0].fields", contains(
|
||||
SubmissionFormFieldMatcher.matchFormFieldDefinition("onebox", "Author",
|
||||
null, true,
|
||||
"Author field that can be associated with an authority providing suggestion",
|
||||
null, "dc.contributor.author", "SolrAuthorAuthority")
|
||||
)))
|
||||
.andExpect(jsonPath("$.rows[1].fields", contains(
|
||||
SubmissionFormFieldMatcher.matchFormFieldDefinition("lookup-name", "Editor",
|
||||
null, false,
|
||||
"Editor field that can be associated with an authority "
|
||||
+ "providing the special name lookup",
|
||||
null, "dc.contributor.editor", "SolrEditorAuthority")
|
||||
)))
|
||||
.andExpect(jsonPath("$.rows[2].fields", contains(
|
||||
SubmissionFormFieldMatcher.matchFormFieldDefinition("lookup", "Subject",
|
||||
null, true,
|
||||
"Subject field that can be associated with an authority providing lookup",
|
||||
null, "dc.subject", "SolrSubjectAuthority")
|
||||
)))
|
||||
;
|
||||
// we need to force a reload of the config now to be able to reload also the cache of the other
|
||||
// authority related services. As this is needed just by this test method it is more efficient do it
|
||||
// here instead that force these reload for each method extending the destroy method
|
||||
configurationService.reloadConfig();
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findFieldWithValuePairsConfig() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/config/submissionforms/traditionalpageone"))
|
||||
//The status has to be 200 OK
|
||||
.andExpect(status().isOk())
|
||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||
.andExpect(content().contentType(contentType))
|
||||
//Check that the JSON root matches the expected "traditionalpageone" input forms
|
||||
.andExpect(jsonPath("$.id", is("traditionalpageone")))
|
||||
.andExpect(jsonPath("$.name", is("traditionalpageone")))
|
||||
.andExpect(jsonPath("$.type", is("submissionform")))
|
||||
.andExpect(jsonPath("$._links.self.href", Matchers
|
||||
.startsWith(REST_SERVER_URL + "config/submissionforms/traditionalpageone")))
|
||||
// our test configuration include the dc.type field with a value pair in the 8th row
|
||||
.andExpect(jsonPath("$.rows[7].fields", contains(
|
||||
SubmissionFormFieldMatcher.matchFormFieldDefinition("dropdown", "Type",
|
||||
null, true,
|
||||
"Select the type(s) of content of the item. To select more than one value in the " +
|
||||
"list, you may have to hold down the \"CTRL\" or \"Shift\" key.",
|
||||
null, "dc.type", "common_types")
|
||||
)))
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOpenRelationshipConfig() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
@@ -203,8 +325,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
public void languageSupportTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
String[] supportedLanguage = {"it","uk"};
|
||||
configurationService.setProperty("default.locale","it");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
Locale uk = new Locale("uk");
|
||||
Locale it = new Locale("it");
|
||||
@@ -234,7 +362,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
"Selezionare la lingua del contenuto principale dell'item."
|
||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||
+ " Se il contenuto non ha davvero una lingua"
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso"))));
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)",
|
||||
null, "dc.language.iso", "common_iso_languages"))));
|
||||
|
||||
// user select ukranian language
|
||||
getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest").locale(uk))
|
||||
@@ -256,9 +385,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
||||
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
||||
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
||||
"dc.language.iso"))));
|
||||
|
||||
resetLocalesConfiguration();
|
||||
null, "dc.language.iso", "common_iso_languages"))));
|
||||
resetLocalesConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -266,8 +394,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
String[] supportedLanguage = {"it","uk"};
|
||||
configurationService.setProperty("default.locale","it");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
EPerson epersonIT = EPersonBuilder.createEPerson(context)
|
||||
.withEmail("epersonIT@example.com")
|
||||
@@ -307,7 +441,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
"Selezionare la lingua del contenuto principale dell'item."
|
||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||
+ " Se il contenuto non ha davvero una lingua"
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso"))));
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)",
|
||||
null, "dc.language.iso", "common_iso_languages"))));
|
||||
|
||||
// user with ukranian prefer language
|
||||
getClient(tokenEpersonUK).perform(get("/api/config/submissionforms/languagetest"))
|
||||
@@ -329,9 +464,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
||||
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
||||
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
||||
"dc.language.iso"))));
|
||||
|
||||
resetLocalesConfiguration();
|
||||
null, "dc.language.iso", "common_iso_languages"))));
|
||||
resetLocalesConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -339,8 +473,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
String[] supportedLanguage = {"it","uk"};
|
||||
configurationService.setProperty("default.locale","it");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
Locale it = new Locale("it");
|
||||
|
||||
@@ -375,9 +515,9 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
"Selezionare la lingua del contenuto principale dell'item."
|
||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||
+ " Se il contenuto non ha davvero una lingua"
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)", "dc.language.iso"))));
|
||||
|
||||
resetLocalesConfiguration();
|
||||
+ " (ad esempio, se è un set di dati o un'immagine) selezionare (N/A)",
|
||||
null, "dc.language.iso", "common_iso_languages"))));
|
||||
resetLocalesConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -387,7 +527,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
String[] supportedLanguage = {"it","uk"};
|
||||
configurationService.setProperty("default.locale","it");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -407,8 +552,7 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
.matchFormFieldDefinition("onebox", "Titolo",
|
||||
"\u00C8 necessario inserire un titolo principale per questo item", false,
|
||||
"Inserisci titolo principale di questo item", "dc.title"))));
|
||||
|
||||
resetLocalesConfiguration();
|
||||
resetLocalesConfiguration();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -417,7 +561,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
String[] supportedLanguage = {"it","uk","en"};
|
||||
configurationService.setProperty("default.locale","en");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
@@ -446,5 +595,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
||||
configurationService.setProperty("default.locale","en");
|
||||
configurationService.setProperty("webui.supported.locales",null);
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,442 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.app.rest.matcher.VocabularyEntryDetailsMatcher;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Mykhaylo Boychuk (4science.it)
|
||||
*/
|
||||
public class VocabularyEntryDetailsIT extends AbstractControllerIntegrationTest {
|
||||
@Test
|
||||
public void discoverableNestedLinkTest() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._links",Matchers.allOf(
|
||||
hasJsonPath("$.vocabularyEntryDetails.href",
|
||||
is("http://localhost/api/submission/vocabularyEntryDetails")),
|
||||
hasJsonPath("$.vocabularyEntryDetails-search.href",
|
||||
is("http://localhost/api/submission/vocabularyEntryDetails/search"))
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllTest() throws Exception {
|
||||
String authToken = getAuthToken(admin.getEmail(), password);
|
||||
getClient(authToken).perform(get("/api/submission/vocabularyEntryDetails"))
|
||||
.andExpect(status()
|
||||
.isMethodNotAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneTest() throws Exception {
|
||||
String idAuthority = "srsc:SCB110";
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/" + idAuthority))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$",
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB110", "Religion/Theology",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology")))
|
||||
.andExpect(jsonPath("$.selectable", is(true)))
|
||||
.andExpect(jsonPath("$.otherInformation.id", is("SCB110")))
|
||||
.andExpect(jsonPath("$.otherInformation.note", is("Religionsvetenskap/Teologi")))
|
||||
.andExpect(jsonPath("$.otherInformation.parent",
|
||||
is("Research Subject Categories::HUMANITIES and RELIGION")))
|
||||
.andExpect(jsonPath("$._links.parent.href",
|
||||
endsWith("api/submission/vocabularyEntryDetails/srsc:SCB110/parent")))
|
||||
.andExpect(jsonPath("$._links.children.href",
|
||||
endsWith("api/submission/vocabularyEntryDetails/srsc:SCB110/children")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneUnauthorizedTest() throws Exception {
|
||||
String idAuthority = "srsc:SCB110";
|
||||
getClient().perform(get("/api/submission/vocabularyEntryDetails/" + idAuthority))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneNotFoundTest() throws Exception {
|
||||
String idAuthority = "srsc:not-existing";
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/" + idAuthority))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// try with a special id missing only the entry-id part
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/srsc:"))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
// try to retrieve the xml root that is not a entry itself
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/srsc:ResearchSubjectCategories"))
|
||||
.andExpect(status().isNotFound());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchTopTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
String tokenEPerson = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularyEntryDetails", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB11", "HUMANITIES and RELIGION",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB12", "LAW/JURISPRUDENCE",
|
||||
"Research Subject Categories::LAW/JURISPRUDENCE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB13", "SOCIAL SCIENCES",
|
||||
"Research Subject Categories::SOCIAL SCIENCES"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB14", "MATHEMATICS",
|
||||
"Research Subject Categories::MATHEMATICS"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB15", "NATURAL SCIENCES",
|
||||
"Research Subject Categories::NATURAL SCIENCES"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB16", "TECHNOLOGY",
|
||||
"Research Subject Categories::TECHNOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB17",
|
||||
"FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING",
|
||||
"Research Subject Categories::FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB18", "MEDICINE",
|
||||
"Research Subject Categories::MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB19", "ODONTOLOGY",
|
||||
"Research Subject Categories::ODONTOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB21", "PHARMACY",
|
||||
"Research Subject Categories::PHARMACY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB22", "VETERINARY MEDICINE",
|
||||
"Research Subject Categories::VETERINARY MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB23", "INTERDISCIPLINARY RESEARCH AREAS",
|
||||
"Research Subject Categories::INTERDISCIPLINARY RESEARCH AREAS")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(12)));
|
||||
|
||||
getClient(tokenEPerson).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularyEntryDetails", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB11", "HUMANITIES and RELIGION",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB12", "LAW/JURISPRUDENCE",
|
||||
"Research Subject Categories::LAW/JURISPRUDENCE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB13", "SOCIAL SCIENCES",
|
||||
"Research Subject Categories::SOCIAL SCIENCES"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB14", "MATHEMATICS",
|
||||
"Research Subject Categories::MATHEMATICS"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB15", "NATURAL SCIENCES",
|
||||
"Research Subject Categories::NATURAL SCIENCES"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB16", "TECHNOLOGY",
|
||||
"Research Subject Categories::TECHNOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB17",
|
||||
"FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING",
|
||||
"Research Subject Categories::FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB18", "MEDICINE",
|
||||
"Research Subject Categories::MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB19", "ODONTOLOGY",
|
||||
"Research Subject Categories::ODONTOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB21", "PHARMACY",
|
||||
"Research Subject Categories::PHARMACY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB22", "VETERINARY MEDICINE",
|
||||
"Research Subject Categories::VETERINARY MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB23", "INTERDISCIPLINARY RESEARCH AREAS",
|
||||
"Research Subject Categories::INTERDISCIPLINARY RESEARCH AREAS")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(12)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchFirstLevel_MATHEMATICS_Test() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB14/children"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.children", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1401",
|
||||
"Algebra, geometry and mathematical analysis",
|
||||
"Research Subject Categories::MATHEMATICS::Algebra, geometry and mathematical analysis"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1402", "Applied mathematics",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1409", "Other mathematics",
|
||||
"Research Subject Categories::MATHEMATICS::Other mathematics")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.children[*].otherInformation.parent",
|
||||
Matchers.everyItem(is("Research Subject Categories::MATHEMATICS"))))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchTopPaginationTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc")
|
||||
.param("page", "0")
|
||||
.param("size", "5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularyEntryDetails", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB11", "HUMANITIES and RELIGION",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB12", "LAW/JURISPRUDENCE",
|
||||
"Research Subject Categories::LAW/JURISPRUDENCE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB13", "SOCIAL SCIENCES",
|
||||
"Research Subject Categories::SOCIAL SCIENCES"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB14", "MATHEMATICS",
|
||||
"Research Subject Categories::MATHEMATICS"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB15", "NATURAL SCIENCES",
|
||||
"Research Subject Categories::NATURAL SCIENCES")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(12)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(3)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
|
||||
//second page
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc")
|
||||
.param("page", "1")
|
||||
.param("size", "5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularyEntryDetails", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB16", "TECHNOLOGY",
|
||||
"Research Subject Categories::TECHNOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB17",
|
||||
"FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING",
|
||||
"Research Subject Categories::FORESTRY, AGRICULTURAL SCIENCES and LANDSCAPE PLANNING"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB18", "MEDICINE",
|
||||
"Research Subject Categories::MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB19", "ODONTOLOGY",
|
||||
"Research Subject Categories::ODONTOLOGY"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB21", "PHARMACY",
|
||||
"Research Subject Categories::PHARMACY")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(12)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(3)))
|
||||
.andExpect(jsonPath("$.page.number", is(1)));
|
||||
|
||||
// third page
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc")
|
||||
.param("page", "2")
|
||||
.param("size", "5"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularyEntryDetails", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB22", "VETERINARY MEDICINE",
|
||||
"Research Subject Categories::VETERINARY MEDICINE"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB23", "INTERDISCIPLINARY RESEARCH AREAS",
|
||||
"Research Subject Categories::INTERDISCIPLINARY RESEARCH AREAS")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(12)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(3)))
|
||||
.andExpect(jsonPath("$.page.number", is(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchTopBadRequestTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", UUID.randomUUID().toString()))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchTopUnauthorizedTest() throws Exception {
|
||||
getClient().perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc:SCB16"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchByParentFirstLevelPaginationTest() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
// first page
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB14/children")
|
||||
.param("page", "0")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.children", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1401",
|
||||
"Algebra, geometry and mathematical analysis",
|
||||
"Research Subject Categories::MATHEMATICS::Algebra, geometry and mathematical analysis"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1402", "Applied mathematics",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(3)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(2)))
|
||||
.andExpect(jsonPath("$.page.number", is(0)));
|
||||
|
||||
// second page
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB14/children")
|
||||
.param("page", "1")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.children", Matchers.contains(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:SCB1409", "Other mathematics",
|
||||
"Research Subject Categories::MATHEMATICS::Other mathematics")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(3)))
|
||||
.andExpect(jsonPath("$.page.totalPages", is(2)))
|
||||
.andExpect(jsonPath("$.page.number", is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchByParentSecondLevel_Applied_mathematics_Test() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB1402/children"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.children", Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR140202", "Numerical analysis",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics::Numerical analysis"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR140203", "Mathematical statistics",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics::Mathematical statistics"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR140204", "Optimization, systems theory",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics::Optimization, systems theory"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR140205", "Theoretical computer science",
|
||||
"Research Subject Categories::MATHEMATICS::Applied mathematics::Theoretical computer science")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchByParentEmptyTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/srsc:VR140202/children"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchByParentWrongIdTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(get("/api/submission/vocabularyEntryDetails/"
|
||||
+ UUID.randomUUID() + "/children"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscSearchTopUnauthorizedTest() throws Exception {
|
||||
getClient().perform(get("/api/submission/vocabularyEntryDetails/search/top")
|
||||
.param("vocabulary", "srsc"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findParentByChildTest() throws Exception {
|
||||
String tokenEperson = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(tokenEperson).perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB180/parent"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", is(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry(
|
||||
"srsc:SCB18", "MEDICINE","Research Subject Categories::MEDICINE")
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findParentByChildBadRequestTest() throws Exception {
|
||||
String tokenEperson = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(tokenEperson).perform(get("/api/submission/vocabularyEntryDetails/" + UUID.randomUUID() + "/parent"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findParentByChildUnauthorizedTest() throws Exception {
|
||||
getClient().perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB180/parent"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findParentTopTest() throws Exception {
|
||||
String tokenEperson = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(tokenEperson)
|
||||
.perform(get("/api/submission/vocabularyEntryDetails/srsc:SCB11/parent"))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void srscProjectionTest() throws Exception {
|
||||
String tokenAdmin = getAuthToken(admin.getEmail(), password);
|
||||
getClient(tokenAdmin).perform(
|
||||
get("/api/submission/vocabularyEntryDetails/srsc:SCB110").param("projection", "full"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.parent",
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry(
|
||||
"srsc:SCB11", "HUMANITIES and RELIGION",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION")))
|
||||
.andExpect(jsonPath("$._embedded.children._embedded.children", matchAllSrscSC110Children()))
|
||||
.andExpect(jsonPath("$._embedded.children._embedded.children[*].otherInformation.parent",
|
||||
Matchers.everyItem(
|
||||
is("Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology"))));
|
||||
|
||||
getClient(tokenAdmin).perform(
|
||||
get("/api/submission/vocabularyEntryDetails/srsc:SCB110").param("embed", "children"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.children._embedded.children", matchAllSrscSC110Children()))
|
||||
.andExpect(jsonPath("$._embedded.children._embedded.children[*].otherInformation.parent",
|
||||
Matchers.everyItem(
|
||||
is("Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology"))));
|
||||
|
||||
getClient(tokenAdmin).perform(
|
||||
get("/api/submission/vocabularyEntryDetails/srsc:SCB110").param("embed", "parent"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.parent",
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry(
|
||||
"srsc:SCB11", "HUMANITIES and RELIGION",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION")));
|
||||
}
|
||||
|
||||
private Matcher<Iterable<? extends Object>> matchAllSrscSC110Children() {
|
||||
return Matchers.containsInAnyOrder(
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110102",
|
||||
"History of religion",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::History of religion"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110103",
|
||||
"Church studies",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Church studies"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110104",
|
||||
"Missionary studies",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Missionary studies"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110105",
|
||||
"Systematic theology",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Systematic theology"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110106",
|
||||
"Islamology",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Islamology"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110107",
|
||||
"Faith and reason",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Faith and reason"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110108",
|
||||
"Sociology of religion",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Sociology of religion"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110109",
|
||||
"Psychology of religion",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Psychology of religion"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110110",
|
||||
"Philosophy of religion",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Philosophy of religion"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110111",
|
||||
"New Testament exegesis",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::New Testament exegesis"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110112",
|
||||
"Old Testament exegesis",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Old Testament exegesis"),
|
||||
VocabularyEntryDetailsMatcher.matchAuthorityEntry("srsc:VR110113",
|
||||
"Dogmatics with symbolics",
|
||||
"Research Subject Categories::HUMANITIES and RELIGION::Religion/Theology::Dogmatics with symbolics")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.app.rest.matcher.VocabularyMatcher;
|
||||
import org.dspace.app.rest.repository.SubmissionFormRestRepository;
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.authority.PersonAuthorityValue;
|
||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.authority.DCInputAuthority;
|
||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||
import org.dspace.core.service.PluginService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This class handles all Authority related IT. It alters some config to run the tests, but it gets cleared again
|
||||
* after every test
|
||||
*/
|
||||
public class VocabularyRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
private SubmissionFormRestRepository submissionFormRestRepository;
|
||||
|
||||
@Autowired
|
||||
private PluginService pluginService;
|
||||
|
||||
@Autowired
|
||||
private ChoiceAuthorityService cas;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setUp();
|
||||
configurationService.setProperty("plugin.named.org.dspace.content.authority.ChoiceAuthority",
|
||||
"org.dspace.content.authority.SolrAuthority = SolrAuthorAuthority");
|
||||
|
||||
configurationService.setProperty("solr.authority.server",
|
||||
"${solr.server}/authority");
|
||||
configurationService.setProperty("choices.plugin.dc.contributor.author",
|
||||
"SolrAuthorAuthority");
|
||||
configurationService.setProperty("choices.presentation.dc.contributor.author",
|
||||
"authorLookup");
|
||||
configurationService.setProperty("authority.controlled.dc.contributor.author",
|
||||
"true");
|
||||
|
||||
configurationService.setProperty("authority.author.indexer.field.1",
|
||||
"dc.contributor.author");
|
||||
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
parentCommunity = CommunityBuilder.createCommunity(context).withName("A parent community for all our test")
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
PersonAuthorityValue person1 = new PersonAuthorityValue();
|
||||
person1.setId(String.valueOf(UUID.randomUUID()));
|
||||
person1.setLastName("Shirasaka");
|
||||
person1.setFirstName("Seiko");
|
||||
person1.setValue("Shirasaka, Seiko");
|
||||
person1.setField("dc_contributor_author");
|
||||
person1.setLastModified(new Date());
|
||||
person1.setCreationDate(new Date());
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().indexContent(person1);
|
||||
|
||||
PersonAuthorityValue person2 = new PersonAuthorityValue();
|
||||
person2.setId(String.valueOf(UUID.randomUUID()));
|
||||
person2.setLastName("Miller");
|
||||
person2.setFirstName("Tyler E");
|
||||
person2.setValue("Miller, Tyler E");
|
||||
person2.setField("dc_contributor_author");
|
||||
person2.setLastModified(new Date());
|
||||
person2.setCreationDate(new Date());
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().indexContent(person2);
|
||||
|
||||
AuthorityServiceFactory.getInstance().getAuthorityIndexingService().commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
@After
|
||||
// We need to cleanup the authorities cache once than the configuration has been restored
|
||||
public void destroy() throws Exception {
|
||||
super.destroy();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findAllTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.vocabularies", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchProperties("srsc", "srsc", false, true),
|
||||
VocabularyMatcher.matchProperties("common_types", "common_types", true, false),
|
||||
VocabularyMatcher.matchProperties("common_iso_languages", "common_iso_languages", true , false),
|
||||
VocabularyMatcher.matchProperties("SolrAuthorAuthority", "SolrAuthorAuthority", false , false)
|
||||
)))
|
||||
.andExpect(jsonPath("$._links.self.href",
|
||||
Matchers.containsString("api/submission/vocabularies")))
|
||||
.andExpect(jsonPath("$.page.totalElements", is(4)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneSRSC_Test() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/srsc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", is(
|
||||
VocabularyMatcher.matchProperties("srsc", "srsc", false, true)
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findOneCommonTypesTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/common_types"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", is(
|
||||
VocabularyMatcher.matchProperties("common_types", "common_types", true, false)
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctSrscQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/submission/vocabularies/srsc/entries")
|
||||
.param("filter", "Research")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("Research Subject Categories",
|
||||
"Research Subject Categories", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Family research",
|
||||
"Research Subject Categories::SOCIAL SCIENCES::Social sciences::Social work::Family research",
|
||||
"vocabularyEntry"))))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(26)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(13)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notScrollableVocabularyRequiredQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/srsc/entries"))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsSrscQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/submission/vocabularies/srsc/entries")
|
||||
.param("metadata", "dc.subject")
|
||||
.param("filter", "Research2")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vocabularyEntriesCommonTypesWithPaginationTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token)
|
||||
.perform(get("/api/submission/vocabularies/common_types/entries").param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("Animation", "Animation", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Article", "Article", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.entries[*].authority").doesNotExist())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(22)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(11)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
|
||||
//second page
|
||||
getClient(token).perform(get("/api/submission/vocabularies/common_types/entries")
|
||||
.param("size", "2")
|
||||
.param("page", "1"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("Book", "Book", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Book chapter", "Book chapter", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.entries[*].authority").doesNotExist())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(22)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(11)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vocabularyEntriesCommon_typesWithQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/common_types/entries")
|
||||
.param("filter", "Book")
|
||||
.param("size", "2"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("Book", "Book", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Book chapter", "Book chapter", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(2)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(1)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vocabularyEntriesDCInputAuthorityLocalesTest() throws Exception {
|
||||
String[] supportedLanguage = {"it","uk"};
|
||||
configurationService.setProperty("default.locale","it");
|
||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
||||
// These clears have to happen so that the config is actually reloaded in those classes. This is needed for
|
||||
// the properties that we're altering above and this is only used within the tests
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
|
||||
Locale uk = new Locale("uk");
|
||||
Locale it = new Locale("it");
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token)
|
||||
.perform(get("/api/submission/vocabularies/common_iso_languages/entries")
|
||||
.param("size", "2")
|
||||
.locale(it))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("N/A", "", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Inglese (USA)", "en_US", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.entries[*].authority").doesNotExist())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(12)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(6)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
|
||||
getClient(token)
|
||||
.perform(get("/api/submission/vocabularies/common_iso_languages/entries")
|
||||
.param("size", "2")
|
||||
.locale(uk))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.containsInAnyOrder(
|
||||
VocabularyMatcher.matchVocabularyEntry("N/A", "", "vocabularyEntry"),
|
||||
VocabularyMatcher.matchVocabularyEntry("Американська (USA)", "en_US", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.entries[*].authority").doesNotExist())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(12)))
|
||||
.andExpect(jsonPath("$.page.totalPages", Matchers.is(6)))
|
||||
.andExpect(jsonPath("$.page.size", Matchers.is(2)));
|
||||
|
||||
configurationService.setProperty("default.locale","en");
|
||||
configurationService.setProperty("webui.supported.locales",null);
|
||||
submissionFormRestRepository.reload();
|
||||
DCInputAuthority.reset();
|
||||
pluginService.clearNamedPluginClasses();
|
||||
cas.clearCache();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void correctSolrQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/submission/vocabularies/SolrAuthorAuthority/entries")
|
||||
.param("filter", "Shirasaka")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.contains(
|
||||
VocabularyMatcher.matchVocabularyEntry("Shirasaka, Seiko", "Shirasaka, Seiko", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$._embedded.entries[0].authority").isNotEmpty())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsSolrQueryTest() throws Exception {
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(
|
||||
get("/api/submission/vocabularies/SolrAuthorAuthority/entries")
|
||||
.param("filter", "Smith")
|
||||
.param("size", "1000"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataAndCollectionTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Test collection")
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection")
|
||||
.param("metadata", "dc.type")
|
||||
.param("collection", collection.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$", is(
|
||||
VocabularyMatcher.matchProperties("common_types", "common_types", true, false)
|
||||
)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataAndCollectionUnprocessableEntityTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Test collection")
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection")
|
||||
.param("metadata", "dc.not.exist")
|
||||
.param("collection", collection.getID().toString()))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
|
||||
getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection")
|
||||
.param("metadata", "dc.type")
|
||||
.param("collection", UUID.randomUUID().toString()))
|
||||
.andExpect(status().isUnprocessableEntity());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findByMetadataAndCollectionBadRequestTest() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
Collection collection = CollectionBuilder.createCollection(context, parentCommunity)
|
||||
.withName("Test collection")
|
||||
.build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
//missing metadata
|
||||
getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection")
|
||||
.param("collection", collection.getID().toString()))
|
||||
.andExpect(status().isBadRequest());
|
||||
|
||||
//missing collection
|
||||
getClient(token).perform(get("/api/submission/vocabularies/search/byMetadataAndCollection")
|
||||
.param("metadata", "dc.type"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkedEntitiesWithExactParamTest() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/common_types/entries")
|
||||
.param("filter", "Animation")
|
||||
.param("exact", "true"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.entries", Matchers.contains(
|
||||
VocabularyMatcher.matchVocabularyEntry("Animation", "Animation", "vocabularyEntry")
|
||||
)))
|
||||
.andExpect(jsonPath("$.page.totalElements", Matchers.is(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linkedEntitiesWithFilterAndEntryIdTest() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
getClient(token).perform(get("/api/submission/vocabularies/srsc/entries")
|
||||
.param("filter", "Research")
|
||||
.param("entryID", "VR131402"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
}
|
@@ -28,8 +28,8 @@ public class SubmissionFormFieldMatcher {
|
||||
|
||||
/**
|
||||
* Shortcut for the
|
||||
* {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String)}
|
||||
* with a null style
|
||||
* {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String, String)}
|
||||
* with a null style and vocabulary name
|
||||
*
|
||||
* @param type
|
||||
* the expected input type
|
||||
@@ -53,7 +53,9 @@ public class SubmissionFormFieldMatcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the json representation of a submission form
|
||||
* Shortcut for the
|
||||
* {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String, String)}
|
||||
* with a null controlled vocabulary
|
||||
*
|
||||
* @param type
|
||||
* the expected input type
|
||||
@@ -74,13 +76,45 @@ public class SubmissionFormFieldMatcher {
|
||||
* @return a Matcher for all the condition above
|
||||
*/
|
||||
public static Matcher<? super Object> matchFormFieldDefinition(String type, String label, String mandatoryMessage,
|
||||
boolean repeatable,
|
||||
String hints, String style, String metadata) {
|
||||
boolean repeatable,
|
||||
String hints, String style, String metadata) {
|
||||
return matchFormFieldDefinition(type, label, mandatoryMessage, repeatable, hints, style, metadata, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the json representation of a submission form
|
||||
*
|
||||
* @param type
|
||||
* the expected input type
|
||||
* @param label
|
||||
* the expected label
|
||||
* @param mandatoryMessage
|
||||
* the expected mandatoryMessage, can be null. If not empty the field is expected to be flagged as
|
||||
* mandatory
|
||||
* @param repeatable
|
||||
* the expected repeatable flag
|
||||
* @param hints
|
||||
* the expected hints message
|
||||
* @param style
|
||||
* the expected style for the field, can be null. If null the corresponding json path is expected to be
|
||||
* missing
|
||||
* @param metadata
|
||||
* the expected metadata
|
||||
* @param controlled vocabulary
|
||||
* the expected controlled vocabulary, can be null. If null the corresponding json path is expected to be
|
||||
* missing
|
||||
* @return a Matcher for all the condition above
|
||||
*/
|
||||
public static Matcher<? super Object> matchFormFieldDefinition(String type, String label, String mandatoryMessage,
|
||||
boolean repeatable, String hints, String style,
|
||||
String metadata, String controlledVocabulary) {
|
||||
return allOf(
|
||||
// check each field definition
|
||||
hasJsonPath("$.input.type", is(type)),
|
||||
hasJsonPath("$.label", containsString(label)),
|
||||
hasJsonPath("$.selectableMetadata[0].metadata", is(metadata)),
|
||||
controlledVocabulary != null ? hasJsonPath("$.selectableMetadata[0].controlledVocabulary",
|
||||
is(controlledVocabulary)) : hasNoJsonPath("$.selectableMetadata[0].controlledVocabulary"),
|
||||
mandatoryMessage != null ? hasJsonPath("$.mandatoryMessage", containsString(mandatoryMessage)) :
|
||||
hasNoJsonPath("$.mandatoryMessage"),
|
||||
hasJsonPath("$.mandatory", is(mandatoryMessage != null)),
|
||||
|
@@ -8,7 +8,6 @@
|
||||
package org.dspace.app.rest.matcher;
|
||||
|
||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
||||
import static org.dspace.app.rest.matcher.HalMatcher.matchEmbeds;
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
@@ -18,20 +17,20 @@ import org.hamcrest.Matcher;
|
||||
/**
|
||||
* This matcher has been created so that we can use a predefined Matcher class to verify Authority Entries
|
||||
*/
|
||||
public class AuthorityEntryMatcher {
|
||||
public class VocabularyEntryDetailsMatcher {
|
||||
|
||||
private AuthorityEntryMatcher() {
|
||||
private VocabularyEntryDetailsMatcher() {
|
||||
}
|
||||
|
||||
public static Matcher<? super Object> matchAuthorityEntry(String id, String display, String value) {
|
||||
return allOf(
|
||||
matchProperties(id, display, value),
|
||||
matchLinks());
|
||||
matchLinks(id));
|
||||
}
|
||||
|
||||
public static Matcher<? super Object> matchLinks() {
|
||||
public static Matcher<? super Object> matchLinks(String id) {
|
||||
return allOf(
|
||||
hasJsonPath("$._links.self.href", containsString("api/integration/authority/")));
|
||||
hasJsonPath("$._links.self.href", containsString("api/submission/vocabularyEntryDetails/" + id)));
|
||||
}
|
||||
|
||||
private static Matcher<? super Object> matchProperties(String id, String display, String value) {
|
||||
@@ -39,16 +38,7 @@ public class AuthorityEntryMatcher {
|
||||
hasJsonPath("$.id", is(id)),
|
||||
hasJsonPath("$.display", is(display)),
|
||||
hasJsonPath("$.value", is(value)),
|
||||
hasJsonPath("$.type", is("authority"))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a matcher for all expected embeds when the full projection is requested.
|
||||
*/
|
||||
public static Matcher<? super Object> matchFullEmbeds() {
|
||||
return matchEmbeds(
|
||||
"authorityEntries"
|
||||
hasJsonPath("$.type", is("vocabularyEntryDetail"))
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author mykhaylo
|
||||
*
|
||||
*/
|
||||
public class VocabularyMatcher {
|
||||
|
||||
private VocabularyMatcher() {}
|
||||
|
||||
public static Matcher<? super Object> matchProperties(String id, String name,
|
||||
boolean scrollable, boolean hierarchical) {
|
||||
return allOf(
|
||||
hasJsonPath("$.id", is(id)),
|
||||
hasJsonPath("$.name", is(name)),
|
||||
hasJsonPath("$.scrollable", is(scrollable)),
|
||||
hasJsonPath("$.hierarchical", is(hierarchical)),
|
||||
hasJsonPath("$.type", is("vocabulary"))
|
||||
);
|
||||
}
|
||||
|
||||
public static Matcher<? super Object> matchVocabularyEntry(String display, String value, String type) {
|
||||
return allOf(
|
||||
hasJsonPath("$.display", is(display)),
|
||||
hasJsonPath("$.value", is(value)),
|
||||
hasJsonPath("$.type", is(type))
|
||||
);
|
||||
}
|
||||
}
|
@@ -58,6 +58,7 @@ or refer to the Web site http://dspace-dev.dsi.uminho.pt.
|
||||
</xs:all>
|
||||
<xs:attribute name="id" type="xs:ID" use="optional"/>
|
||||
<xs:attribute name="label" type="xs:string" use="required"/>
|
||||
<xs:attribute name="selectable" type="xs:boolean" default="true"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
|
@@ -1486,7 +1486,7 @@ orcid.url = https://orcid.org/
|
||||
## eg: nsi, srsc.
|
||||
## Each DSpaceControlledVocabulary plugin comes with three configuration options:
|
||||
# vocabulary.plugin._plugin_.hierarchy.store = <true|false> # default: true
|
||||
# vocabulary.plugin._plugin_.hierarchy.suggest = <true|false> # default: true
|
||||
# vocabulary.plugin._plugin_.hierarchy.suggest = <true|false> # default: false
|
||||
# vocabulary.plugin._plugin_.delimiter = "<string>" # default: "::"
|
||||
##
|
||||
## An example using "srsc" can be found later in this section
|
||||
|
Reference in New Issue
Block a user