mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-18 15:33:09 +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;
|
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 Map<String, String> extras = new HashMap<String, String>();
|
||||||
|
|
||||||
public Choice() {
|
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) {
|
public Choice(String authority, String value, String label) {
|
||||||
this.authority = authority;
|
this.authority = authority;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.label = label;
|
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) {
|
public Choice(String authority, String label, String value, Map<String, String> extras) {
|
||||||
this.authority = authority;
|
this.authority = authority;
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.extras = extras;
|
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;
|
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
|
* Plugin interface that supplies an authority control mechanism for
|
||||||
@@ -17,7 +20,7 @@ import org.dspace.content.Collection;
|
|||||||
* @see ChoiceAuthorityServiceImpl
|
* @see ChoiceAuthorityServiceImpl
|
||||||
* @see MetadataAuthorityServiceImpl
|
* @see MetadataAuthorityServiceImpl
|
||||||
*/
|
*/
|
||||||
public interface ChoiceAuthority {
|
public interface ChoiceAuthority extends NameAwarePlugin {
|
||||||
/**
|
/**
|
||||||
* Get all values from the authority that match the preferred value.
|
* Get all values from the authority that match the preferred value.
|
||||||
* Note that the offering was entered by the user and may contain
|
* 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,
|
* defaultSelected index in the Choices instance to the choice, if any,
|
||||||
* that matches the value.
|
* that matches the value.
|
||||||
*
|
*
|
||||||
* @param field being matched for
|
|
||||||
* @param text user's value to match
|
* @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 start choice at which to start, 0 is first.
|
||||||
* @param limit maximum number of choices to return, 0 for no limit.
|
* @param limit maximum number of choices to return, 0 for no limit.
|
||||||
* @param locale explicit localization key if available, or null
|
* @param locale explicit localization key if available, or null
|
||||||
* @return a Choices object (never 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
|
* 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
|
* This call is typically used in non-interactive metadata ingest
|
||||||
* where there is no interactive agent to choose from among options.
|
* where there is no interactive agent to choose from among options.
|
||||||
*
|
*
|
||||||
* @param field being matched for
|
|
||||||
* @param text user's value to match
|
* @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
|
* @param locale explicit localization key if available, or null
|
||||||
* @return a Choices object (never null) with 1 or 0 values.
|
* @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)
|
* 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
|
* This may get called many times while populating a Web page so it should
|
||||||
* be implemented as efficiently as possible.
|
* be implemented as efficiently as possible.
|
||||||
*
|
*
|
||||||
* @param field being matched for
|
|
||||||
* @param key authority key known to this authority.
|
* @param key authority key known to this authority.
|
||||||
* @param locale explicit localization key if available, or null
|
* @param locale explicit localization key if available, or null
|
||||||
* @return descriptive label - should always return something, never 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() {
|
default boolean isHierarchical() {
|
||||||
return false;
|
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() {
|
default boolean isScrollable() {
|
||||||
return false;
|
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();
|
Choice result = new Choice();
|
||||||
result.authority = authKey;
|
result.authority = authKey;
|
||||||
result.label = getLabel(fieldKey, authKey, locale);
|
result.label = getLabel(authKey, locale);
|
||||||
result.value = getLabel(fieldKey, authKey, locale);
|
result.value = getValue(authKey, locale);
|
||||||
|
result.extras.putAll(getExtra(authKey, locale));
|
||||||
return result;
|
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;
|
package org.dspace.content.authority;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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.DCInputSet;
|
||||||
import org.dspace.app.util.DCInputsReader;
|
import org.dspace.app.util.DCInputsReader;
|
||||||
import org.dspace.app.util.DCInputsReaderException;
|
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.Collection;
|
||||||
import org.dspace.content.MetadataValue;
|
import org.dspace.content.MetadataValue;
|
||||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||||
@@ -54,23 +60,37 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
// map of field key to authority plugin
|
// map of field key to authority plugin
|
||||||
protected Map<String, ChoiceAuthority> controller = new HashMap<String, ChoiceAuthority>();
|
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
|
// map of field key to presentation type
|
||||||
protected Map<String, String> presentation = new HashMap<String, String>();
|
protected Map<String, String> presentation = new HashMap<String, String>();
|
||||||
|
|
||||||
// map of field key to closed value
|
// map of field key to closed value
|
||||||
protected Map<String, Boolean> closed = new HashMap<String, Boolean>();
|
protected Map<String, Boolean> closed = new HashMap<String, Boolean>();
|
||||||
|
|
||||||
// map of authority name to field key
|
// flag to track the initialization status of the service
|
||||||
protected Map<String, String> authorities = new HashMap<String, String>();
|
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)
|
@Autowired(required = true)
|
||||||
protected ConfigurationService configurationService;
|
protected ConfigurationService configurationService;
|
||||||
@Autowired(required = true)
|
@Autowired(required = true)
|
||||||
protected PluginService pluginService;
|
protected PluginService pluginService;
|
||||||
|
|
||||||
private final String CHOICES_PLUGIN_PREFIX = "choices.plugin.";
|
final static String CHOICES_PLUGIN_PREFIX = "choices.plugin.";
|
||||||
private final String CHOICES_PRESENTATION_PREFIX = "choices.presentation.";
|
final static String CHOICES_PRESENTATION_PREFIX = "choices.presentation.";
|
||||||
private final String CHOICES_CLOSED_PREFIX = "choices.closed.";
|
final static String CHOICES_CLOSED_PREFIX = "choices.closed.";
|
||||||
|
|
||||||
protected ChoiceAuthorityServiceImpl() {
|
protected ChoiceAuthorityServiceImpl() {
|
||||||
}
|
}
|
||||||
@@ -96,10 +116,25 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getChoiceAuthoritiesNames() {
|
public Set<String> getChoiceAuthoritiesNames() {
|
||||||
if (authorities.keySet().isEmpty()) {
|
init();
|
||||||
loadChoiceAuthorityConfigurations();
|
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
|
@Override
|
||||||
@@ -112,59 +147,62 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
@Override
|
@Override
|
||||||
public Choices getMatches(String fieldKey, String query, Collection collection,
|
public Choices getMatches(String fieldKey, String query, Collection collection,
|
||||||
int start, int limit, String locale) {
|
int start, int limit, String locale) {
|
||||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||||
if (ma == null) {
|
if (ma == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"No choices plugin was configured for field \"" + fieldKey
|
"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
|
@Override
|
||||||
public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale,
|
public Choices getMatches(String fieldKey, String query, Collection collection, int start, int limit, String locale,
|
||||||
boolean externalInput) {
|
boolean externalInput) {
|
||||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||||
if (ma == null) {
|
if (ma == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"No choices plugin was configured for field \"" + fieldKey
|
"No choices plugin was configured for field \"" + fieldKey
|
||||||
+ "\".");
|
+ "\", collection=" + collection.getID().toString() + ".");
|
||||||
}
|
}
|
||||||
if (externalInput && ma instanceof SolrAuthority) {
|
if (externalInput && ma instanceof SolrAuthority) {
|
||||||
((SolrAuthority) ma).addExternalResultsInNextMatches();
|
((SolrAuthority) ma).addExternalResultsInNextMatches();
|
||||||
}
|
}
|
||||||
return ma.getMatches(fieldKey, query, collection, start, limit, locale);
|
return ma.getMatches(query, start, limit, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getBestMatch(String fieldKey, String query, Collection collection,
|
public Choices getBestMatch(String fieldKey, String query, Collection collection,
|
||||||
String locale) {
|
String locale) {
|
||||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||||
if (ma == null) {
|
if (ma == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"No choices plugin was configured for field \"" + fieldKey
|
"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
|
@Override
|
||||||
public String getLabel(MetadataValue metadataValue, String locale) {
|
public String getLabel(MetadataValue metadataValue, Collection collection, String locale) {
|
||||||
return getLabel(metadataValue.getMetadataField().toString(), metadataValue.getAuthority(), locale);
|
return getLabel(metadataValue.getMetadataField().toString(), collection, metadataValue.getAuthority(), locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel(String fieldKey, String authKey, String locale) {
|
public String getLabel(String fieldKey, Collection collection, String authKey, String locale) {
|
||||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(fieldKey);
|
ChoiceAuthority ma = getAuthorityByFieldKeyCollection(fieldKey, collection);
|
||||||
if (ma == null) {
|
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
|
@Override
|
||||||
public boolean isChoicesConfigured(String fieldKey) {
|
public boolean isChoicesConfigured(String fieldKey, Collection collection) {
|
||||||
return getChoiceAuthorityMap().containsKey(fieldKey);
|
return getAuthorityByFieldKeyCollection(fieldKey, collection) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -178,8 +216,14 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getVariants(MetadataValue metadataValue) {
|
public List<String> getVariants(MetadataValue metadataValue, Collection collection) {
|
||||||
ChoiceAuthority ma = getChoiceAuthorityMap().get(metadataValue.getMetadataField().toString());
|
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) {
|
if (ma instanceof AuthorityVariantsSupport) {
|
||||||
AuthorityVariantsSupport avs = (AuthorityVariantsSupport) ma;
|
AuthorityVariantsSupport avs = (AuthorityVariantsSupport) ma;
|
||||||
return avs.getVariants(metadataValue.getAuthority(), metadataValue.getLanguage());
|
return avs.getVariants(metadataValue.getAuthority(), metadataValue.getLanguage());
|
||||||
@@ -189,42 +233,53 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getChoiceAuthorityName(String schema, String element, String qualifier) {
|
public String getChoiceAuthorityName(String schema, String element, String qualifier, Collection collection) {
|
||||||
String makeFieldKey = makeFieldKey(schema, element, qualifier);
|
init();
|
||||||
if (getChoiceAuthorityMap().containsKey(makeFieldKey)) {
|
String fieldKey = makeFieldKey(schema, element, qualifier);
|
||||||
for (String key : this.authorities.keySet()) {
|
// check if there is an authority configured for the metadata valid for all the collections
|
||||||
if (this.authorities.get(key).equals(makeFieldKey)) {
|
if (controller.containsKey(fieldKey)) {
|
||||||
return key;
|
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) {
|
protected String makeFieldKey(String schema, String element, String qualifier) {
|
||||||
return Utils.standardize(schema, element, 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
|
@Override
|
||||||
public void clearCache() {
|
public void clearCache() {
|
||||||
controller.clear();
|
controller.clear();
|
||||||
authorities.clear();
|
authorities.clear();
|
||||||
|
presentation.clear();
|
||||||
|
closed.clear();
|
||||||
|
controllerFormDefinitions.clear();
|
||||||
|
authoritiesFormDefinitions.clear();
|
||||||
|
itemSubmissionConfigReader = null;
|
||||||
|
initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadChoiceAuthorityConfigurations() {
|
private void loadChoiceAuthorityConfigurations() {
|
||||||
// Get all configuration keys starting with a given prefix
|
// Get all configuration keys starting with a given prefix
|
||||||
List<String> propKeys = configurationService.getPropertyKeys(CHOICES_PLUGIN_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);
|
"Skipping invalid configuration for " + key + " because named plugin not found: " + authorityName);
|
||||||
continue;
|
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);
|
log.debug("Choice Control: For field=" + fkey + ", Plugin=" + ma);
|
||||||
}
|
}
|
||||||
autoRegisterChoiceAuthorityFromInputReader();
|
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() {
|
private void autoRegisterChoiceAuthorityFromInputReader() {
|
||||||
try {
|
try {
|
||||||
|
List<SubmissionConfig> submissionConfigs = itemSubmissionConfigReader
|
||||||
|
.getAllSubmissionConfigs(Integer.MAX_VALUE, 0);
|
||||||
DCInputsReader dcInputsReader = new DCInputsReader();
|
DCInputsReader dcInputsReader = new DCInputsReader();
|
||||||
for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) {
|
|
||||||
|
// 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();
|
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||||
for (DCInput[] dcrows : dcinputs) {
|
for (DCInput[] dcrows : dcinputs) {
|
||||||
for (DCInput dcinput : dcrows) {
|
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())
|
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
&& !StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||||
String authorityName = dcinput.getPairsType();
|
authorityName = dcinput.getPairsType();
|
||||||
if (StringUtils.isBlank(authorityName)) {
|
} else if (StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||||
authorityName = 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(),
|
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||||
dcinput.getQualifier());
|
dcinput.getQualifier());
|
||||||
ChoiceAuthority ca = controller.get(authorityName);
|
ChoiceAuthority ca = controller.get(authorityName);
|
||||||
if (ca == null) {
|
if (ca == null) {
|
||||||
InputFormSelfRegisterWrapperAuthority ifa = new
|
ca = (ChoiceAuthority) pluginService
|
||||||
InputFormSelfRegisterWrapperAuthority();
|
|
||||||
if (controller.containsKey(fieldKey)) {
|
|
||||||
ifa = (InputFormSelfRegisterWrapperAuthority) controller.get(fieldKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
ChoiceAuthority ma = (ChoiceAuthority) pluginService
|
|
||||||
.getNamedPlugin(ChoiceAuthority.class, authorityName);
|
.getNamedPlugin(ChoiceAuthority.class, authorityName);
|
||||||
if (ma == null) {
|
if (ca == null) {
|
||||||
log.warn("Skipping invalid configuration for " + fieldKey
|
throw new IllegalStateException("Invalid configuration for " + fieldKey
|
||||||
+ " because named plugin not found: " + authorityName);
|
+ " in submission definition " + submissionName
|
||||||
continue;
|
+ ", 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) {
|
} 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
|
* Return map of key to presentation
|
||||||
*
|
*
|
||||||
@@ -370,26 +481,6 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
return closed;
|
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
|
@Override
|
||||||
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName) {
|
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName) {
|
||||||
ChoiceAuthority ma = (ChoiceAuthority)
|
ChoiceAuthority ma = (ChoiceAuthority)
|
||||||
@@ -401,4 +492,68 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
|||||||
}
|
}
|
||||||
return ma;
|
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.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
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.ArrayUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.app.util.DCInputsReader;
|
import org.dspace.app.util.DCInputsReader;
|
||||||
import org.dspace.app.util.DCInputsReaderException;
|
import org.dspace.app.util.DCInputsReaderException;
|
||||||
import org.dspace.content.Collection;
|
import org.dspace.core.I18nUtil;
|
||||||
import org.dspace.core.SelfNamedPlugin;
|
import org.dspace.core.SelfNamedPlugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,16 +50,38 @@ import org.dspace.core.SelfNamedPlugin;
|
|||||||
public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority {
|
public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority {
|
||||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DCInputAuthority.class);
|
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;
|
private static String pluginNames[] = null;
|
||||||
|
|
||||||
public DCInputAuthority() {
|
public DCInputAuthority() {
|
||||||
super();
|
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() {
|
public static String[] getPluginNames() {
|
||||||
if (pluginNames == null) {
|
if (pluginNames == null) {
|
||||||
initPluginNames();
|
initPluginNames();
|
||||||
@@ -63,20 +91,28 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static synchronized void initPluginNames() {
|
private static synchronized void initPluginNames() {
|
||||||
|
Locale[] locales = I18nUtil.getSupportedLocales();
|
||||||
|
Set<String> names = new HashSet<String>();
|
||||||
if (pluginNames == null) {
|
if (pluginNames == null) {
|
||||||
try {
|
try {
|
||||||
if (dci == null) {
|
dcis = new HashMap<Locale, DCInputsReader>();
|
||||||
dci = new 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) {
|
} catch (DCInputsReaderException e) {
|
||||||
log.error("Failed reading DCInputs initialization: ", 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()]);
|
pluginNames = names.toArray(new String[names.size()]);
|
||||||
log.debug("Got plugin names = " + Arrays.deepToString(pluginNames));
|
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
|
// once-only load of values and labels
|
||||||
private void init() {
|
private void init() {
|
||||||
if (values == null) {
|
if (values == null) {
|
||||||
|
values = new HashMap<String, String[]>();
|
||||||
|
labels = new HashMap<String, String[]>();
|
||||||
String pname = this.getPluginInstanceName();
|
String pname = this.getPluginInstanceName();
|
||||||
|
for (Locale l : dcis.keySet()) {
|
||||||
|
DCInputsReader dci = dcis.get(l);
|
||||||
List<String> pairs = dci.getPairs(pname);
|
List<String> pairs = dci.getPairs(pname);
|
||||||
if (pairs != null) {
|
if (pairs != null) {
|
||||||
values = new String[pairs.size() / 2];
|
String[] valuesLocale = new String[pairs.size() / 2];
|
||||||
labels = new String[pairs.size() / 2];
|
String[]labelsLocale = new String[pairs.size() / 2];
|
||||||
for (int i = 0; i < pairs.size(); i += 2) {
|
for (int i = 0; i < pairs.size(); i += 2) {
|
||||||
labels[i / 2] = pairs.get(i);
|
labelsLocale[i / 2] = pairs.get(i);
|
||||||
values[i / 2] = pairs.get(i + 1);
|
valuesLocale[i / 2] = pairs.get(i + 1);
|
||||||
}
|
}
|
||||||
log.debug("Found pairs for name=" + pname);
|
values.put(l.getLanguage(), valuesLocale);
|
||||||
|
labels.put(l.getLanguage(), labelsLocale);
|
||||||
|
log.debug("Found pairs for name=" + pname + ",locale=" + l);
|
||||||
} else {
|
} else {
|
||||||
log.error("Failed to find any pairs for name=" + pname, new IllegalStateException());
|
log.error("Failed to find any pairs for name=" + pname, new IllegalStateException());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@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();
|
init();
|
||||||
|
Locale currentLocale = I18nUtil.getSupportedLocale(locale);
|
||||||
|
String[] valuesLocale = values.get(currentLocale.getLanguage());
|
||||||
|
String[] labelsLocale = labels.get(currentLocale.getLanguage());
|
||||||
int dflt = -1;
|
int dflt = -1;
|
||||||
Choice v[] = new Choice[values.length];
|
int found = 0;
|
||||||
for (int i = 0; i < values.length; ++i) {
|
List<Choice> v = new ArrayList<Choice>();
|
||||||
v[i] = new Choice(values[i], values[i], labels[i]);
|
for (int i = 0; i < valuesLocale.length; ++i) {
|
||||||
if (values[i].equalsIgnoreCase(query)) {
|
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;
|
dflt = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Choices(v, 0, v.length, Choices.CF_AMBIGUOUS, false, dflt);
|
found++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Choice[] vArray = new Choice[v.size()];
|
||||||
|
return new Choices(v.toArray(vArray), start, found, Choices.CF_AMBIGUOUS, false, dflt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
public Choices getBestMatch(String text, String locale) {
|
||||||
init();
|
init();
|
||||||
for (int i = 0; i < values.length; ++i) {
|
Locale currentLocale = I18nUtil.getSupportedLocale(locale);
|
||||||
if (text.equalsIgnoreCase(values[i])) {
|
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];
|
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);
|
return new Choices(v, 0, v.length, Choices.CF_UNCERTAIN, false, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,19 +187,31 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel(String field, String key, String locale) {
|
public String getLabel(String key, String locale) {
|
||||||
init();
|
init();
|
||||||
|
|
||||||
|
// Get default if locale is empty
|
||||||
|
if (StringUtils.isBlank(locale)) {
|
||||||
|
locale = I18nUtil.getDefaultLocale().getLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] labelsLocale = labels.get(locale);
|
||||||
int pos = -1;
|
int pos = -1;
|
||||||
for (int i = 0; i < values.length; i++) {
|
for (int i = 0; i < labelsLocale.length; i++) {
|
||||||
if (values[i].equals(key)) {
|
if (labelsLocale[i].equals(key)) {
|
||||||
pos = i;
|
pos = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pos != -1) {
|
if (pos != -1) {
|
||||||
return labels[pos];
|
return labelsLocale[pos];
|
||||||
} else {
|
} else {
|
||||||
return "UNKNOWN KEY " + key;
|
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.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import javax.xml.xpath.XPath;
|
import javax.xml.xpath.XPath;
|
||||||
import javax.xml.xpath.XPathConstants;
|
import javax.xml.xpath.XPathConstants;
|
||||||
import javax.xml.xpath.XPathExpressionException;
|
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.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.core.SelfNamedPlugin;
|
import org.dspace.core.SelfNamedPlugin;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
@@ -54,25 +55,35 @@ import org.xml.sax.InputSource;
|
|||||||
* @author Michael B. Klein
|
* @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);
|
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DSpaceControlledVocabulary.class);
|
||||||
protected static String xpathTemplate = "//node[contains(translate(@label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'," +
|
protected static String xpathTemplate = "//node[contains(translate(@label,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'," +
|
||||||
"'abcdefghijklmnopqrstuvwxyz'),'%s')]";
|
"'abcdefghijklmnopqrstuvwxyz'),'%s')]";
|
||||||
protected static String idTemplate = "//node[@id = '%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 static String pluginNames[] = null;
|
||||||
|
|
||||||
protected String vocabularyName = null;
|
protected String vocabularyName = null;
|
||||||
protected InputSource vocabulary = null;
|
protected InputSource vocabulary = null;
|
||||||
protected Boolean suggestHierarchy = true;
|
protected Boolean suggestHierarchy = false;
|
||||||
protected Boolean storeHierarchy = true;
|
protected Boolean storeHierarchy = true;
|
||||||
protected String hierarchyDelimiter = "::";
|
protected String hierarchyDelimiter = "::";
|
||||||
|
protected Integer preloadLevel = 1;
|
||||||
|
|
||||||
public DSpaceControlledVocabulary() {
|
public DSpaceControlledVocabulary() {
|
||||||
super();
|
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() {
|
public static String[] getPluginNames() {
|
||||||
if (pluginNames == null) {
|
if (pluginNames == null) {
|
||||||
initPluginNames();
|
initPluginNames();
|
||||||
@@ -112,6 +123,7 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
|||||||
String configurationPrefix = "vocabulary.plugin." + vocabularyName;
|
String configurationPrefix = "vocabulary.plugin." + vocabularyName;
|
||||||
storeHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.store", storeHierarchy);
|
storeHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.store", storeHierarchy);
|
||||||
suggestHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.suggest", suggestHierarchy);
|
suggestHierarchy = config.getBooleanProperty(configurationPrefix + ".hierarchy.suggest", suggestHierarchy);
|
||||||
|
preloadLevel = config.getIntProperty(configurationPrefix + ".hierarchy.preloadLevel", preloadLevel);
|
||||||
String configuredDelimiter = config.getProperty(configurationPrefix + ".delimiter");
|
String configuredDelimiter = config.getProperty(configurationPrefix + ".delimiter");
|
||||||
if (configuredDelimiter != null) {
|
if (configuredDelimiter != null) {
|
||||||
hierarchyDelimiter = configuredDelimiter.replaceAll("(^\"|\"$)", "");
|
hierarchyDelimiter = configuredDelimiter.replaceAll("(^\"|\"$)", "");
|
||||||
@@ -142,7 +154,7 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
init();
|
||||||
log.debug("Getting matches for '" + text + "'");
|
log.debug("Getting matches for '" + text + "'");
|
||||||
String xpathExpression = "";
|
String xpathExpression = "";
|
||||||
@@ -151,59 +163,60 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
|||||||
xpathExpression += String.format(xpathTemplate, textHierarchy[i].replaceAll("'", "'").toLowerCase());
|
xpathExpression += String.format(xpathTemplate, textHierarchy[i].replaceAll("'", "'").toLowerCase());
|
||||||
}
|
}
|
||||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
Choice[] choices;
|
int total = 0;
|
||||||
|
List<Choice> choices = new ArrayList<Choice>();
|
||||||
try {
|
try {
|
||||||
NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET);
|
NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET);
|
||||||
String[] authorities = new String[results.getLength()];
|
total = results.getLength();
|
||||||
String[] values = new String[results.getLength()];
|
choices = getChoicesFromNodeList(results, start, limit);
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (XPathExpressionException e) {
|
} 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
|
@Override
|
||||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
public Choices getBestMatch(String text, String locale) {
|
||||||
init();
|
init();
|
||||||
log.debug("Getting best match for '" + text + "'");
|
log.debug("Getting best matches for '" + text + "'");
|
||||||
return getMatches(field, text, collection, 0, 2, locale);
|
String xpathExpression = "";
|
||||||
|
String[] textHierarchy = text.split(hierarchyDelimiter, -1);
|
||||||
|
for (int i = 0; i < textHierarchy.length; i++) {
|
||||||
|
xpathExpression += String.format(labelTemplate, textHierarchy[i].replaceAll("'", "'"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getLabel(String field, String key, String locale) {
|
|
||||||
init();
|
|
||||||
String xpathExpression = String.format(idTemplate, key);
|
|
||||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
List<Choice> choices = new ArrayList<Choice>();
|
||||||
try {
|
try {
|
||||||
Node node = (Node) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODE);
|
NodeList results = (NodeList) xpath.evaluate(xpathExpression, vocabulary, XPathConstants.NODESET);
|
||||||
return node.getAttributes().getNamedItem("label").getNodeValue();
|
choices = getChoicesFromNodeList(results, 0, 1);
|
||||||
} catch (XPathExpressionException e) {
|
} 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
|
@Override
|
||||||
@@ -212,81 +225,227 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choice getChoice(String fieldKey, String authKey, String locale) {
|
public Choices getTopChoices(String authorityName, int start, int limit, String locale) {
|
||||||
init();
|
init();
|
||||||
log.debug("Getting matches for '" + authKey + "'");
|
String xpathExpression = rootTemplate;
|
||||||
String xpathExpression = String.format(idTemplate, authKey);
|
return getChoicesByXpath(xpathExpression, start, limit);
|
||||||
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) {
|
@Override
|
||||||
Choice choice = new Choice(authorities[0], values[0], labels[0]);
|
public Choices getChoicesByParent(String authorityName, String parentId, int start, int limit, String locale) {
|
||||||
if (StringUtils.isNotBlank(parent[0])) {
|
init();
|
||||||
choice.extras.put("parent", parent[0]);
|
String xpathExpression = String.format(idTemplate, parentId);
|
||||||
}
|
return getChoicesByXpath(xpathExpression, start, limit);
|
||||||
if (StringUtils.isNotBlank(note[0])) {
|
|
||||||
choice.extras.put("note", note[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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;
|
return choice;
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (XPathExpressionException e) {
|
} catch (XPathExpressionException e) {
|
||||||
log.warn(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void readNode(String[] authorities, String[] values, String[] labels, String[] parent, String[] notes,
|
@Override
|
||||||
int i, Node node) {
|
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);
|
String hierarchy = this.buildString(node);
|
||||||
if (this.suggestHierarchy) {
|
if (this.suggestHierarchy) {
|
||||||
labels[i] = hierarchy;
|
return hierarchy;
|
||||||
} else {
|
} else {
|
||||||
labels[i] = node.getAttributes().getNamedItem("label").getNodeValue();
|
return node.getAttributes().getNamedItem("label").getNodeValue();
|
||||||
}
|
}
|
||||||
if (this.storeHierarchy) {
|
|
||||||
values[i] = hierarchy;
|
|
||||||
} else {
|
|
||||||
values[i] = 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();
|
NodeList childNodes = node.getChildNodes();
|
||||||
for (int ci = 0; ci < childNodes.getLength(); ci++) {
|
for (int ci = 0; ci < childNodes.getLength(); ci++) {
|
||||||
Node firstChild = childNodes.item(ci);
|
Node firstChild = childNodes.item(ci);
|
||||||
if (firstChild != null && "hasNote".equals(firstChild.getNodeName())) {
|
if (firstChild != null && "hasNote".equals(firstChild.getNodeName())) {
|
||||||
String nodeValue = firstChild.getTextContent();
|
String nodeValue = firstChild.getTextContent();
|
||||||
if (StringUtils.isNotBlank(nodeValue)) {
|
if (StringUtils.isNotBlank(nodeValue)) {
|
||||||
notes[i] = nodeValue;
|
return nodeValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Node idAttr = node.getAttributes().getNamedItem("id");
|
return null;
|
||||||
if (null != idAttr) { // 'id' is optional
|
}
|
||||||
authorities[i] = idAttr.getNodeValue();
|
|
||||||
if (isHierarchical()) {
|
private List<String> getChildren(Node node) {
|
||||||
Node parentN = node.getParentNode();
|
List<String> children = new ArrayList<String>();
|
||||||
if (parentN != null) {
|
NodeList childNodes = node.getChildNodes();
|
||||||
parentN = parentN.getParentNode();
|
for (int ci = 0; ci < childNodes.getLength(); ci++) {
|
||||||
if (parentN != null) {
|
Node firstChild = childNodes.item(ci);
|
||||||
Node parentIdAttr = parentN.getAttributes().getNamedItem("id");
|
if (firstChild != null && "isComposedBy".equals(firstChild.getNodeName())) {
|
||||||
if (null != parentIdAttr) {
|
for (int cii = 0; cii < firstChild.getChildNodes().getLength(); cii++) {
|
||||||
parent[i] = parentIdAttr.getNodeValue();
|
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;
|
return children;
|
||||||
parent[i] = null;
|
}
|
||||||
|
|
||||||
|
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
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.MetadataField;
|
||||||
import org.dspace.content.authority.service.MetadataAuthorityService;
|
import org.dspace.content.authority.service.MetadataAuthorityService;
|
||||||
import org.dspace.content.service.MetadataFieldService;
|
import org.dspace.content.service.MetadataFieldService;
|
||||||
@@ -144,8 +139,6 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
|||||||
if (dmc >= Choices.CF_UNSET) {
|
if (dmc >= Choices.CF_UNSET) {
|
||||||
defaultMinConfidence = dmc;
|
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
|
* Give the minimal level of confidence required to consider valid an authority value
|
||||||
* for the given metadata.
|
* for the given metadata.
|
||||||
@@ -229,35 +221,4 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
|||||||
}
|
}
|
||||||
return copy;
|
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;
|
package org.dspace.content.authority;
|
||||||
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a *very* stupid test fixture for authority control, and also
|
* This is a *very* stupid test fixture for authority control, and also
|
||||||
* serves as a trivial example of an authority plugin implementation.
|
* serves as a trivial example of an authority plugin implementation.
|
||||||
*/
|
*/
|
||||||
public class SampleAuthority implements ChoiceAuthority {
|
public class SampleAuthority implements ChoiceAuthority {
|
||||||
|
private String pluginInstanceName;
|
||||||
|
|
||||||
protected static String values[] = {
|
protected static String values[] = {
|
||||||
"sun",
|
"sun",
|
||||||
"mon",
|
"mon",
|
||||||
@@ -35,7 +35,7 @@ public class SampleAuthority implements ChoiceAuthority {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@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;
|
int dflt = -1;
|
||||||
Choice v[] = new Choice[values.length];
|
Choice v[] = new Choice[values.length];
|
||||||
for (int i = 0; i < values.length; ++i) {
|
for (int i = 0; i < values.length; ++i) {
|
||||||
@@ -48,7 +48,7 @@ public class SampleAuthority implements ChoiceAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
for (int i = 0; i < values.length; ++i) {
|
||||||
if (text.equalsIgnoreCase(values[i])) {
|
if (text.equalsIgnoreCase(values[i])) {
|
||||||
Choice v[] = new Choice[1];
|
Choice v[] = new Choice[1];
|
||||||
@@ -60,7 +60,17 @@ public class SampleAuthority implements ChoiceAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel(String field, String key, String locale) {
|
public String getLabel(String key, String locale) {
|
||||||
return labels[Integer.parseInt(key)];
|
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.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@@ -24,8 +25,9 @@ import org.dspace.authority.AuthorityValue;
|
|||||||
import org.dspace.authority.SolrAuthorityInterface;
|
import org.dspace.authority.SolrAuthorityInterface;
|
||||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
import org.dspace.authority.factory.AuthorityServiceFactory;
|
||||||
import org.dspace.authority.service.AuthorityValueService;
|
import org.dspace.authority.service.AuthorityValueService;
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
import org.dspace.core.ConfigurationManager;
|
||||||
|
import org.dspace.core.NameAwarePlugin;
|
||||||
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,7 +37,14 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
|||||||
* @author Mark Diggory (markd at atmire dot com)
|
* @author Mark Diggory (markd at atmire dot com)
|
||||||
*/
|
*/
|
||||||
public class SolrAuthority implements ChoiceAuthority {
|
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 =
|
protected SolrAuthorityInterface source =
|
||||||
DSpaceServicesFactory.getInstance().getServiceManager()
|
DSpaceServicesFactory.getInstance().getServiceManager()
|
||||||
.getServiceByName("AuthoritySource", SolrAuthorityInterface.class);
|
.getServiceByName("AuthoritySource", SolrAuthorityInterface.class);
|
||||||
@@ -45,8 +54,9 @@ public class SolrAuthority implements ChoiceAuthority {
|
|||||||
protected boolean externalResults = false;
|
protected boolean externalResults = false;
|
||||||
protected final AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance()
|
protected final AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance()
|
||||||
.getAuthorityValueService();
|
.getAuthorityValueService();
|
||||||
|
protected final ConfigurationService configurationService = DSpaceServicesFactory.getInstance()
|
||||||
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale,
|
.getConfigurationService();
|
||||||
|
public Choices getMatches(String text, int start, int limit, String locale,
|
||||||
boolean bestMatch) {
|
boolean bestMatch) {
|
||||||
if (limit == 0) {
|
if (limit == 0) {
|
||||||
limit = 10;
|
limit = 10;
|
||||||
@@ -193,13 +203,13 @@ public class SolrAuthority implements ChoiceAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
||||||
return getMatches(field, text, collection, start, limit, locale, true);
|
return getMatches(text, start, limit, locale, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
|
public Choices getBestMatch(String text, String locale) {
|
||||||
Choices matches = getMatches(field, text, collection, 0, 1, locale, false);
|
Choices matches = getMatches(text, 0, 1, locale, false);
|
||||||
if (matches.values.length != 0 && !matches.values[0].value.equalsIgnoreCase(text)) {
|
if (matches.values.length != 0 && !matches.values[0].value.equalsIgnoreCase(text)) {
|
||||||
matches = new Choices(false);
|
matches = new Choices(false);
|
||||||
}
|
}
|
||||||
@@ -207,7 +217,7 @@ public class SolrAuthority implements ChoiceAuthority {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel(String field, String key, String locale) {
|
public String getLabel(String key, String locale) {
|
||||||
try {
|
try {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
log.debug("requesting label for key " + key + " using locale " + locale);
|
log.debug("requesting label for key " + key + " using locale " + locale);
|
||||||
@@ -276,4 +286,23 @@ public class SolrAuthority implements ChoiceAuthority {
|
|||||||
public void addExternalResultsInNextMatches() {
|
public void addExternalResultsInNextMatches() {
|
||||||
this.externalResults = true;
|
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 java.util.List;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dspace.content.Collection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a *very* stupid test fixture for authority control with AuthorityVariantsSupport.
|
* 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)
|
* @author Andrea Bollini (CILEA)
|
||||||
*/
|
*/
|
||||||
public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport {
|
public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport {
|
||||||
|
private String pluginInstanceName;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getVariants(String key, String locale) {
|
public List<String> getVariants(String key, String locale) {
|
||||||
@@ -33,8 +33,7 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getMatches(String field, String text, Collection collection,
|
public Choices getMatches(String text, int start, int limit, String locale) {
|
||||||
int start, int limit, String locale) {
|
|
||||||
Choices choices = new Choices(false);
|
Choices choices = new Choices(false);
|
||||||
if (StringUtils.isNotBlank(text)) {
|
if (StringUtils.isNotBlank(text)) {
|
||||||
|
|
||||||
@@ -52,8 +51,7 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Choices getBestMatch(String field, String text, Collection collection,
|
public Choices getBestMatch(String text, String locale) {
|
||||||
String locale) {
|
|
||||||
Choices choices = new Choices(false);
|
Choices choices = new Choices(false);
|
||||||
if (StringUtils.isNotBlank(text)) {
|
if (StringUtils.isNotBlank(text)) {
|
||||||
|
|
||||||
@@ -70,10 +68,20 @@ public class TestAuthority implements ChoiceAuthority, AuthorityVariantsSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getLabel(String field, String key, String locale) {
|
public String getLabel(String key, String locale) {
|
||||||
if (StringUtils.isNotBlank(key)) {
|
if (StringUtils.isNotBlank(key)) {
|
||||||
return key.replaceAll("authority", "label");
|
return key.replaceAll("authority", "label");
|
||||||
}
|
}
|
||||||
return "Unknown";
|
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 element element of metadata field
|
||||||
* @param qualifier qualifier of metadata field
|
* @param qualifier qualifier of metadata field
|
||||||
* @return the name of the choice authority associated with the specified
|
* @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
|
* 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
|
* 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.
|
* the metadata field defined by schema,element,qualifier.
|
||||||
*
|
*
|
||||||
* @param metadataValue metadata value
|
* @param metadataValue metadata value
|
||||||
|
* @param collection Collection owner of Item
|
||||||
* @param locale explicit localization key if available
|
* @param locale explicit localization key if available
|
||||||
* @return label
|
* @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
|
* Wrapper that calls getLabel method of the plugin corresponding to
|
||||||
* the metadata field defined by single field key.
|
* the metadata field defined by single field key.
|
||||||
*
|
*
|
||||||
* @param fieldKey single string identifying metadata field
|
* @param fieldKey single string identifying metadata field
|
||||||
|
* @param collection Collection owner of Item
|
||||||
* @param locale explicit localization key if available
|
* @param locale explicit localization key if available
|
||||||
* @param authKey authority key
|
* @param authKey authority key
|
||||||
* @return label
|
* @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
|
* Predicate, is there a Choices configuration of any kind for the
|
||||||
* given metadata field?
|
* given metadata field?
|
||||||
*
|
*
|
||||||
* @param fieldKey single string identifying metadata field
|
* @param fieldKey single string identifying metadata field
|
||||||
|
* @param collection Collection owner of Item
|
||||||
* @return true if choices are configured for this field.
|
* @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
|
* Get the presentation keyword (should be "lookup", "select" or "suggest", but this
|
||||||
@@ -160,12 +163,14 @@ public interface ChoiceAuthorityService {
|
|||||||
* @param metadataValue metadata value
|
* @param metadataValue metadata value
|
||||||
* @return List of variants
|
* @return List of variants
|
||||||
*/
|
*/
|
||||||
public List<String> getVariants(MetadataValue metadataValue);
|
public List<String> getVariants(MetadataValue metadataValue, Collection collection);
|
||||||
|
|
||||||
public String getChoiceMetadatabyAuthorityName(String name);
|
|
||||||
|
|
||||||
public Choice getChoice(String fieldKey, String authKey, String locale);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,4 +178,49 @@ public interface ChoiceAuthorityService {
|
|||||||
*/
|
*/
|
||||||
public void clearCache();
|
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;
|
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
|
* 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 +
|
" for interface=" + iname +
|
||||||
" pluginName=" + name);
|
" pluginName=" + name);
|
||||||
Object result = pluginClass.newInstance();
|
Object result = pluginClass.newInstance();
|
||||||
if (result instanceof SelfNamedPlugin) {
|
if (result instanceof NameAwarePlugin) {
|
||||||
((SelfNamedPlugin) result).setPluginInstanceName(name);
|
((NameAwarePlugin) result).setPluginInstanceName(name);
|
||||||
}
|
}
|
||||||
return result;
|
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$
|
* @version $Revision$
|
||||||
* @see org.dspace.core.service.PluginService
|
* @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.
|
// the specific alias used to find the class that created this instance.
|
||||||
private String myName = null;
|
private String myName = null;
|
||||||
|
|
||||||
@@ -52,30 +52,13 @@ public abstract class SelfNamedPlugin {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public String getPluginInstanceName() {
|
public String getPluginInstanceName() {
|
||||||
return myName;
|
return myName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Set the name under which this plugin was instantiated.
|
public void setPluginInstanceName(String name) {
|
||||||
* 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) {
|
|
||||||
myName = name;
|
myName = name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ import org.apache.logging.log4j.Logger;
|
|||||||
import org.apache.solr.common.SolrInputDocument;
|
import org.apache.solr.common.SolrInputDocument;
|
||||||
import org.dspace.browse.BrowseException;
|
import org.dspace.browse.BrowseException;
|
||||||
import org.dspace.browse.BrowseIndex;
|
import org.dspace.browse.BrowseIndex;
|
||||||
|
import org.dspace.content.Collection;
|
||||||
import org.dspace.content.Item;
|
import org.dspace.content.Item;
|
||||||
import org.dspace.content.MetadataValue;
|
import org.dspace.content.MetadataValue;
|
||||||
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
import org.dspace.content.authority.service.ChoiceAuthorityService;
|
||||||
@@ -63,7 +64,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Item item = ((IndexableItem) indexableObject).getIndexedObject();
|
Item item = ((IndexableItem) indexableObject).getIndexedObject();
|
||||||
|
Collection collection = item.getOwningCollection();
|
||||||
// Get the currently configured browse indexes
|
// Get the currently configured browse indexes
|
||||||
BrowseIndex[] bis;
|
BrowseIndex[] bis;
|
||||||
try {
|
try {
|
||||||
@@ -175,7 +176,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
|||||||
true);
|
true);
|
||||||
if (!ignorePrefered) {
|
if (!ignorePrefered) {
|
||||||
preferedLabel = choiceAuthorityService
|
preferedLabel = choiceAuthorityService
|
||||||
.getLabel(values.get(x), values.get(x).getLanguage());
|
.getLabel(values.get(x), collection, values.get(x).getLanguage());
|
||||||
}
|
}
|
||||||
List<String> variants = null;
|
List<String> variants = null;
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ public class SolrServiceMetadataBrowseIndexingPlugin implements SolrServiceIndex
|
|||||||
if (!ignoreVariants) {
|
if (!ignoreVariants) {
|
||||||
variants = choiceAuthorityService
|
variants = choiceAuthorityService
|
||||||
.getVariants(
|
.getVariants(
|
||||||
values.get(x));
|
values.get(x), collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils
|
if (StringUtils
|
||||||
|
@@ -173,6 +173,8 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
|||||||
public void addDiscoveryFields(SolrInputDocument doc, Context context, Item item,
|
public void addDiscoveryFields(SolrInputDocument doc, Context context, Item item,
|
||||||
List<DiscoveryConfiguration> discoveryConfigurations)
|
List<DiscoveryConfiguration> discoveryConfigurations)
|
||||||
throws SQLException, IOException {
|
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
|
//Keep a list of our sort values which we added, sort values can only be added once
|
||||||
List<String> sortFieldsAdded = new ArrayList<>();
|
List<String> sortFieldsAdded = new ArrayList<>();
|
||||||
Map<String, List<DiscoverySearchFilter>> searchFilters = null;
|
Map<String, List<DiscoverySearchFilter>> searchFilters = null;
|
||||||
@@ -359,7 +361,7 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
|||||||
if (!ignorePrefered) {
|
if (!ignorePrefered) {
|
||||||
|
|
||||||
preferedLabel = choiceAuthorityService
|
preferedLabel = choiceAuthorityService
|
||||||
.getLabel(meta, meta.getLanguage());
|
.getLabel(meta, collection, meta.getLanguage());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean ignoreVariants =
|
boolean ignoreVariants =
|
||||||
@@ -375,7 +377,7 @@ public class ItemIndexFactoryImpl extends DSpaceObjectIndexFactoryImpl<Indexable
|
|||||||
true);
|
true);
|
||||||
if (!ignoreVariants) {
|
if (!ignoreVariants) {
|
||||||
variants = choiceAuthorityService
|
variants = choiceAuthorityService
|
||||||
.getVariants(meta);
|
.getVariants(meta, collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -109,6 +109,11 @@ plugin.sequence.java.util.Collection = \
|
|||||||
java.util.Stack, \
|
java.util.Stack, \
|
||||||
java.util.TreeSet
|
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 #
|
# PROPERTIES USED TO TEST CONFIGURATION #
|
||||||
# PROPERTY EXPOSURE VIA REST #
|
# PROPERTY EXPOSURE VIA REST #
|
||||||
|
@@ -282,6 +282,70 @@ it, please enter the types and the actual numbers or codes.</hint>
|
|||||||
</row>
|
</row>
|
||||||
</form>
|
</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>
|
</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
|
// Set the item to have two pieces of metadata for dc.type and dc2.type
|
||||||
String dcType = "DC-TYPE";
|
String dcType = "DC-TYPE";
|
||||||
String testType = "TEST-TYPE";
|
String testType = "TEST-TYPE";
|
||||||
itemService.addMetadata(context, it, "dc", "type", null, null, dcType, "accepted", 0);
|
itemService.addMetadata(context, it, "dc", "type", null, null, dcType);
|
||||||
itemService.addMetadata(context, it, "test", "type", null, null, testType, "accepted", 0);
|
itemService.addMetadata(context, it, "test", "type", null, null, testType);
|
||||||
|
|
||||||
// Check that only one is returned when we ask for all dc.type values
|
// Check that only one is returned when we ask for all dc.type values
|
||||||
List<MetadataValue> values = itemService.getMetadata(it, "dc", "type", null, null);
|
List<MetadataValue> values = itemService.getMetadata(it, "dc", "type", null, null);
|
||||||
|
@@ -78,7 +78,7 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest {
|
|||||||
String text = "north 40";
|
String text = "north 40";
|
||||||
Collection collection = null;
|
Collection collection = null;
|
||||||
int start = 0;
|
int start = 0;
|
||||||
int limit = 0;
|
int limit = 10;
|
||||||
String locale = null;
|
String locale = null;
|
||||||
// This "farm" Controlled Vocab is included in TestEnvironment data
|
// This "farm" Controlled Vocab is included in TestEnvironment data
|
||||||
// (under /src/test/data/dspaceFolder/) and it should be auto-loaded
|
// (under /src/test/data/dspaceFolder/) and it should be auto-loaded
|
||||||
@@ -86,8 +86,7 @@ public class DSpaceControlledVocabularyTest extends AbstractDSpaceTest {
|
|||||||
DSpaceControlledVocabulary instance = (DSpaceControlledVocabulary)
|
DSpaceControlledVocabulary instance = (DSpaceControlledVocabulary)
|
||||||
CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(Class.forName(PLUGIN_INTERFACE), "farm");
|
CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(Class.forName(PLUGIN_INTERFACE), "farm");
|
||||||
assertNotNull(instance);
|
assertNotNull(instance);
|
||||||
Choices result = instance.getMatches(field, text, collection, start,
|
Choices result = instance.getMatches(text, start, limit, locale);
|
||||||
limit, locale);
|
|
||||||
assertEquals("the farm::north 40", result.values[0].value);
|
assertEquals("the farm::north 40", result.values[0].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -149,7 +149,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
* @return single DSpaceResource
|
* @return single DSpaceResource
|
||||||
*/
|
*/
|
||||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT)
|
@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) {
|
@PathVariable Integer id) {
|
||||||
return findOneInternal(apiCategory, model, id);
|
return findOneInternal(apiCategory, model, id);
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
* @return single DSpaceResource
|
* @return single DSpaceResource
|
||||||
*/
|
*/
|
||||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG)
|
@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) {
|
@PathVariable String id) {
|
||||||
return findOneInternal(apiCategory, model, id);
|
return findOneInternal(apiCategory, model, id);
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
* @return single DSpaceResource
|
* @return single DSpaceResource
|
||||||
*/
|
*/
|
||||||
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
|
@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) {
|
@PathVariable UUID uuid) {
|
||||||
return findOneInternal(apiCategory, model, uuid);
|
return findOneInternal(apiCategory, model, uuid);
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
* @param id Identifier from request
|
* @param id Identifier from request
|
||||||
* @return single DSpaceResource
|
* @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) {
|
String model, ID id) {
|
||||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||||
Optional<RestAddressableModel> modelObject = Optional.empty();
|
Optional<RestAddressableModel> modelObject = Optional.empty();
|
||||||
@@ -799,7 +799,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
Method linkMethod = utils.requireMethod(linkRepository.getClass(), linkRest.method());
|
Method linkMethod = utils.requireMethod(linkRepository.getClass(), linkRest.method());
|
||||||
try {
|
try {
|
||||||
if (Page.class.isAssignableFrom(linkMethod.getReturnType())) {
|
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());
|
.invoke(linkRepository, request, uuid, page, utils.obtainProjection());
|
||||||
|
|
||||||
if (pageResult == null) {
|
if (pageResult == null) {
|
||||||
@@ -823,8 +823,8 @@ public class RestResourceController implements InitializingBean {
|
|||||||
return new EntityModel(new EmbeddedPage(link.getHref(),
|
return new EntityModel(new EmbeddedPage(link.getHref(),
|
||||||
pageResult.map(converter::toResource), null, subpath));
|
pageResult.map(converter::toResource), null, subpath));
|
||||||
} else {
|
} else {
|
||||||
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request, uuid, page,
|
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request,
|
||||||
utils.obtainProjection());
|
uuid, page, utils.obtainProjection());
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
return null;
|
return null;
|
||||||
@@ -846,7 +846,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RestAddressableModel modelObject = repository.findById(uuid).orElse(null);
|
RestModel modelObject = repository.findById(uuid).orElse(null);
|
||||||
|
|
||||||
if (modelObject == null) {
|
if (modelObject == null) {
|
||||||
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
|
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();
|
String inputType = dcinput.getInputType();
|
||||||
|
|
||||||
SelectableMetadata selMd = new SelectableMetadata();
|
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(),
|
inputRest.setType(getPresentation(dcinput.getSchema(), dcinput.getElement(),
|
||||||
dcinput.getQualifier(), inputType));
|
dcinput.getQualifier(), inputType));
|
||||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
selMd.setControlledVocabulary(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||||
dcinput.getQualifier(), dcinput.getPairsType(),
|
dcinput.getQualifier(), dcinput.getPairsType(),
|
||||||
dcinput.getVocabulary()));
|
dcinput.getVocabulary()));
|
||||||
selMd.setClosed(
|
selMd.setClosed(
|
||||||
authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier()));
|
isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(),
|
||||||
|
dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||||
} else {
|
} else {
|
||||||
inputRest.setType(inputType);
|
inputRest.setType(inputType);
|
||||||
}
|
}
|
||||||
@@ -139,10 +141,10 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
|||||||
selMd.setMetadata(org.dspace.core.Utils
|
selMd.setMetadata(org.dspace.core.Utils
|
||||||
.standardize(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1), "."));
|
.standardize(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1), "."));
|
||||||
if (authorityUtils.isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier())) {
|
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()));
|
pairs.get(idx + 1), dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||||
selMd.setClosed(authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(),
|
selMd.setClosed(isClosed(dcinput.getSchema(), dcinput.getElement(),
|
||||||
dcinput.getQualifier()));
|
dcinput.getQualifier(), null, dcinput.getVocabulary()));
|
||||||
}
|
}
|
||||||
selectableMetadata.add(selMd);
|
selectableMetadata.add(selMd);
|
||||||
}
|
}
|
||||||
@@ -185,7 +187,8 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
|||||||
return INPUT_TYPE_LOOKUP;
|
return INPUT_TYPE_LOOKUP;
|
||||||
}
|
}
|
||||||
} else if (INPUT_TYPE_NAME.equals(inputType)) {
|
} 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;
|
return INPUT_TYPE_LOOKUP_NAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,6 +206,22 @@ public class SubmissionFormConverter implements DSpaceConverter<DCInputSet, Subm
|
|||||||
return authorityUtils.getAuthorityName(schema, element, qualifier);
|
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
|
@Override
|
||||||
public Class<DCInputSet> getModelClass() {
|
public Class<DCInputSet> getModelClass() {
|
||||||
return DCInputSet.class;
|
return DCInputSet.class;
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.app.rest.converter;
|
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.projection.Projection;
|
||||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||||
import org.dspace.content.authority.Choice;
|
import org.dspace.content.authority.Choice;
|
||||||
@@ -22,16 +22,17 @@ import org.springframework.stereotype.Component;
|
|||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class AuthorityEntryRestConverter implements DSpaceConverter<Choice, AuthorityEntryRest> {
|
public class VocabularyEntryDetailsRestConverter implements DSpaceConverter<Choice, VocabularyEntryDetailsRest> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorityEntryRest convert(Choice choice, Projection projection) {
|
public VocabularyEntryDetailsRest convert(Choice choice, Projection projection) {
|
||||||
AuthorityEntryRest entry = new AuthorityEntryRest();
|
VocabularyEntryDetailsRest entry = new VocabularyEntryDetailsRest();
|
||||||
entry.setProjection(projection);
|
entry.setProjection(projection);
|
||||||
entry.setValue(choice.value);
|
entry.setValue(choice.value);
|
||||||
entry.setDisplay(choice.label);
|
entry.setDisplay(choice.label);
|
||||||
entry.setId(choice.authority);
|
entry.setId(choice.authority);
|
||||||
entry.setOtherInformation(choice.extras);
|
entry.setOtherInformation(choice.extras);
|
||||||
|
entry.setSelectable(choice.selectable);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.app.rest.converter;
|
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.projection.Projection;
|
||||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||||
import org.dspace.content.authority.ChoiceAuthority;
|
import org.dspace.content.authority.ChoiceAuthority;
|
||||||
@@ -23,15 +23,15 @@ import org.springframework.stereotype.Component;
|
|||||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class AuthorityRestConverter implements DSpaceConverter<ChoiceAuthority, AuthorityRest> {
|
public class VocabularyRestConverter implements DSpaceConverter<ChoiceAuthority, VocabularyRest> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorityRest convert(ChoiceAuthority step, Projection projection) {
|
public VocabularyRest convert(ChoiceAuthority authority, Projection projection) {
|
||||||
AuthorityRest authorityRest = new AuthorityRest();
|
VocabularyRest authorityRest = new VocabularyRest();
|
||||||
authorityRest.setProjection(projection);
|
authorityRest.setProjection(projection);
|
||||||
authorityRest.setHierarchical(step.isHierarchical());
|
authorityRest.setHierarchical(authority.isHierarchical());
|
||||||
authorityRest.setScrollable(step.isScrollable());
|
authorityRest.setScrollable(authority.isScrollable());
|
||||||
authorityRest.setIdentifier(step.hasIdentifier());
|
authorityRest.setPreloadLevel(authority.getPreloadLevel());
|
||||||
return authorityRest;
|
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 {
|
public class SubmissionFormInputTypeRest {
|
||||||
private String type;
|
private String type;
|
||||||
private String regex;
|
private String regex;
|
||||||
private AuthorityRest authority;
|
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
@@ -39,11 +38,4 @@ public class SubmissionFormInputTypeRest {
|
|||||||
this.regex = regex;
|
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 java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
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)
|
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||||
*/
|
*/
|
||||||
public class AuthorityEntryRest extends RestAddressableModel {
|
public class VocabularyEntryRest implements RestModel {
|
||||||
public static final String NAME = "authorityEntry";
|
public static final String NAME = "vocabularyEntry";
|
||||||
private String id;
|
|
||||||
|
@JsonInclude(Include.NON_NULL)
|
||||||
|
private String authority;
|
||||||
private String display;
|
private String display;
|
||||||
private String value;
|
private String value;
|
||||||
private Map<String, String> otherInformation;
|
private Map<String, String> otherInformation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Vocabulary Entry Details resource if available related to this entry
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private String authorityName;
|
private VocabularyEntryDetailsRest vocabularyEntryDetailsRest;
|
||||||
|
|
||||||
public String getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(String id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDisplay() {
|
public String getDisplay() {
|
||||||
return display;
|
return display;
|
||||||
@@ -59,31 +57,24 @@ public class AuthorityEntryRest extends RestAddressableModel {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getName() {
|
public void setAuthority(String authority) {
|
||||||
return NAME;
|
this.authority = authority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuthorityName() {
|
public String getAuthority() {
|
||||||
return authorityName;
|
return authority;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthorityName(String authorityName) {
|
public void setVocabularyEntryDetailsRest(VocabularyEntryDetailsRest vocabularyEntryDetailsRest) {
|
||||||
this.authorityName = authorityName;
|
this.vocabularyEntryDetailsRest = vocabularyEntryDetailsRest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public VocabularyEntryDetailsRest getVocabularyEntryDetailsRest() {
|
||||||
public String getCategory() {
|
return vocabularyEntryDetailsRest;
|
||||||
return AuthorityRest.CATEGORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
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;
|
import org.dspace.app.rest.RestResourceController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The authority REST resource
|
* The vocabulary REST resource
|
||||||
*
|
*
|
||||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||||
*/
|
*/
|
||||||
@LinksRest(links = {
|
@LinksRest(links = {
|
||||||
@LinkRest(name = AuthorityRest.ENTRIES,
|
@LinkRest(name = VocabularyRest.ENTRIES,
|
||||||
method = "query"
|
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 NAME = "vocabulary";
|
||||||
public static final String CATEGORY = RestAddressableModel.INTEGRATION;
|
public static final String CATEGORY = RestAddressableModel.SUBMISSION;
|
||||||
public static final String ENTRIES = "entries";
|
public static final String ENTRIES = "entries";
|
||||||
public static final String ENTRY = "entryValues";
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@@ -36,7 +31,7 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
|||||||
|
|
||||||
private boolean hierarchical;
|
private boolean hierarchical;
|
||||||
|
|
||||||
private boolean identifier;
|
private Integer preloadLevel;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
@@ -67,6 +62,14 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
|||||||
this.hierarchical = hierarchical;
|
this.hierarchical = hierarchical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getPreloadLevel() {
|
||||||
|
return preloadLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreloadLevel(Integer preloadLevel) {
|
||||||
|
this.preloadLevel = preloadLevel;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return NAME;
|
return NAME;
|
||||||
@@ -81,12 +84,4 @@ public class AuthorityRest extends BaseObjectRest<String> {
|
|||||||
public String getCategory() {
|
public String getCategory() {
|
||||||
return CATEGORY;
|
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;
|
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.model.hateoas.annotations.RelNameDSpaceResource;
|
||||||
import org.dspace.app.rest.utils.Utils;
|
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)
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
*/
|
*/
|
||||||
@RelNameDSpaceResource(AuthorityRest.NAME)
|
@RelNameDSpaceResource(VocabularyRest.NAME)
|
||||||
public class AuthorityResource extends DSpaceResource<AuthorityRest> {
|
public class VocabularyResource extends DSpaceResource<VocabularyRest> {
|
||||||
public AuthorityResource(AuthorityRest sd, Utils utils) {
|
public VocabularyResource(VocabularyRest sd, Utils utils) {
|
||||||
super(sd, utils);
|
super(sd, utils);
|
||||||
if (sd.hasIdentifier()) {
|
add(utils.linkToSubResource(sd, VocabularyRest.ENTRIES));
|
||||||
add(utils.linkToSubResource(sd, AuthorityRest.ENTRY));
|
|
||||||
}
|
|
||||||
add(utils.linkToSubResource(sd, AuthorityRest.ENTRIES));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,6 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.app.rest.model.submit;
|
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
|
* The SelectableMetadata REST Resource. It is not addressable directly, only
|
||||||
* used as inline object in the InputForm resource.
|
* used as inline object in the InputForm resource.
|
||||||
@@ -24,7 +27,9 @@ package org.dspace.app.rest.model.submit;
|
|||||||
public class SelectableMetadata {
|
public class SelectableMetadata {
|
||||||
private String metadata;
|
private String metadata;
|
||||||
private String label;
|
private String label;
|
||||||
private String authority;
|
@JsonInclude(Include.NON_NULL)
|
||||||
|
private String controlledVocabulary;
|
||||||
|
@JsonInclude(Include.NON_NULL)
|
||||||
private Boolean closed = false;
|
private Boolean closed = false;
|
||||||
|
|
||||||
public String getMetadata() {
|
public String getMetadata() {
|
||||||
@@ -43,12 +48,12 @@ public class SelectableMetadata {
|
|||||||
this.label = label;
|
this.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAuthority(String authority) {
|
public void setControlledVocabulary(String vocabularyName) {
|
||||||
this.authority = authority;
|
this.controlledVocabulary = vocabularyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAuthority() {
|
public String getControlledVocabulary() {
|
||||||
return authority;
|
return controlledVocabulary;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean isClosed() {
|
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;
|
package org.dspace.app.rest.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.dspace.app.rest.converter.ConverterService;
|
import org.dspace.app.rest.converter.ConverterService;
|
||||||
import org.dspace.app.rest.model.AuthorityEntryRest;
|
import org.dspace.app.rest.model.VocabularyEntryDetailsRest;
|
||||||
import org.dspace.app.rest.model.AuthorityRest;
|
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.projection.Projection;
|
||||||
import org.dspace.content.authority.Choice;
|
import org.dspace.content.authority.Choice;
|
||||||
import org.dspace.content.authority.ChoiceAuthority;
|
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_LOOKUP = "lookup";
|
||||||
|
|
||||||
|
public static final String PRESENTATION_TYPE_AUTHORLOOKUP = "authorLookup";
|
||||||
|
|
||||||
public static final String PRESENTATION_TYPE_SUGGEST = "suggest";
|
public static final String PRESENTATION_TYPE_SUGGEST = "suggest";
|
||||||
|
|
||||||
public static final String RESERVED_KEYMAP_PARENT = "parent";
|
public static final String RESERVED_KEYMAP_PARENT = "parent";
|
||||||
@@ -39,11 +43,11 @@ public class AuthorityUtils {
|
|||||||
|
|
||||||
|
|
||||||
public boolean isChoice(String schema, String element, String qualifier) {
|
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) {
|
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) {
|
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}.
|
* @param projection the name of the projection to use, or {@code null}.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public AuthorityEntryRest convertEntry(Choice choice, String authorityName, Projection projection) {
|
public VocabularyEntryDetailsRest convertEntryDetails(Choice choice, String authorityName,
|
||||||
AuthorityEntryRest entry = converter.toRest(choice, projection);
|
boolean isHierarchical, Projection projection) {
|
||||||
entry.setAuthorityName(authorityName);
|
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;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +116,8 @@ public class AuthorityUtils {
|
|||||||
* @param projection the projecton to use.
|
* @param projection the projecton to use.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public AuthorityRest convertAuthority(ChoiceAuthority source, String authorityName, Projection projection) {
|
public VocabularyRest convertAuthority(ChoiceAuthority source, String authorityName, Projection projection) {
|
||||||
AuthorityRest result = converter.toRest(source, projection);
|
VocabularyRest result = converter.toRest(source, projection);
|
||||||
result.setName(authorityName);
|
result.setName(authorityName);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,8 @@ public class RegexUtils {
|
|||||||
* identifier (digits or uuid)
|
* identifier (digits or uuid)
|
||||||
*/
|
*/
|
||||||
public static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG = "/{id:^(?!^\\d+$)" +
|
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
|
* 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.converter.ConverterService;
|
||||||
import org.dspace.app.rest.exception.PaginationException;
|
import org.dspace.app.rest.exception.PaginationException;
|
||||||
import org.dspace.app.rest.exception.RepositoryNotFoundException;
|
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.BaseObjectRest;
|
||||||
import org.dspace.app.rest.model.CommunityRest;
|
import org.dspace.app.rest.model.CommunityRest;
|
||||||
import org.dspace.app.rest.model.LinkRest;
|
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.RestAddressableModel;
|
||||||
import org.dspace.app.rest.model.RestModel;
|
import org.dspace.app.rest.model.RestModel;
|
||||||
import org.dspace.app.rest.model.VersionHistoryRest;
|
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.EmbeddedPage;
|
||||||
import org.dspace.app.rest.model.hateoas.HALResource;
|
import org.dspace.app.rest.model.hateoas.HALResource;
|
||||||
import org.dspace.app.rest.projection.CompositeProjection;
|
import org.dspace.app.rest.projection.CompositeProjection;
|
||||||
@@ -254,7 +254,7 @@ public class Utils {
|
|||||||
return CommunityRest.NAME;
|
return CommunityRest.NAME;
|
||||||
}
|
}
|
||||||
if (modelPlural.equals("authorities")) {
|
if (modelPlural.equals("authorities")) {
|
||||||
return AuthorityRest.NAME;
|
return VocabularyRest.NAME;
|
||||||
}
|
}
|
||||||
if (modelPlural.equals("resourcepolicies")) {
|
if (modelPlural.equals("resourcepolicies")) {
|
||||||
return ResourcePolicyRest.NAME;
|
return ResourcePolicyRest.NAME;
|
||||||
@@ -268,6 +268,9 @@ public class Utils {
|
|||||||
if (StringUtils.equals(modelPlural, "properties")) {
|
if (StringUtils.equals(modelPlural, "properties")) {
|
||||||
return PropertyRest.NAME;
|
return PropertyRest.NAME;
|
||||||
}
|
}
|
||||||
|
if (StringUtils.equals(modelPlural, "vocabularies")) {
|
||||||
|
return VocabularyRest.NAME;
|
||||||
|
}
|
||||||
return modelPlural.replaceAll("s$", "");
|
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"
|
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||||
.andExpect(content().contentType(contentType))
|
.andExpect(content().contentType(contentType))
|
||||||
//Check that all required root links are present and that they are absolute
|
//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.bitstreamformats.href", startsWith(BASE_REST_SERVER_URL)))
|
||||||
.andExpect(jsonPath("$._links.bitstreams.href", startsWith(BASE_REST_SERVER_URL)))
|
.andExpect(jsonPath("$._links.bitstreams.href", startsWith(BASE_REST_SERVER_URL)))
|
||||||
.andExpect(jsonPath("$._links.browses.href", startsWith(BASE_REST_SERVER_URL)))
|
.andExpect(jsonPath("$._links.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.rest.test.AbstractControllerIntegrationTest;
|
||||||
import org.dspace.app.util.DCInputsReaderException;
|
import org.dspace.app.util.DCInputsReaderException;
|
||||||
import org.dspace.builder.EPersonBuilder;
|
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.eperson.EPerson;
|
||||||
import org.dspace.services.ConfigurationService;
|
import org.dspace.services.ConfigurationService;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
@@ -39,6 +42,10 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
private ConfigurationService configurationService;
|
private ConfigurationService configurationService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private SubmissionFormRestRepository submissionFormRestRepository;
|
private SubmissionFormRestRepository submissionFormRestRepository;
|
||||||
|
@Autowired
|
||||||
|
private PluginService pluginService;
|
||||||
|
@Autowired
|
||||||
|
private ChoiceAuthorityService cas;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findAll() throws Exception {
|
public void findAll() throws Exception {
|
||||||
@@ -56,15 +63,15 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
//We expect the content type to be "application/hal+json;charset=UTF-8"
|
||||||
.andExpect(content().contentType(contentType))
|
.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.size", is(20)))
|
||||||
.andExpect(jsonPath("$.page.totalElements", equalTo(4)))
|
.andExpect(jsonPath("$.page.totalElements", equalTo(6)))
|
||||||
.andExpect(jsonPath("$.page.totalPages", equalTo(1)))
|
.andExpect(jsonPath("$.page.totalPages", equalTo(1)))
|
||||||
.andExpect(jsonPath("$.page.number", is(0)))
|
.andExpect(jsonPath("$.page.number", is(0)))
|
||||||
.andExpect(
|
.andExpect(
|
||||||
jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL + "config/submissionforms")))
|
jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL + "config/submissionforms")))
|
||||||
//The array of submissionforms should have a size of 3
|
//The array of submissionforms should have a size of 6
|
||||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(4))))
|
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(6))))
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,12 +82,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().contentType(contentType))
|
.andExpect(content().contentType(contentType))
|
||||||
.andExpect(jsonPath("$.page.size", is(20)))
|
.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.totalPages", equalTo(1)))
|
||||||
.andExpect(jsonPath("$.page.number", is(0)))
|
.andExpect(jsonPath("$.page.number", is(0)))
|
||||||
.andExpect(jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL
|
.andExpect(jsonPath("$._links.self.href", Matchers.startsWith(REST_SERVER_URL
|
||||||
+ "config/submissionforms")))
|
+ "config/submissionforms")))
|
||||||
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(4))));
|
.andExpect(jsonPath("$._embedded.submissionforms", hasSize(equalTo(6))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -152,6 +159,121 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
"col-sm-8","dc.publisher"))));
|
"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
|
@Test
|
||||||
public void findOpenRelationshipConfig() throws Exception {
|
public void findOpenRelationshipConfig() throws Exception {
|
||||||
String token = getAuthToken(admin.getEmail(), password);
|
String token = getAuthToken(admin.getEmail(), password);
|
||||||
@@ -203,8 +325,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
public void languageSupportTest() throws Exception {
|
public void languageSupportTest() throws Exception {
|
||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
String[] supportedLanguage = {"it","uk"};
|
String[] supportedLanguage = {"it","uk"};
|
||||||
|
configurationService.setProperty("default.locale","it");
|
||||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
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();
|
submissionFormRestRepository.reload();
|
||||||
|
DCInputAuthority.reset();
|
||||||
|
pluginService.clearNamedPluginClasses();
|
||||||
|
cas.clearCache();
|
||||||
|
|
||||||
Locale uk = new Locale("uk");
|
Locale uk = new Locale("uk");
|
||||||
Locale it = new Locale("it");
|
Locale it = new Locale("it");
|
||||||
@@ -234,7 +362,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
"Selezionare la lingua del contenuto principale dell'item."
|
"Selezionare la lingua del contenuto principale dell'item."
|
||||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||||
+ " Se il contenuto non ha davvero una lingua"
|
+ " 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
|
// user select ukranian language
|
||||||
getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest").locale(uk))
|
getClient(tokenEperson).perform(get("/api/config/submissionforms/languagetest").locale(uk))
|
||||||
@@ -256,8 +385,7 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
||||||
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
||||||
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
||||||
"dc.language.iso"))));
|
null, "dc.language.iso", "common_iso_languages"))));
|
||||||
|
|
||||||
resetLocalesConfiguration();
|
resetLocalesConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,8 +394,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
String[] supportedLanguage = {"it","uk"};
|
String[] supportedLanguage = {"it","uk"};
|
||||||
|
configurationService.setProperty("default.locale","it");
|
||||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
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();
|
submissionFormRestRepository.reload();
|
||||||
|
DCInputAuthority.reset();
|
||||||
|
pluginService.clearNamedPluginClasses();
|
||||||
|
cas.clearCache();
|
||||||
|
|
||||||
EPerson epersonIT = EPersonBuilder.createEPerson(context)
|
EPerson epersonIT = EPersonBuilder.createEPerson(context)
|
||||||
.withEmail("epersonIT@example.com")
|
.withEmail("epersonIT@example.com")
|
||||||
@@ -307,7 +441,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
"Selezionare la lingua del contenuto principale dell'item."
|
"Selezionare la lingua del contenuto principale dell'item."
|
||||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||||
+ " Se il contenuto non ha davvero una lingua"
|
+ " 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
|
// user with ukranian prefer language
|
||||||
getClient(tokenEpersonUK).perform(get("/api/config/submissionforms/languagetest"))
|
getClient(tokenEpersonUK).perform(get("/api/config/submissionforms/languagetest"))
|
||||||
@@ -329,8 +464,7 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
.matchFormFieldDefinition("dropdown", "Мова", null, false,
|
||||||
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
"Виберiть мову головного змiсту файлу, як що мови немає у списку, вибрати (Iнша)."
|
||||||
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
+ " Як що вмiст вайлу не є текстовим, наприклад є фотографiєю, тодi вибрати (N/A)",
|
||||||
"dc.language.iso"))));
|
null, "dc.language.iso", "common_iso_languages"))));
|
||||||
|
|
||||||
resetLocalesConfiguration();
|
resetLocalesConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,8 +473,14 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
context.turnOffAuthorisationSystem();
|
context.turnOffAuthorisationSystem();
|
||||||
|
|
||||||
String[] supportedLanguage = {"it","uk"};
|
String[] supportedLanguage = {"it","uk"};
|
||||||
|
configurationService.setProperty("default.locale","it");
|
||||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
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();
|
submissionFormRestRepository.reload();
|
||||||
|
DCInputAuthority.reset();
|
||||||
|
pluginService.clearNamedPluginClasses();
|
||||||
|
cas.clearCache();
|
||||||
|
|
||||||
Locale it = new Locale("it");
|
Locale it = new Locale("it");
|
||||||
|
|
||||||
@@ -375,8 +515,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
"Selezionare la lingua del contenuto principale dell'item."
|
"Selezionare la lingua del contenuto principale dell'item."
|
||||||
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
+ " Se la lingua non compare nell'elenco, selezionare (Altro)."
|
||||||
+ " Se il contenuto non ha davvero una lingua"
|
+ " 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"))));
|
||||||
resetLocalesConfiguration();
|
resetLocalesConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +527,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
String[] supportedLanguage = {"it","uk"};
|
String[] supportedLanguage = {"it","uk"};
|
||||||
configurationService.setProperty("default.locale","it");
|
configurationService.setProperty("default.locale","it");
|
||||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
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();
|
submissionFormRestRepository.reload();
|
||||||
|
DCInputAuthority.reset();
|
||||||
|
pluginService.clearNamedPluginClasses();
|
||||||
|
cas.clearCache();
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
@@ -407,7 +552,6 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
.matchFormFieldDefinition("onebox", "Titolo",
|
.matchFormFieldDefinition("onebox", "Titolo",
|
||||||
"\u00C8 necessario inserire un titolo principale per questo item", false,
|
"\u00C8 necessario inserire un titolo principale per questo item", false,
|
||||||
"Inserisci titolo principale di questo item", "dc.title"))));
|
"Inserisci titolo principale di questo item", "dc.title"))));
|
||||||
|
|
||||||
resetLocalesConfiguration();
|
resetLocalesConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,7 +561,12 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
String[] supportedLanguage = {"it","uk","en"};
|
String[] supportedLanguage = {"it","uk","en"};
|
||||||
configurationService.setProperty("default.locale","en");
|
configurationService.setProperty("default.locale","en");
|
||||||
configurationService.setProperty("webui.supported.locales",supportedLanguage);
|
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();
|
submissionFormRestRepository.reload();
|
||||||
|
DCInputAuthority.reset();
|
||||||
|
pluginService.clearNamedPluginClasses();
|
||||||
|
cas.clearCache();
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
context.restoreAuthSystemState();
|
||||||
|
|
||||||
@@ -446,5 +595,8 @@ public class SubmissionFormsControllerIT extends AbstractControllerIntegrationTe
|
|||||||
configurationService.setProperty("default.locale","en");
|
configurationService.setProperty("default.locale","en");
|
||||||
configurationService.setProperty("webui.supported.locales",null);
|
configurationService.setProperty("webui.supported.locales",null);
|
||||||
submissionFormRestRepository.reload();
|
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
|
* Shortcut for the
|
||||||
* {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String)}
|
* {@link SubmissionFormFieldMatcher#matchFormFieldDefinition(String, String, String, boolean, String, String, String, String)}
|
||||||
* with a null style
|
* with a null style and vocabulary name
|
||||||
*
|
*
|
||||||
* @param type
|
* @param type
|
||||||
* the expected input 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
|
* @param type
|
||||||
* the expected input type
|
* the expected input type
|
||||||
@@ -76,11 +78,43 @@ public class SubmissionFormFieldMatcher {
|
|||||||
public static Matcher<? super Object> matchFormFieldDefinition(String type, String label, String mandatoryMessage,
|
public static Matcher<? super Object> matchFormFieldDefinition(String type, String label, String mandatoryMessage,
|
||||||
boolean repeatable,
|
boolean repeatable,
|
||||||
String hints, String style, String metadata) {
|
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(
|
return allOf(
|
||||||
// check each field definition
|
// check each field definition
|
||||||
hasJsonPath("$.input.type", is(type)),
|
hasJsonPath("$.input.type", is(type)),
|
||||||
hasJsonPath("$.label", containsString(label)),
|
hasJsonPath("$.label", containsString(label)),
|
||||||
hasJsonPath("$.selectableMetadata[0].metadata", is(metadata)),
|
hasJsonPath("$.selectableMetadata[0].metadata", is(metadata)),
|
||||||
|
controlledVocabulary != null ? hasJsonPath("$.selectableMetadata[0].controlledVocabulary",
|
||||||
|
is(controlledVocabulary)) : hasNoJsonPath("$.selectableMetadata[0].controlledVocabulary"),
|
||||||
mandatoryMessage != null ? hasJsonPath("$.mandatoryMessage", containsString(mandatoryMessage)) :
|
mandatoryMessage != null ? hasJsonPath("$.mandatoryMessage", containsString(mandatoryMessage)) :
|
||||||
hasNoJsonPath("$.mandatoryMessage"),
|
hasNoJsonPath("$.mandatoryMessage"),
|
||||||
hasJsonPath("$.mandatory", is(mandatoryMessage != null)),
|
hasJsonPath("$.mandatory", is(mandatoryMessage != null)),
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
package org.dspace.app.rest.matcher;
|
package org.dspace.app.rest.matcher;
|
||||||
|
|
||||||
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
|
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.allOf;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.is;
|
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
|
* 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) {
|
public static Matcher<? super Object> matchAuthorityEntry(String id, String display, String value) {
|
||||||
return allOf(
|
return allOf(
|
||||||
matchProperties(id, display, value),
|
matchProperties(id, display, value),
|
||||||
matchLinks());
|
matchLinks(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matcher<? super Object> matchLinks() {
|
public static Matcher<? super Object> matchLinks(String id) {
|
||||||
return allOf(
|
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) {
|
private static Matcher<? super Object> matchProperties(String id, String display, String value) {
|
||||||
@@ -39,16 +38,7 @@ public class AuthorityEntryMatcher {
|
|||||||
hasJsonPath("$.id", is(id)),
|
hasJsonPath("$.id", is(id)),
|
||||||
hasJsonPath("$.display", is(display)),
|
hasJsonPath("$.display", is(display)),
|
||||||
hasJsonPath("$.value", is(value)),
|
hasJsonPath("$.value", is(value)),
|
||||||
hasJsonPath("$.type", is("authority"))
|
hasJsonPath("$.type", is("vocabularyEntryDetail"))
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a matcher for all expected embeds when the full projection is requested.
|
|
||||||
*/
|
|
||||||
public static Matcher<? super Object> matchFullEmbeds() {
|
|
||||||
return matchEmbeds(
|
|
||||||
"authorityEntries"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -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:all>
|
||||||
<xs:attribute name="id" type="xs:ID" use="optional"/>
|
<xs:attribute name="id" type="xs:ID" use="optional"/>
|
||||||
<xs:attribute name="label" type="xs:string" use="required"/>
|
<xs:attribute name="label" type="xs:string" use="required"/>
|
||||||
|
<xs:attribute name="selectable" type="xs:boolean" default="true"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
</xs:element>
|
</xs:element>
|
||||||
</xs:schema>
|
</xs:schema>
|
||||||
|
@@ -1486,7 +1486,7 @@ orcid.url = https://orcid.org/
|
|||||||
## eg: nsi, srsc.
|
## eg: nsi, srsc.
|
||||||
## Each DSpaceControlledVocabulary plugin comes with three configuration options:
|
## Each DSpaceControlledVocabulary plugin comes with three configuration options:
|
||||||
# vocabulary.plugin._plugin_.hierarchy.store = <true|false> # default: true
|
# 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: "::"
|
# vocabulary.plugin._plugin_.delimiter = "<string>" # default: "::"
|
||||||
##
|
##
|
||||||
## An example using "srsc" can be found later in this section
|
## An example using "srsc" can be found later in this section
|
||||||
|
Reference in New Issue
Block a user