Merge pull request #2899 from atmire/w2p-71752_Metadata-field-search

Metadata field search
This commit is contained in:
Tim Donohue
2020-08-31 16:28:50 -05:00
committed by GitHub
12 changed files with 1018 additions and 48 deletions

View File

@@ -9,6 +9,8 @@ package org.dspace.content;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
@@ -20,8 +22,12 @@ import org.dspace.content.dao.MetadataFieldDAO;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.SiteService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.discovery.indexobject.IndexableMetadataField;
import org.dspace.event.Event;
import org.springframework.beans.factory.annotation.Autowired;
/**
@@ -46,6 +52,8 @@ public class MetadataFieldServiceImpl implements MetadataFieldService {
protected MetadataValueService metadataValueService;
@Autowired(required = true)
protected MetadataSchemaService metadataSchemaService;
@Autowired
protected SiteService siteService;
protected MetadataFieldServiceImpl() {
@@ -77,6 +85,8 @@ public class MetadataFieldServiceImpl implements MetadataFieldService {
log.info(LogManager.getHeader(context, "create_metadata_field",
"metadata_field_id=" + metadataField.getID()));
// Update the index of type metadatafield
this.triggerEventToUpdateIndex(context, metadataField.getID());
return metadataField;
}
@@ -149,6 +159,8 @@ public class MetadataFieldServiceImpl implements MetadataFieldService {
"metadata_field_id=" + metadataField.getID() + "element=" + metadataField
.getElement()
+ "qualifier=" + metadataField.getQualifier()));
// Update the index of type metadatafield
this.triggerEventToUpdateIndex(context, metadataField.getID());
}
@Override
@@ -177,6 +189,21 @@ public class MetadataFieldServiceImpl implements MetadataFieldService {
log.info(LogManager.getHeader(context, "delete_metadata_field",
"metadata_field_id=" + metadataField.getID()));
// Update the index of type metadatafield
this.triggerEventToUpdateIndex(context, metadataField.getID());
}
/**
* Calls a MODIFY SITE event with the identifier of the changed mdField, so it can be indexed in
* {@link org.dspace.discovery.IndexEventConsumer}, with type of {@link org.dspace.discovery.IndexableObject} in
* {@link Event}.detail and the identifiers of the changed mdFields in {@link Event}.identifiers
*
* @param context DSpace context
* @param mdFieldId ID of the metadata field that needs to be (re)indexed
*/
private void triggerEventToUpdateIndex(Context context, int mdFieldId) {
context.addEvent(new Event(Event.MODIFY, Constants.SITE, null, IndexableMetadataField.TYPE, new ArrayList<>(
Arrays.asList(Integer.toString(mdFieldId)))));
}
/**

View File

@@ -8,6 +8,7 @@
package org.dspace.discovery;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import org.apache.logging.log4j.Logger;
@@ -15,6 +16,7 @@ import org.dspace.content.Bundle;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.discovery.indexobject.factory.IndexFactory;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.event.Consumer;
import org.dspace.event.Event;
@@ -67,7 +69,7 @@ public class IndexEventConsumer implements Consumer {
int st = event.getSubjectType();
if (!(st == Constants.ITEM || st == Constants.BUNDLE
|| st == Constants.COLLECTION || st == Constants.COMMUNITY)) {
|| st == Constants.COLLECTION || st == Constants.COMMUNITY || st == Constants.SITE)) {
log
.warn("IndexConsumer should not have been given this kind of Subject in an event, skipping: "
+ event.toString());
@@ -104,10 +106,28 @@ public class IndexEventConsumer implements Consumer {
case Event.MODIFY:
case Event.MODIFY_METADATA:
if (subject == null) {
log.warn(event.getEventTypeAsString() + " event, could not get object for "
if (st == Constants.SITE) {
// Update the indexable objects of type in event.detail of objects with ids in event.identifiers
for (String id : event.getIdentifiers()) {
IndexFactory indexableObjectService = IndexObjectFactoryFactory.getInstance().
getIndexFactoryByType(event.getDetail());
Optional<IndexableObject> indexableObject = Optional.empty();
indexableObject = indexableObjectService.findIndexableObject(ctx, id);
if (indexableObject.isPresent()) {
log.debug("consume() adding event to update queue: " + event.toString());
objectsToUpdate
.addAll(indexObjectServiceFactory
.getIndexableObjects(ctx, indexableObject.get().getIndexedObject()));
} else {
log.warn("Cannot resolve " + id);
}
}
} else {
log.warn(event.getEventTypeAsString() + " event, could not get object for "
+ event.getSubjectTypeAsString() + " id="
+ event.getSubjectID()
+ ", perhaps it has been deleted.");
}
} else {
log.debug("consume() adding event to update queue: " + event.toString());
objectsToUpdate.addAll(indexObjectServiceFactory.getIndexableObjects(ctx, subject));

View File

@@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
@@ -56,7 +57,7 @@ public abstract class IndexFactoryImpl<T extends IndexableObject, S> implements
doc.addField(SearchUtils.RESOURCE_ID_FIELD, indexableObject.getID().toString());
//Do any additional indexing, depends on the plugins
for (SolrServiceIndexPlugin solrServiceIndexPlugin : solrServiceIndexPlugins) {
for (SolrServiceIndexPlugin solrServiceIndexPlugin : ListUtils.emptyIfNull(solrServiceIndexPlugins)) {
solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc);
}
@@ -190,4 +191,4 @@ public abstract class IndexFactoryImpl<T extends IndexableObject, S> implements
public void deleteAll() throws IOException, SolrServerException {
solrSearchCore.getSolr().deleteByQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":" + getType());
}
}
}

View File

@@ -0,0 +1,51 @@
/**
* 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.discovery.indexobject;
import org.dspace.content.MetadataField;
import org.dspace.discovery.IndexableObject;
/**
* {@link MetadataField} implementation for the {@link IndexableObject}
*
* @author Maria Verdonck (Atmire) on 14/07/2020
*/
public class IndexableMetadataField implements IndexableObject<MetadataField, Integer> {
private MetadataField metadataField;
public static final String TYPE = MetadataField.class.getSimpleName();
public IndexableMetadataField(MetadataField metadataField) {
this.metadataField = metadataField;
}
@Override
public String getType() {
return TYPE;
}
@Override
public Integer getID() {
return this.metadataField.getID();
}
@Override
public MetadataField getIndexedObject() {
return this.metadataField;
}
@Override
public void setIndexedObject(MetadataField metadataField) {
this.metadataField = metadataField;
}
@Override
public String getTypeText() {
return TYPE.toUpperCase();
}
}

View File

@@ -0,0 +1,109 @@
/**
* 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.discovery.indexobject;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.content.MetadataField;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.core.Context;
import org.dspace.discovery.indexobject.factory.MetadataFieldIndexFactory;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Factory implementation for indexing/retrieving {@link org.dspace.content.MetadataField} items in the search core
*
* @author Maria Verdonck (Atmire) on 14/07/2020
*/
public class MetadataFieldIndexFactoryImpl extends IndexFactoryImpl<IndexableMetadataField, MetadataField>
implements MetadataFieldIndexFactory {
public static final String SCHEMA_FIELD_NAME = "schema";
public static final String ELEMENT_FIELD_NAME = "element";
public static final String QUALIFIER_FIELD_NAME = "qualifier";
public static final String FIELD_NAME_VARIATIONS = "fieldName";
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
@Override
public SolrInputDocument buildDocument(Context context, IndexableMetadataField indexableObject) throws SQLException,
IOException {
// Add the ID's, types and call the SolrServiceIndexPlugins
final SolrInputDocument doc = super.buildDocument(context, indexableObject);
final MetadataField metadataField = indexableObject.getIndexedObject();
// add schema, element, qualifier and full fieldName
addFacetIndex(doc, SCHEMA_FIELD_NAME, metadataField.getMetadataSchema().getName(),
metadataField.getMetadataSchema().getName());
addFacetIndex(doc, ELEMENT_FIELD_NAME, metadataField.getElement(), metadataField.getElement());
String fieldName = metadataField.toString().replace('_', '.');
addFacetIndex(doc, FIELD_NAME_VARIATIONS, fieldName, fieldName);
if (StringUtils.isNotBlank(metadataField.getQualifier())) {
addFacetIndex(doc, QUALIFIER_FIELD_NAME, metadataField.getQualifier(), metadataField.getQualifier());
addFacetIndex(doc, FIELD_NAME_VARIATIONS, fieldName,
metadataField.getElement() + "." + metadataField.getQualifier());
addFacetIndex(doc, FIELD_NAME_VARIATIONS, metadataField.getQualifier(), metadataField.getQualifier());
} else {
addFacetIndex(doc, FIELD_NAME_VARIATIONS, metadataField.getElement(), metadataField.getElement());
}
addNamedResourceTypeIndex(doc, indexableObject.getTypeText());
Group anonymousGroup = groupService.findByName(context, Group.ANONYMOUS);
// add read permission on doc for anonymous group
doc.addField("read", "g" + anonymousGroup.getID());
return doc;
}
@Autowired
private MetadataFieldService metadataFieldService;
@Override
public Iterator<IndexableMetadataField> findAll(Context context) throws SQLException {
final Iterator<MetadataField> metadataFields = metadataFieldService.findAll(context).iterator();
return new Iterator<>() {
@Override
public boolean hasNext() {
return metadataFields.hasNext();
}
@Override
public IndexableMetadataField next() {
return new IndexableMetadataField(metadataFields.next());
}
};
}
@Override
public String getType() {
return IndexableMetadataField.TYPE;
}
@Override
public Optional<IndexableMetadataField> findIndexableObject(Context context, String id) throws SQLException {
final MetadataField metadataField = metadataFieldService.find(context, Integer.parseInt(id));
return metadataField == null ? Optional.empty() : Optional.of(new IndexableMetadataField(metadataField));
}
@Override
public boolean supports(Object object) {
return object instanceof MetadataField;
}
@Override
public List getIndexableObjects(Context context, MetadataField object) {
return Arrays.asList(new IndexableMetadataField(object));
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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.discovery.indexobject.factory;
import org.dspace.content.MetadataField;
import org.dspace.discovery.indexobject.IndexableMetadataField;
/**
* Factory interface for indexing/retrieving {@link org.dspace.content.MetadataField} items in the search core
*
* @author Maria Verdonck (Atmire) on 14/07/2020
*/
public interface MetadataFieldIndexFactory extends IndexFactory<IndexableMetadataField, MetadataField> {
}

View File

@@ -0,0 +1,93 @@
/**
* 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.discovery;
import static org.junit.Assert.assertTrue;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.AbstractUnitTest;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.discovery.indexobject.IndexableMetadataField;
import org.dspace.discovery.indexobject.MetadataFieldIndexFactoryImpl;
import org.junit.Test;
/**
* Test class for {@link MetadataFieldIndexFactoryImpl}
*
* @author Maria Verdonck (Atmire) on 23/07/2020
*/
public class MetadataFieldIndexFactoryImplTest extends AbstractUnitTest {
private MetadataSchemaService metadataSchemaService =
ContentServiceFactory.getInstance().getMetadataSchemaService();
private MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
private String schemaName = "schema1";
private String elemName1 = "elem1";
private String elemName2 = "elem2";
private String qualName1 = "qual1";
private MetadataSchema schema;
private MetadataField field1;
private MetadataField field2;
@Test
public void test_buildDocument_withQualifier() throws Exception {
context.turnOffAuthorisationSystem();
schema = metadataSchemaService.create(context, schemaName, "htpp://test/schema/");
field1 = metadataFieldService.create(context, schema, elemName1, qualName1, "note 1");
MetadataFieldIndexFactoryImpl fieldIndexFactory = new MetadataFieldIndexFactoryImpl();
IndexableMetadataField indexableMetadataField = new IndexableMetadataField(this.field1);
SolrInputDocument solrInputDocument = fieldIndexFactory.buildDocument(context, indexableMetadataField);
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.SCHEMA_FIELD_NAME + "_keyword")
.contains(this.field1.getMetadataSchema().getName()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.ELEMENT_FIELD_NAME + "_keyword")
.contains(this.field1.getElement()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.QUALIFIER_FIELD_NAME + "_keyword")
.contains(this.field1.getQualifier()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS + "_keyword")
.contains(this.field1.getQualifier()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS + "_keyword")
.contains(this.field1.getElement() + "." + this.field1.getQualifier()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS + "_keyword")
.contains(this.field1.toString('.')));
metadataSchemaService.delete(context, schema);
metadataFieldService.delete(context, field1);
context.restoreAuthSystemState();
}
@Test
public void test_buildDocument_noQualifier() throws Exception {
context.turnOffAuthorisationSystem();
schema = metadataSchemaService.create(context, schemaName, "htpp://test/schema/");
field2 = metadataFieldService.create(context, schema, elemName2, null, "note 2");
MetadataFieldIndexFactoryImpl fieldIndexFactory = new MetadataFieldIndexFactoryImpl();
IndexableMetadataField indexableMetadataField = new IndexableMetadataField(this.field2);
SolrInputDocument solrInputDocument = fieldIndexFactory.buildDocument(context, indexableMetadataField);
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.SCHEMA_FIELD_NAME + "_keyword")
.contains(this.field2.getMetadataSchema().getName()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.ELEMENT_FIELD_NAME + "_keyword")
.contains(this.field2.getElement()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS + "_keyword")
.contains(this.field2.getElement()));
assertTrue(solrInputDocument.getFieldValues(MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS + "_keyword")
.contains(this.field2.toString('.')));
metadataSchemaService.delete(context, schema);
metadataFieldService.delete(context, field2);
context.restoreAuthSystemState();
}
}

View File

@@ -18,6 +18,7 @@ import org.dspace.app.rest.RestResourceController;
*/
public class MetadataFieldRest extends BaseObjectRest<Integer> {
public static final String NAME = "metadatafield";
public static final String NAME_PLURAL = "metadatafields";
public static final String CATEGORY = RestAddressableModel.CORE;
@JsonIgnore

View File

@@ -9,9 +9,11 @@ package org.dspace.app.rest.repository;
import static java.lang.Integer.parseInt;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.dspace.app.rest.model.SearchConfigurationRest.Filter.OPERATOR_EQUALS;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
@@ -19,6 +21,8 @@ import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.Parameter;
import org.dspace.app.rest.SearchRestMethod;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
@@ -31,6 +35,13 @@ import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context;
import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.IndexableObject;
import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.indexobject.IndexableMetadataField;
import org.dspace.discovery.indexobject.MetadataFieldIndexFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -45,6 +56,10 @@ import org.springframework.stereotype.Component;
*/
@Component(MetadataFieldRest.CATEGORY + "." + MetadataFieldRest.NAME)
public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFieldRest, Integer> {
/**
* log4j logger
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataFieldRestRepository.class);
@Autowired
MetadataFieldService metadataFieldService;
@@ -52,6 +67,9 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Autowired
MetadataSchemaService metadataSchemaService;
@Autowired
private SearchService searchService;
@Override
@PreAuthorize("permitAll()")
public MetadataFieldRest findOne(Context context, Integer id) {
@@ -79,7 +97,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@SearchRestMethod(name = "bySchema")
public Page<MetadataFieldRest> findBySchema(@Parameter(value = "schema", required = true) String schemaName,
Pageable pageable) {
Pageable pageable) {
try {
Context context = obtainContext();
MetadataSchema schema = metadataSchemaService.find(context, schemaName);
@@ -93,6 +111,108 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
}
}
/**
* Endpoint for the search in the {@link MetadataField} objects by various different params representing the
* field name. Query being a partial
*
* @param schemaName an exact match of the prefix of the metadata schema (e.g. "dc", "dcterms", "eperson")
* @param elementName an exact match of the field's element (e.g. "contributor", "title")
* @param qualifierName an exact match of the field's qualifier (e.g. "author", "alternative")
* @param query part of the fully qualified field, should start with the start of the schema, element or
* qualifier (e.g. "dc.ti", "contributor", "auth", "contributor.ot")
* @param exactName exactName, The exact fully qualified field, should use the syntax schema.element
* .qualifier or schema.element if no qualifier exists (e.g. "dc.title", "dc.contributor
* .author"). It will only return one value if there's an exact match
* @param pageable the pagination options
* @return List of {@link MetadataFieldRest} objects representing all {@link MetadataField} objects that match
* the given params
*/
@SearchRestMethod(name = "byFieldName")
public Page<MetadataFieldRest> findByFieldName(@Parameter(value = "schema", required = false) String schemaName,
@Parameter(value = "element", required = false) String elementName,
@Parameter(value = "qualifier", required = false) String qualifierName,
@Parameter(value = "query", required = false) String query,
@Parameter(value = "exactName", required = false) String exactName,
Pageable pageable) throws SQLException {
Context context = obtainContext();
List<MetadataField> matchingMetadataFields = new ArrayList<>();
if (StringUtils.isBlank(exactName)) {
// Find matches in Solr Search core
DiscoverQuery discoverQuery =
this.createDiscoverQuery(context, schemaName, elementName, qualifierName, query);
try {
DiscoverResult searchResult = searchService.search(context, null, discoverQuery);
for (IndexableObject object : searchResult.getIndexableObjects()) {
if (object instanceof IndexableMetadataField) {
matchingMetadataFields.add(((IndexableMetadataField) object).getIndexedObject());
}
}
} catch (SearchServiceException e) {
log.error("Error while searching with Discovery", e);
throw new IllegalArgumentException("Error while searching with Discovery: " + e.getMessage());
}
} else {
if (StringUtils.isNotBlank(elementName) || StringUtils.isNotBlank(qualifierName) ||
StringUtils.isNotBlank(schemaName) || StringUtils.isNotBlank(query)) {
throw new UnprocessableEntityException("Use either exactName or a combination of element, qualifier " +
"and schema to search discovery for metadata fields");
}
// Find at most one match with exactName query param in DB
MetadataField exactMatchingMdField = metadataFieldService.findByString(context, exactName, '.');
if (exactMatchingMdField != null) {
matchingMetadataFields.add(exactMatchingMdField);
}
}
return converter.toRestPage(matchingMetadataFields, pageable, utils.obtainProjection());
}
/**
* Creates a discovery query containing the filter queries derived from the request params
*
* @param context Context request
* @param schemaName an exact match of the prefix of the metadata schema (e.g. "dc", "dcterms", "eperson")
* @param elementName an exact match of the field's element (e.g. "contributor", "title")
* @param qualifierName an exact match of the field's qualifier (e.g. "author", "alternative")
* @param query part of the fully qualified field, should start with the start of the schema, element or
* qualifier (e.g. "dc.ti", "contributor", "auth", "contributor.ot")
* @return Discover query containing the filter queries derived from the request params
* @throws SQLException If DB error
*/
private DiscoverQuery createDiscoverQuery(Context context, String schemaName, String elementName,
String qualifierName, String query) throws SQLException {
List<String> filterQueries = new ArrayList<>();
if (StringUtils.isNotBlank(query)) {
if (query.split("\\.").length > 3) {
throw new IllegalArgumentException("Query param should not contain more than 2 dot (.) separators, " +
"forming schema.element.qualifier metadata field name");
}
filterQueries.add(searchService.toFilterQuery(context, MetadataFieldIndexFactoryImpl.FIELD_NAME_VARIATIONS,
OPERATOR_EQUALS, query).getFilterQuery() + "*");
}
if (StringUtils.isNotBlank(schemaName)) {
filterQueries.add(
searchService.toFilterQuery(context, MetadataFieldIndexFactoryImpl.SCHEMA_FIELD_NAME, OPERATOR_EQUALS,
schemaName).getFilterQuery());
}
if (StringUtils.isNotBlank(elementName)) {
filterQueries.add(
searchService.toFilterQuery(context, MetadataFieldIndexFactoryImpl.ELEMENT_FIELD_NAME, OPERATOR_EQUALS,
elementName).getFilterQuery());
}
if (StringUtils.isNotBlank(qualifierName)) {
filterQueries.add(searchService
.toFilterQuery(context, MetadataFieldIndexFactoryImpl.QUALIFIER_FIELD_NAME, OPERATOR_EQUALS,
qualifierName).getFilterQuery());
}
DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.addFilterQueries(filterQueries.toArray(new String[filterQueries.size()]));
return discoverQuery;
}
@Override
public Class<MetadataFieldRest> getDomainClass() {
return MetadataFieldRest.class;
@@ -101,15 +221,15 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected MetadataFieldRest createAndReturn(Context context)
throws AuthorizeException, SQLException {
throws AuthorizeException, SQLException {
// parse request body
MetadataFieldRest metadataFieldRest;
try {
metadataFieldRest = new ObjectMapper().readValue(
getRequestService().getCurrentRequest().getHttpServletRequest().getInputStream(),
MetadataFieldRest.class
);
getRequestService().getCurrentRequest().getHttpServletRequest().getInputStream(),
MetadataFieldRest.class
);
} catch (IOException excIO) {
throw new DSpaceBadRequestException("error parsing request body", excIO);
}
@@ -133,14 +253,14 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
MetadataField metadataField;
try {
metadataField = metadataFieldService.create(context, schema,
metadataFieldRest.getElement(), metadataFieldRest.getQualifier(), metadataFieldRest.getScopeNote());
metadataFieldRest.getElement(), metadataFieldRest.getQualifier(), metadataFieldRest.getScopeNote());
metadataFieldService.update(context, metadataField);
} catch (NonUniqueMetadataException e) {
throw new UnprocessableEntityException(
"metadata field "
+ schema.getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists"
"metadata field "
+ schema.getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists"
);
} catch (IOException e) {
throw new RuntimeException(e);
@@ -170,7 +290,7 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
@Override
@PreAuthorize("hasAuthority('ADMIN')")
protected MetadataFieldRest put(Context context, HttpServletRequest request, String apiCategory, String model,
Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException {
Integer id, JsonNode jsonNode) throws SQLException, AuthorizeException {
MetadataFieldRest metadataFieldRest = new Gson().fromJson(jsonNode.toString(), MetadataFieldRest.class);
@@ -196,9 +316,11 @@ public class MetadataFieldRestRepository extends DSpaceRestRepository<MetadataFi
context.commit();
} catch (NonUniqueMetadataException e) {
throw new UnprocessableEntityException("metadata field "
+ metadataField.getMetadataSchema().getName() + "." + metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ? "." + metadataFieldRest.getQualifier() : "")
+ " already exists");
+ metadataField.getMetadataSchema().getName() + "." +
metadataFieldRest.getElement()
+ (metadataFieldRest.getQualifier() != null ?
"." + metadataFieldRest.getQualifier() : "")
+ " already exists");
} catch (IOException e) {
throw new RuntimeException(e);
}

View File

@@ -8,6 +8,7 @@
package org.dspace.app.rest;
import static com.jayway.jsonpath.JsonPath.read;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
@@ -54,6 +55,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
private MetadataSchema metadataSchema;
public static final String METADATAFIELDS_ENDPOINT = "/api/core/metadatafields/";
private static final String SEARCH_BYFIELDNAME_ENDPOINT = METADATAFIELDS_ENDPOINT + "search/byFieldName";
@Autowired
private MetadataSchemaService metadataSchemaService;
@@ -74,13 +78,13 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields")
.param("size", String.valueOf(100)))
.param("size", String.valueOf(100)))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "title", null),
MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "date", "issued"))
))
))
.andExpect(jsonPath("$._links.first.href", Matchers.containsString("/api/core/metadatafields")))
.andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/core/metadatafields")))
.andExpect(jsonPath("$._links.next.href", Matchers.containsString("/api/core/metadatafields")))
@@ -102,7 +106,7 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$", Matchers.is(
MetadataFieldMatcher.matchMetadataField(metadataField)
)));
)));
}
@Test
@@ -122,30 +126,30 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement", "AQualifier", "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get("/api/core/metadatafields/search/bySchema")
.param("schema", "dc")
.param("size", String.valueOf(100)))
.param("schema", "dc")
.param("size", String.valueOf(100)))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItems(
MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "title", null),
MetadataFieldMatcher.matchMetadataFieldByKeys("dc", "date", "issued"))
))
))
.andExpect(jsonPath("$.page.size", is(100)));
getClient().perform(get("/api/core/metadatafields/search/bySchema")
.param("schema", schema.getName()))
.param("schema", schema.getName()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@@ -154,7 +158,7 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
public void findByUndefinedSchema() throws Exception {
getClient().perform(get("/api/core/metadatafields/search/bySchema")
.param("schema", "undefined"))
.param("schema", "undefined"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.page.size", is(20)))
@@ -168,6 +172,394 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
.andExpect(status().isBadRequest());
}
@Test
public void findByFieldName_schema() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement", "AQualifier", "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", schema.getName()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByFieldName_element() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema2",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement", "AQualifier", "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement", "AQualifier2", "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("element", "AnElement"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)));
}
@Test
public void findByFieldName_elementAndQualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema2",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", "AQualifier", "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", "AQualifier", "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement2", "AQualifier", "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("element", "AnElement2")
.param("qualifier", "AQualifier"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)));
}
@Test
public void findByFieldName_schemaAndQualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema2",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", "AQualifier", "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", "AQualifier", "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement3", "AQualifier", "AScopeNote3").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", schema.getName())
.param("qualifier", "AQualifier"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)));
}
@Test
public void findByFieldName_schemaElementAndQualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema2",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", "AQualifier", "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", "AQualifier", "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement3", "AQualifier", "AScopeNote3").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", schema.getName())
.param("element", metadataField3.getElement())
.param("qualifier", metadataField3.getQualifier()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByFieldName_query() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema2",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", "AQualifier", "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", "AQualifier", "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement3", "AQualifier", "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("query", schema.getName()))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(3)));
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("query", schema.getName() + ".AnElement3"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("query", "AnElement3.AQual"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByFieldName_query_noQualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "test",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", null, "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "test", null, "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("query", "test"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)));
}
@Test
public void findByFieldName_invalidQuery() throws Exception {
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("query", "schema.element.qualifier.morestuff"))
.andExpect(status().isBadRequest());
}
@Test
public void findByFieldName_exactName() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataSchema schema2 = MetadataSchemaBuilder.createMetadataSchema(context, "test",
"http://www.dspace.org/ns/aschema2").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
MetadataField metadataField2 = MetadataFieldBuilder
.createMetadataField(context, schema2, "AnElement2", null, "AScopeNote2").build();
MetadataField metadataField3 = MetadataFieldBuilder
.createMetadataField(context, schema, "test", null, "AScopeNote2").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.')))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField3))
)))
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.not(hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField2))
)))
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(1)));
}
@Test
public void findByFieldName_exactName_NoResult() throws Exception {
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", "not.valid.mdstring"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.page.totalElements", is(0)));
}
@Test
public void findByFieldName_exactName_combinedDiscoveryQueryParams_query() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.'))
.param("query", "query"))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void findByFieldName_exactName_combinedDiscoveryQueryParams_schema() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.'))
.param("schema", "schema"))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void findByFieldName_exactName_combinedDiscoveryQueryParams_element() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.'))
.param("element", "element"))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void findByFieldName_exactName_combinedDiscoveryQueryParams_qualifier() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder
.createMetadataField(context, schema, "AnElement1", null, "AScopeNote").build();
context.restoreAuthSystemState();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("exactName", metadataField.toString('.'))
.param("qualifier", "qualifier"))
.andExpect(status().isUnprocessableEntity());
}
@Test
public void createSuccess() throws Exception {
@@ -183,10 +575,10 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient(authToken)
.perform(post("/api/core/metadatafields")
.param("schemaId", metadataSchema.getID() + "")
.param("projection", "full")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.param("schemaId", metadataSchema.getID() + "")
.param("projection", "full")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isCreated())
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
@@ -199,6 +591,49 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
}
}
@Test
public void create_checkAddedToIndex() throws Exception {
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setElement("testElementForCreate");
metadataFieldRest.setQualifier("testQualifierForCreate");
metadataFieldRest.setScopeNote(SCOPE_NOTE);
String authToken = getAuthToken(admin.getEmail(), password);
AtomicReference<Integer> idRef = new AtomicReference<>();
try {
assertThat(metadataFieldService.findByElement(context, metadataSchema, ELEMENT, QUALIFIER), nullValue());
getClient(authToken)
.perform(post("/api/core/metadatafields")
.param("schemaId", metadataSchema.getID() + "")
.param("projection", "full")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isCreated())
.andDo(result -> idRef.set(read(result.getResponse().getContentAsString(), "$.id")));
getClient(authToken).perform(get("/api/core/metadatafields/" + idRef.get()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
metadataSchema.getName(), "testElementForCreate", "testQualifierForCreate")));
// new metadata field found in index
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", metadataSchema.getName())
.param("element", metadataFieldRest.getElement())
.param("qualifier", metadataFieldRest.getQualifier()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataFieldByKeys(metadataSchema.getName(),
metadataFieldRest.getElement(), metadataFieldRest.getQualifier()))
))
.andExpect(jsonPath("$.page.totalElements", is(1)));
} finally {
MetadataFieldBuilder.deleteMetadataField(idRef.get());
}
}
@Test
public void createUnauthorized() throws Exception {
@@ -209,9 +644,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient()
.perform(post("/api/core/metadatafields")
.param("schemaId", metadataSchema.getID() + "")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.param("schemaId", metadataSchema.getID() + "")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isUnauthorized());
}
@@ -227,9 +662,9 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient(token)
.perform(post("/api/core/metadatafields")
.param("schemaId", metadataSchema.getID() + "")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.param("schemaId", metadataSchema.getID() + "")
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isForbidden());
}
@@ -315,6 +750,44 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
.andExpect(status().isNotFound());
}
@Test
public void delete_checkDeletedFromIndex() throws Exception {
context.turnOffAuthorisationSystem();
MetadataSchema schema = MetadataSchemaBuilder.createMetadataSchema(context, "ASchema",
"http://www.dspace.org/ns/aschema").build();
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, schema, ELEMENT, QUALIFIER,
SCOPE_NOTE).build();
context.restoreAuthSystemState();
Integer id = metadataField.getID();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", schema.getName())
.param("element", metadataField.getElement())
.param("qualifier", metadataField.getQualifier()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataField(metadataField))
));
getClient(getAuthToken(admin.getEmail(), password))
.perform(delete("/api/core/metadatafields/" + id))
.andExpect(status().isNoContent());
assertThat(metadataFieldService.find(context, id), nullValue());
// deleted metadata field not found in index
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", schema.getName())
.param("element", metadataField.getElement())
.param("qualifier", metadataField.getQualifier()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(0)));
}
@Test
public void update() throws Exception {
context.turnOffAuthorisationSystem();
@@ -332,15 +805,68 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient(getAuthToken(admin.getEmail(), password))
.perform(put("/api/core/metadatafields/" + metadataField.getID())
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isOk());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
metadataSchema.getName(), ELEMENT_UPDATED, QUALIFIER_UPDATED)
));
));
}
@Test
public void update_checkUpdatedInIndex() throws Exception {
context.turnOffAuthorisationSystem();
MetadataField metadataField = MetadataFieldBuilder.createMetadataField(context, ELEMENT, QUALIFIER, SCOPE_NOTE)
.build();
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", metadataSchema.getName())
.param("element", metadataField.getElement())
.param("qualifier", metadataField.getQualifier()))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataFieldByKeys(metadataSchema.getName(),
metadataField.getElement(), metadataField.getQualifier()))
))
.andExpect(jsonPath("$.page.totalElements", is(1)));
context.restoreAuthSystemState();
MetadataFieldRest metadataFieldRest = new MetadataFieldRest();
metadataFieldRest.setId(metadataField.getID());
metadataFieldRest.setElement(ELEMENT_UPDATED);
metadataFieldRest.setQualifier(QUALIFIER_UPDATED);
metadataFieldRest.setScopeNote(SCOPE_NOTE_UPDATED);
getClient(getAuthToken(admin.getEmail(), password))
.perform(put("/api/core/metadatafields/" + metadataField.getID())
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isOk());
// new metadata field found in index
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", metadataSchema.getName())
.param("element", ELEMENT_UPDATED)
.param("qualifier", QUALIFIER_UPDATED))
.andExpect(status().isOk())
.andExpect(jsonPath("$._embedded.metadatafields", Matchers.hasItem(
MetadataFieldMatcher.matchMetadataFieldByKeys(metadataSchema.getName(),
ELEMENT_UPDATED, QUALIFIER_UPDATED))
))
.andExpect(jsonPath("$.page.totalElements", is(1)));
// original metadata field not found in index
getClient().perform(get(SEARCH_BYFIELDNAME_ENDPOINT)
.param("schema", metadataSchema.getName())
.param("element", metadataField.getElement())
.param("qualifier", metadataField.getQualifier()))
.andExpect(status().isOk())
.andExpect(jsonPath("$.page.totalElements", is(0)));
}
@Test
@@ -360,15 +886,15 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient()
.perform(put("/api/core/metadatafields/" + metadataField.getID())
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isUnauthorized());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
metadataSchema.getName(), ELEMENT, QUALIFIER)
));
));
}
@@ -390,15 +916,15 @@ public class MetadatafieldRestRepositoryIT extends AbstractControllerIntegration
getClient(getAuthToken(eperson.getEmail(), password))
.perform(put("/api/core/metadatafields/" + metadataField.getID())
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.content(new ObjectMapper().writeValueAsBytes(metadataFieldRest))
.contentType(contentType))
.andExpect(status().isForbidden());
getClient().perform(get("/api/core/metadatafields/" + metadataField.getID()))
.andExpect(status().isOk())
.andExpect(jsonPath("$", MetadataFieldMatcher.matchMetadataFieldByKeys(
metadataSchema.getName(), ELEMENT, QUALIFIER)
));
));
}

View File

@@ -672,7 +672,7 @@ event.dispatcher.noindex.consumers = eperson
# consumer to maintain the discovery index
event.consumer.discovery.class = org.dspace.discovery.IndexEventConsumer
event.consumer.discovery.filters = Community|Collection|Item|Bundle+Add|Create|Modify|Modify_Metadata|Delete|Remove
event.consumer.discovery.filters = Community|Collection|Item|Bundle|Site+Add|Create|Modify|Modify_Metadata|Delete|Remove
# consumer related to EPerson changes
event.consumer.eperson.class = org.dspace.eperson.EPersonConsumer

View File

@@ -126,6 +126,7 @@
<bean class="org.dspace.discovery.indexobject.PoolTaskIndexFactoryImpl" autowire-candidate="true"/>
<bean class="org.dspace.discovery.indexobject.WorkflowItemIndexFactoryImpl" autowire-candidate="true"/>
<bean class="org.dspace.discovery.indexobject.WorkspaceItemIndexFactoryImpl" autowire-candidate="true"/>
<bean class="org.dspace.discovery.indexobject.MetadataFieldIndexFactoryImpl" autowire-candidate="true"/>
</beans>