Skip to content

Commit

Permalink
Merge pull request DSpace#9478 from toniprieto/form-by-entity-type-wi…
Browse files Browse the repository at this point in the history
…th-map

Refactor SubmissionConfigReader to use a map for the item process configurations based on entityType
  • Loading branch information
tdonohue authored May 2, 2024
2 parents e632c30 + b0d314f commit c15d939
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.dspace.discovery.SearchServiceException;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.w3c.dom.Document;
Expand Down Expand Up @@ -99,6 +99,13 @@ public class SubmissionConfigReader {
*/
private Map<String, String> communityToSubmissionConfig = null;

/**
* Hashmap which stores which submission process configuration is used by
* which entityType, computed from the item submission config file
* (specifically, the 'submission-map' tag)
*/
private Map<String, String> entityTypeToSubmissionConfig = null;

/**
* Reference to the global submission step definitions defined in the
* "step-definitions" section
Expand Down Expand Up @@ -137,6 +144,7 @@ public SubmissionConfigReader() throws SubmissionConfigReaderException {
public void reload() throws SubmissionConfigReaderException {
collectionToSubmissionConfig = null;
communityToSubmissionConfig = null;
entityTypeToSubmissionConfig = null;
stepDefns = null;
submitDefns = null;
buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX);
Expand All @@ -156,6 +164,7 @@ public void reload() throws SubmissionConfigReaderException {
private void buildInputs(String fileName) throws SubmissionConfigReaderException {
collectionToSubmissionConfig = new HashMap<String, String>();
communityToSubmissionConfig = new HashMap<String, String>();
entityTypeToSubmissionConfig = new HashMap<String, String>();
submitDefns = new LinkedHashMap<String, List<Map<String, String>>>();

String uri = "file:" + new File(fileName).getAbsolutePath();
Expand All @@ -173,9 +182,6 @@ private void buildInputs(String fileName) throws SubmissionConfigReaderException
} catch (FactoryConfigurationError fe) {
throw new SubmissionConfigReaderException(
"Cannot create Item Submission Configuration parser", fe);
} catch (SearchServiceException se) {
throw new SubmissionConfigReaderException(
"Cannot perform a discovery search for Item Submission Configuration", se);
} catch (Exception e) {
throw new SubmissionConfigReaderException(
"Error creating Item Submission Configuration: " + e);
Expand Down Expand Up @@ -238,6 +244,16 @@ public SubmissionConfig getSubmissionConfigByCollection(Collection col) {
return getSubmissionConfigByName(submitName);
}

// get the name of the submission process based on the entity type of this collections
if (!entityTypeToSubmissionConfig.isEmpty()) {
String entityType = collectionService.getMetadataFirstValue(col, "dspace", "entity", "type", Item.ANY);
submitName = entityTypeToSubmissionConfig
.get(entityType);
if (submitName != null) {
return getSubmissionConfigByName(submitName);
}
}

if (!communityToSubmissionConfig.isEmpty()) {
try {
List<Community> communities = col.getCommunities();
Expand Down Expand Up @@ -358,7 +374,7 @@ public SubmissionStepConfig getStepConfig(String stepID)
* should correspond to the collection-form maps, the form definitions, and
* the display/storage word pairs.
*/
private void doNodes(Node n) throws SAXException, SearchServiceException, SubmissionConfigReaderException {
private void doNodes(Node n) throws SAXException, SubmissionConfigReaderException {
if (n == null) {
return;
}
Expand Down Expand Up @@ -405,9 +421,7 @@ private void doNodes(Node n) throws SAXException, SearchServiceException, Submis
* the collection handle and item submission name, put name in hashmap keyed
* by the collection handle.
*/
private void processMap(Node e) throws SAXException, SearchServiceException {
// create a context
Context context = new Context();
private void processMap(Node e) throws SAXException {

NodeList nl = e.getChildNodes();
int len = nl.getLength();
Expand All @@ -428,7 +442,7 @@ private void processMap(Node e) throws SAXException, SearchServiceException {
throw new SAXException(
"name-map element is missing submission-name attribute in 'item-submission.xml'");
}
if (content != null && content.length() > 0) {
if (content != null && !content.isEmpty()) {
throw new SAXException(
"name-map element has content in 'item-submission.xml', it should be empty.");
}
Expand All @@ -437,12 +451,7 @@ private void processMap(Node e) throws SAXException, SearchServiceException {
} else if (communityId != null) {
communityToSubmissionConfig.put(communityId, value);
} else {
// get all collections for this entity-type
List<Collection> collections = collectionService.findAllCollectionsByEntityType( context,
entityType);
for (Collection collection : collections) {
collectionToSubmissionConfig.putIfAbsent(collection.getHandle(), value);
}
entityTypeToSubmissionConfig.put(entityType, value);
}
} // ignore any child node that isn't a "name-map"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1109,26 +1109,6 @@ public int countCollectionsWithSubmit(String q, Context context, Community commu
return (int) resp.getTotalSearchResults();
}

@Override
@SuppressWarnings("rawtypes")
public List<Collection> findAllCollectionsByEntityType(Context context, String entityType)
throws SearchServiceException {
List<Collection> collectionList = new ArrayList<>();

DiscoverQuery discoverQuery = new DiscoverQuery();
discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
discoverQuery.addFilterQueries("dspace.entity.type:" + entityType);

DiscoverResult discoverResult = searchService.search(context, discoverQuery);
List<IndexableObject> solrIndexableObjects = discoverResult.getIndexableObjects();

for (IndexableObject solrCollection : solrIndexableObjects) {
Collection c = ((IndexableCollection) solrCollection).getIndexedObject();
collectionList.add(c);
}
return collectionList;
}

/**
* Returns total collection archived items
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,21 +484,6 @@ public int countCollectionsWithSubmit(String q, Context context, Community commu
public int countCollectionsWithSubmit(String q, Context context, Community community, String entityType)
throws SQLException, SearchServiceException;

/**
* Returns a list of all collections for a specific entity type.
* NOTE: for better performance, this method retrieves its results from an index (cache)
* and does not query the database directly.
* This means that results may be stale or outdated until
* https://github.com/DSpace/DSpace/issues/2853 is resolved."
*
* @param context DSpace Context
* @param entityType limit the returned collection to those related to given entity type
* @return list of collections found
* @throws SearchServiceException if search error
*/
public List<Collection> findAllCollectionsByEntityType(Context context, String entityType)
throws SearchServiceException;

/**
* Returns total collection archived items
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<name-map community-handle="123456789/topcommunity-test" submission-name="topcommunitytest"/>
<name-map community-handle="123456789/subcommunity-test" submission-name="subcommunitytest"/>
<name-map collection-handle="123456789/collection-test" submission-name="collectiontest"/>
<name-map collection-entity-type="CustomEntityType" submission-name="entitytypetest"/>
<name-map collection-handle="123456789/test-duplicate-detection" submission-name="test-duplicate-detection"/>
</submission-map>

Expand Down Expand Up @@ -289,6 +290,10 @@
<step id="collection"/>
</submission-process>

<submission-process name="entitytypetest">
<step id="collection"/>
</submission-process>

<submission-process name="test-duplicate-detection">
<step id="collection"/>
<step id="duplicates"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ public void testSubmissionMapByCommunityHandleSubmissionConfig()
// col3 should use the item submission form directly mapped for this collection
Collection col3 = CollectionBuilder.createCollection(context, subcom1, "123456789/collection-test")
.withName("Collection 3")
.withEntityType("CustomEntityType")
.build();
// col4 should use the item submission form mapped for the entity type CustomEntityType
Collection col4 = CollectionBuilder.createCollection(context, subcom1, "123456789/not-mapped4")
.withName("Collection 4")
.withEntityType("CustomEntityType")
.build();
context.restoreAuthSystemState();

Expand All @@ -69,5 +75,8 @@ public void testSubmissionMapByCommunityHandleSubmissionConfig()
SubmissionConfig submissionConfig3 = submissionConfigService.getSubmissionConfigByCollection(col3);
assertEquals("collectiontest", submissionConfig3.getSubmissionName());

// for col4, it should return the item submission form defined for the entitytype CustomEntityType
SubmissionConfig submissionConfig4 = submissionConfigService.getSubmissionConfigByCollection(col4);
assertEquals("entitytypetest", submissionConfig4.getSubmissionName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class SubmissionDefinitionsControllerIT extends AbstractControllerIntegra
// The total number of expected submission definitions is referred to in multiple tests and assertions as
// is the last page (totalDefinitions - 1)
// This integer should be maintained along with any changes to item-submissions.xml
private static final int totalDefinitions = 11;
private static final int totalDefinitions = 12;

@Test
public void findAll() throws Exception {
Expand Down Expand Up @@ -419,7 +419,7 @@ public void findAllPaginationTest() throws Exception {
Matchers.containsString("page=5"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
Expand All @@ -445,7 +445,7 @@ public void findAllPaginationTest() throws Exception {
Matchers.containsString("page=6"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
Expand All @@ -471,7 +471,7 @@ public void findAllPaginationTest() throws Exception {
Matchers.containsString("page=7"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
Expand All @@ -497,7 +497,7 @@ public void findAllPaginationTest() throws Exception {
Matchers.containsString("page=8"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
Expand All @@ -515,16 +515,68 @@ public void findAllPaginationTest() throws Exception {
.andExpect(jsonPath("$._links.prev.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=8"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.next.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.self.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=9"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
.andExpect(jsonPath("$.page.number", is(9)));

getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions")
.param("size", "1")
.param("page", "10"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("entitytypetest")))
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=0"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.prev.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=9"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.next.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=11"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.self.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
.andExpect(jsonPath("$.page.number", is(10)));

getClient(tokenAdmin).perform(get("/api/config/submissiondefinitions")
.param("size", "1")
.param("page", "11"))
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$._embedded.submissiondefinitions[0].id", is("test-duplicate-detection")))
.andExpect(jsonPath("$._links.first.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=0"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.prev.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=10"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.self.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=11"), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$._links.last.href", Matchers.allOf(
Matchers.containsString("/api/config/submissiondefinitions?"),
Matchers.containsString("page=" + (totalDefinitions - 1)), Matchers.containsString("size=1"))))
.andExpect(jsonPath("$.page.size", is(1)))
.andExpect(jsonPath("$.page.totalElements", is(totalDefinitions)))
.andExpect(jsonPath("$.page.totalPages", is(totalDefinitions)))
.andExpect(jsonPath("$.page.number", is(11)));
}

}
7 changes: 6 additions & 1 deletion dspace/config/dspace.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,7 @@ event.dispatcher.default.class = org.dspace.event.BasicDispatcher
# Add rdf here, if you are using dspace-rdf to export your repository content as RDF.
# Add iiif here, if you are using dspace-iiif.
# Add orcidqueue here, if the integration with ORCID is configured and wish to enable the synchronization queue functionality
event.dispatcher.default.consumers = versioning, discovery, eperson, submissionconfig, qaeventsdelete, ldnmessage
event.dispatcher.default.consumers = versioning, discovery, eperson, qaeventsdelete, ldnmessage

# The noindex dispatcher will not create search or browse indexes (useful for batch item imports)
event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher
Expand Down Expand Up @@ -831,6 +831,11 @@ event.consumer.ldnmessage.class = org.dspace.app.ldn.LDNMessageConsumer
event.consumer.ldnmessage.filters = Item+Install

# item submission config reload consumer
# This consumer can be useful for reloading changes made in the item-submission.xml config file,
# without restarting Tomcat, primarily for adding new collection mappings.
# With this consumer, configuration reloading is triggered after a collection is updated.
# It is disabled by default. To enable it, add 'submissionconfig' to the list of
# activated consumers (event.dispatcher.default.consumers).
event.consumer.submissionconfig.class = org.dspace.submit.consumer.SubmissionConfigConsumer
event.consumer.submissionconfig.filters = Collection+Modify_Metadata

Expand Down

0 comments on commit c15d939

Please sign in to comment.