Merge remote-tracking branch 'upstream/master' into DS-4351-upgrade-dependencies

This commit is contained in:
Kevin Van de Velde
2020-01-02 15:20:14 +01:00
19 changed files with 2900 additions and 305 deletions

View File

@@ -128,7 +128,7 @@ public class ItemCountDAOSolr implements ItemCountDAO {
DiscoverResult sResponse = null; DiscoverResult sResponse = null;
try { try {
sResponse = searcher.search(context, query, false); sResponse = searcher.search(context, query);
List<FacetResult> commCount = sResponse.getFacetResult("location.comm"); List<FacetResult> commCount = sResponse.getFacetResult("location.comm");
List<FacetResult> collCount = sResponse.getFacetResult("location.coll"); List<FacetResult> collCount = sResponse.getFacetResult("location.coll");
for (FacetResult c : commCount) { for (FacetResult c : commCount) {

View File

@@ -169,9 +169,6 @@ public class SolrBrowseDAO implements BrowseDAO {
private DiscoverResult sResponse = null; private DiscoverResult sResponse = null;
private boolean itemsWithdrawn = false;
private boolean itemsDiscoverable = true;
private boolean showFrequencies; private boolean showFrequencies;
private DiscoverResult getSolrResponse() throws BrowseException { private DiscoverResult getSolrResponse() throws BrowseException {
@@ -217,8 +214,7 @@ public class SolrBrowseDAO implements BrowseDAO {
} }
} }
try { try {
sResponse = searcher.search(context, query, itemsWithdrawn sResponse = searcher.search(context, query);
|| !itemsDiscoverable);
} catch (SearchServiceException e) { } catch (SearchServiceException e) {
throw new BrowseException(e); throw new BrowseException(e);
} }
@@ -227,12 +223,6 @@ public class SolrBrowseDAO implements BrowseDAO {
} }
private void addStatusFilter(DiscoverQuery query) { private void addStatusFilter(DiscoverQuery query) {
if (itemsWithdrawn) {
query.addFilterQueries("withdrawn:true");
} else if (!itemsDiscoverable) {
query.addFilterQueries("discoverable:false");
// TODO
try { try {
if (!authorizeService.isAdmin(context) if (!authorizeService.isAdmin(context)
&& (authorizeService.isCommunityAdmin(context) && (authorizeService.isCommunityAdmin(context)
@@ -240,8 +230,7 @@ public class SolrBrowseDAO implements BrowseDAO {
query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context)); query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context));
} }
} catch (SQLException ex) { } catch (SQLException ex) {
log.error(ex); log.error("Error looking up authorization rights of current user", ex);
}
} }
} }
@@ -363,10 +352,9 @@ public class SolrBrowseDAO implements BrowseDAO {
query.setQuery("bi_" + column + "_sort" + ": {\"" + value + "\" TO *]"); query.setQuery("bi_" + column + "_sort" + ": {\"" + value + "\" TO *]");
query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)"); query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)");
} }
boolean includeUnDiscoverable = itemsWithdrawn || !itemsDiscoverable;
DiscoverResult resp = null; DiscoverResult resp = null;
try { try {
resp = searcher.search(context, query, includeUnDiscoverable); resp = searcher.search(context, query);
} catch (SearchServiceException e) { } catch (SearchServiceException e) {
throw new BrowseException(e); throw new BrowseException(e);
} }
@@ -693,11 +681,6 @@ public class SolrBrowseDAO implements BrowseDAO {
*/ */
@Override @Override
public void setTable(String table) { public void setTable(String table) {
if (table.equals(BrowseIndex.getWithdrawnBrowseIndex().getTableName())) {
itemsWithdrawn = true;
} else if (table.equals(BrowseIndex.getPrivateBrowseIndex().getTableName())) {
itemsDiscoverable = false;
}
facetField = table; facetField = table;
} }

View File

@@ -14,6 +14,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -462,7 +464,9 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
return bitstreamDAO.getNotReferencedBitstreams(context); return bitstreamDAO.getNotReferencedBitstreams(context);
} }
public Long getLastModified(Bitstream bitstream) { @Nullable
@Override
public Long getLastModified(Bitstream bitstream) throws IOException {
return bitstreamStorageService.getLastModified(bitstream); return bitstreamStorageService.getLastModified(bitstream);
} }
} }

View File

@@ -14,6 +14,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat; import org.dspace.content.BitstreamFormat;
@@ -222,5 +224,13 @@ public interface BitstreamService extends DSpaceObjectService<Bitstream>, DSpace
List<Bitstream> getNotReferencedBitstreams(Context context) throws SQLException; List<Bitstream> getNotReferencedBitstreams(Context context) throws SQLException;
public Long getLastModified(Bitstream bitstream); /**
* Gets the last modified timestamp of the the given bitstream's content, if known.
*
* @param bitstream the bitstream.
* @return the timestamp in milliseconds, or {@code null} if unknown.
* @throws IOException if an unexpected io error occurs.
*/
@Nullable
Long getLastModified(Bitstream bitstream) throws IOException;
} }

View File

@@ -51,29 +51,6 @@ public interface SearchService {
DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery query) DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery query)
throws SearchServiceException; throws SearchServiceException;
/**
* @param context DSpace Context object.
* @param query the discovery query object.
* @param includeWithdrawn use <code>true</code> to include in the results also withdrawn
* items that match the query.
* @return discovery search result object
* @throws SearchServiceException if search error
*/
DiscoverResult search(Context context, DiscoverQuery query,
boolean includeWithdrawn) throws SearchServiceException;
/**
* @param context DSpace Context object
* @param dso a DSpace Object to use as scope of the search (only results
* within this object)
* @param query the discovery query object
* @param includeWithdrawn use <code>true</code> to include in the results also withdrawn
* items that match the query
* @return discovery search result object
* @throws SearchServiceException if search error
*/
DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery query, boolean includeWithdrawn)
throws SearchServiceException;
List<IndexableObject> search(Context context, String query, String orderfield, boolean ascending, int offset, List<IndexableObject> search(Context context, String query, String orderfield, boolean ascending, int offset,
int max, String... filterquery); int max, String... filterquery);

View File

@@ -561,15 +561,23 @@ public class SolrServiceImpl implements SearchService, IndexingService {
// Query for all indexed Items, Collections and Communities, // Query for all indexed Items, Collections and Communities,
// returning just their handle // returning just their handle
query.setFields(HANDLE_FIELD, RESOURCE_UNIQUE_ID, RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD); query.setFields(HANDLE_FIELD, RESOURCE_UNIQUE_ID, RESOURCE_ID_FIELD, RESOURCE_TYPE_FIELD);
query.addSort(RESOURCE_UNIQUE_ID, SolrQuery.ORDER.asc);
query.setQuery(RESOURCE_TYPE_FIELD + ":" + type); query.setQuery(RESOURCE_TYPE_FIELD + ":" + type);
// Get the total amount of results
QueryResponse totalResponse = getSolr().query(query);
long total = totalResponse.getResults().getNumFound();
int start = 0;
int batch = 100;
query.setRows(batch);
while (start < total) {
query.setStart(start);
QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST); QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST);
SolrDocumentList docs = rsp.getResults(); SolrDocumentList docs = rsp.getResults();
Iterator iter = docs.iterator(); for (SolrDocument doc : docs) {
while (iter.hasNext()) {
SolrDocument doc = (SolrDocument) iter.next();
String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID); String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID);
IndexableObject o = findIndexableObject(context, doc); IndexableObject o = findIndexableObject(context, doc);
@@ -585,6 +593,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
log.debug("Keeping: " + o.getUniqueIndexID()); log.debug("Keeping: " + o.getUniqueIndexID());
} }
} }
start += batch;
}
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Error cleaning discovery index: " + e.getMessage(), e); log.error("Error cleaning discovery index: " + e.getMessage(), e);
@@ -1855,21 +1866,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} }
//========== SearchService implementation //========== SearchService implementation
@Override
public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException {
return search(context, query, false);
}
@Override @Override
public DiscoverResult search(Context context, IndexableObject dso, public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery)
DiscoverQuery query)
throws SearchServiceException { throws SearchServiceException {
return search(context, dso, query, false);
}
@Override
public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery,
boolean includeUnDiscoverable) throws SearchServiceException {
if (dso != null) { if (dso != null) {
if (dso instanceof Community) { if (dso instanceof Community) {
discoveryQuery.addFilterQueries("location:m" + dso.getID()); discoveryQuery.addFilterQueries("location:m" + dso.getID());
@@ -1879,19 +1879,19 @@ public class SolrServiceImpl implements SearchService, IndexingService {
discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + ((Item) dso).getHandle()); discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + ((Item) dso).getHandle());
} }
} }
return search(context, discoveryQuery, includeUnDiscoverable); return search(context, discoveryQuery);
} }
@Override @Override
public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable) public DiscoverResult search(Context context, DiscoverQuery discoveryQuery )
throws SearchServiceException { throws SearchServiceException {
try { try {
if (getSolr() == null) { if (getSolr() == null) {
return new DiscoverResult(); return new DiscoverResult();
} }
SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery, includeUnDiscoverable); SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery);
QueryResponse queryResponse = getSolr().query(solrQuery, SolrRequest.METHOD.POST); QueryResponse queryResponse = getSolr().query(solrQuery, SolrRequest.METHOD.POST);
@@ -1902,8 +1902,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} }
} }
protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery, protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery)
boolean includeUnDiscoverable) throws SearchServiceException { throws SearchServiceException {
SolrQuery solrQuery = new SolrQuery(); SolrQuery solrQuery = new SolrQuery();
String query = "*:*"; String query = "*:*";
@@ -1929,11 +1929,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
solrQuery.setParam("spellcheck", Boolean.TRUE); solrQuery.setParam("spellcheck", Boolean.TRUE);
} }
if (!includeUnDiscoverable) {
solrQuery.addFilterQuery("NOT(withdrawn:true)");
solrQuery.addFilterQuery("NOT(discoverable:false)");
}
for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) { for (int i = 0; i < discoveryQuery.getFilterQueries().size(); i++) {
String filterQuery = discoveryQuery.getFilterQueries().get(i); String filterQuery = discoveryQuery.getFilterQueries().get(i);
solrQuery.addFilterQuery(filterQuery); solrQuery.addFilterQuery(filterQuery);
@@ -2401,8 +2396,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} catch (Exception e) { } catch (Exception e) {
log.error( log.error(
LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()), LogManager.getHeader(context, "Error while retrieving related items", "Handle: "
e); + item.getHandle()), e);
} }
return results; return results;
} }

View File

@@ -0,0 +1,49 @@
/**
* 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.apache.logging.log4j.LogManager.getLogger;
import java.sql.SQLException;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This plugin prevents discovery of private items by non-administrators.
*/
public class SolrServicePrivateItemPlugin implements SolrServiceSearchPlugin {
private static final Logger log = getLogger(SolrServicePrivateItemPlugin.class.getSimpleName());
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Autowired(required = true)
protected SearchService searchService;
@Override
public void additionalSearchParameters(Context context, DiscoverQuery discoveryQuery, SolrQuery solrQuery) {
try {
// Prevents access if user has no administrative rights on the community or collection.
// NOTE: the resource restriction plugin adds location filters for community and collection admins.
if ( !authorizeService.isAdmin(context) && !authorizeService.isCommunityAdmin(context)
&& !authorizeService.isCollectionAdmin(context)) {
solrQuery.addFilterQuery("NOT(discoverable:false)");
}
} catch (SQLException ex) {
log.error(LogManager.getHeader(context, "Error looking up authorization rights of current user",
""), ex);
}
}
}

View File

@@ -16,6 +16,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable;
import org.apache.commons.collections4.MapUtils; import org.apache.commons.collections4.MapUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
@@ -326,15 +328,16 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini
} }
} }
public Long getLastModified(Bitstream bitstream) { @Nullable
Map wantedMetadata = new HashMap(); @Override
wantedMetadata.put("modified", null); public Long getLastModified(Bitstream bitstream) throws IOException {
try { Map attrs = new HashMap();
wantedMetadata = stores.get(incoming).about(bitstream, wantedMetadata); attrs.put("modified", null);
} catch (IOException e) { attrs = stores.get(bitstream.getStoreNumber()).about(bitstream, attrs);
log.error(e); if (attrs == null || !attrs.containsKey("modified")) {
return null;
} }
return Long.valueOf(wantedMetadata.get("modified").toString()); return Long.valueOf(attrs.get("modified").toString());
} }
/** /**

View File

@@ -12,6 +12,7 @@ import java.io.InputStream;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import javax.annotation.Nullable;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
@@ -181,11 +182,13 @@ public interface BitstreamStorageService {
/** /**
* Get the last modified timestamp of the file linked to the given bitstream * Gets the last modified timestamp of the the given bitstream's content, if known.
* *
* @param bitstream The bitstream for which to get the last modified timestamp * @param bitstream the bitstream.
* @return The last modified timestamp in milliseconds * @return the timestamp in milliseconds, or {@code null} if unknown.
* @throws IOException if an unexpected io error occurs.
*/ */
public Long getLastModified(Bitstream bitstream); @Nullable
Long getLastModified(Bitstream bitstream) throws IOException;
} }

View File

@@ -15,7 +15,7 @@
<properties> <properties>
<!-- This is the path to the root [dspace-src] directory. --> <!-- This is the path to the root [dspace-src] directory. -->
<root.basedir>${basedir}/..</root.basedir> <root.basedir>${basedir}/..</root.basedir>
<xoai.version>3.2.10</xoai.version> <xoai.version>3.2.11</xoai.version>
<jtwig.version>5.87.0.RELEASE</jtwig.version> <jtwig.version>5.87.0.RELEASE</jtwig.version>
</properties> </properties>

View File

@@ -448,6 +448,12 @@ public class XOAI {
doc.addField("metadata.dc.format.mimetype", f); doc.addField("metadata.dc.format.mimetype", f);
} }
// Message output before processing - for debugging purposes
if (verbose) {
println(String.format("Item %s with handle %s is about to be indexed",
item.getID().toString(), handle));
}
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
XmlOutputContext xmlContext = XmlOutputContext.emptyContext(out, Second); XmlOutputContext xmlContext = XmlOutputContext.emptyContext(out, Second);
retrieveMetadata(context, item).write(xmlContext); retrieveMetadata(context, item).write(xmlContext);

View File

@@ -30,6 +30,7 @@ import org.dspace.content.authority.Choices;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.core.ConfigurationManager; import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -49,13 +50,17 @@ public class ItemUtils {
private static final ItemService itemService private static final ItemService itemService
= ContentServiceFactory.getInstance().getItemService(); = ContentServiceFactory.getInstance().getItemService();
private static final RelationshipService relationshipService
= ContentServiceFactory.getInstance().getRelationshipService();
private static final BitstreamService bitstreamService private static final BitstreamService bitstreamService
= ContentServiceFactory.getInstance().getBitstreamService(); = ContentServiceFactory.getInstance().getBitstreamService();
/** /**
* Default constructor * Default constructor
*/ */
private ItemUtils() { } private ItemUtils() {
}
private static Element getElement(List<Element> list, String name) { private static Element getElement(List<Element> list, String name) {
for (Element e : list) { for (Element e : list) {
@@ -73,47 +78,116 @@ public class ItemUtils {
return e; return e;
} }
private static Element.Field createValue( private static Element.Field createValue(String name, String value) {
String name, String value) {
Element.Field e = new Element.Field(); Element.Field e = new Element.Field();
e.setValue(value); e.setValue(value);
e.setName(name); e.setName(name);
return e; return e;
} }
public static Metadata retrieveMetadata(Context context, Item item) { private static Element createBundlesElement(Context context, Item item) throws SQLException {
Metadata metadata; Element bundles = create("bundles");
// read all metadata into Metadata Object List<Bundle> bs;
metadata = new Metadata();
List<MetadataValue> vals = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); bs = item.getBundles();
for (MetadataValue val : vals) { for (Bundle b : bs) {
Element bundle = create("bundle");
bundles.getElement().add(bundle);
bundle.getField().add(createValue("name", b.getName()));
Element bitstreams = create("bitstreams");
bundle.getElement().add(bitstreams);
List<Bitstream> bits = b.getBitstreams();
for (Bitstream bit : bits) {
Element bitstream = create("bitstream");
bitstreams.getElement().add(bitstream);
String url = "";
String bsName = bit.getName();
String sid = String.valueOf(bit.getSequenceID());
String baseUrl = ConfigurationManager.getProperty("oai", "bitstream.baseUrl");
String handle = null;
// get handle of parent Item of this bitstream, if there
// is one:
List<Bundle> bn = bit.getBundles();
if (!bn.isEmpty()) {
List<Item> bi = bn.get(0).getItems();
if (!bi.isEmpty()) {
handle = bi.get(0).getHandle();
}
}
if (bsName == null) {
List<String> ext = bit.getFormat(context).getExtensions();
bsName = "bitstream_" + sid + (ext.isEmpty() ? "" : ext.get(0));
}
if (handle != null && baseUrl != null) {
url = baseUrl + "/bitstream/" + handle + "/" + sid + "/" + URLUtils.encode(bsName);
} else {
url = URLUtils.encode(bsName);
}
String cks = bit.getChecksum();
String cka = bit.getChecksumAlgorithm();
String oname = bit.getSource();
String name = bit.getName();
String description = bit.getDescription();
if (name != null) {
bitstream.getField().add(createValue("name", name));
}
if (oname != null) {
bitstream.getField().add(createValue("originalName", name));
}
if (description != null) {
bitstream.getField().add(createValue("description", description));
}
bitstream.getField().add(createValue("format", bit.getFormat(context).getMIMEType()));
bitstream.getField().add(createValue("size", "" + bit.getSizeBytes()));
bitstream.getField().add(createValue("url", url));
bitstream.getField().add(createValue("checksum", cks));
bitstream.getField().add(createValue("checksumAlgorithm", cka));
bitstream.getField().add(createValue("sid", bit.getSequenceID() + ""));
}
}
return bundles;
}
private static Element createLicenseElement(Context context, Item item)
throws SQLException, AuthorizeException, IOException {
Element license = create("license");
List<Bundle> licBundles;
licBundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME);
if (!licBundles.isEmpty()) {
Bundle licBundle = licBundles.get(0);
List<Bitstream> licBits = licBundle.getBitstreams();
if (!licBits.isEmpty()) {
Bitstream licBit = licBits.get(0);
InputStream in;
in = bitstreamService.retrieve(context, licBit);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Utils.bufferedCopy(in, out);
license.getField().add(createValue("bin", Base64Utils.encode(out.toString())));
}
}
return license;
}
/**
* This method will add all sub-elements to a top element, like: dc, or dcterms, ... *
* @param schema Element argument passed by reference that will be changed
* @param val Metadatavalue that will be processed
* @throws SQLException
*/
private static void fillSchemaElement(Element schema, MetadataValue val) throws SQLException {
MetadataField field = val.getMetadataField(); MetadataField field = val.getMetadataField();
Element valueElem = schema;
// Don't expose fields that are hidden by configuration
try {
if (metadataExposureService.isHidden(context,
field.getMetadataSchema().getName(),
field.getElement(),
field.getQualifier())) {
continue;
}
} catch (SQLException se) {
throw new RuntimeException(se);
}
Element valueElem = null;
Element schema = getElement(metadata.getElement(), field.getMetadataSchema().getName());
if (schema == null) {
schema = create(field.getMetadataSchema().getName());
metadata.getElement().add(schema);
}
valueElem = schema;
// Has element.. with XOAI one could have only schema and value // Has element.. with XOAI one could have only schema and value
if (field.getElement() != null && !field.getElement().equals("")) { if (field.getElement() != null && !field.getElement().equals("")) {
Element element = getElement(schema.getElement(), Element element = getElement(schema.getElement(), field.getElement());
field.getElement());
if (element == null) { if (element == null) {
element = create(field.getElement()); element = create(field.getElement());
schema.getElement().add(element); schema.getElement().add(element);
@@ -122,8 +196,7 @@ public class ItemUtils {
// Qualified element? // Qualified element?
if (field.getQualifier() != null && !field.getQualifier().equals("")) { if (field.getQualifier() != null && !field.getQualifier().equals("")) {
Element qualifier = getElement(element.getElement(), Element qualifier = getElement(element.getElement(), field.getQualifier());
field.getQualifier());
if (qualifier == null) { if (qualifier == null) {
qualifier = create(field.getQualifier()); qualifier = create(field.getQualifier());
element.getElement().add(qualifier); element.getElement().add(qualifier);
@@ -134,16 +207,14 @@ public class ItemUtils {
// Language? // Language?
if (val.getLanguage() != null && !val.getLanguage().equals("")) { if (val.getLanguage() != null && !val.getLanguage().equals("")) {
Element language = getElement(valueElem.getElement(), Element language = getElement(valueElem.getElement(), val.getLanguage());
val.getLanguage());
if (language == null) { if (language == null) {
language = create(val.getLanguage()); language = create(val.getLanguage());
valueElem.getElement().add(language); valueElem.getElement().add(language);
} }
valueElem = language; valueElem = language;
} else { } else {
Element language = getElement(valueElem.getElement(), Element language = getElement(valueElem.getElement(), "none");
"none");
if (language == null) { if (language == null) {
language = create("none"); language = create("none");
valueElem.getElement().add(language); valueElem.getElement().add(language);
@@ -159,144 +230,73 @@ public class ItemUtils {
} }
} }
} }
/**
* Utility method to retrieve a structured XML in XOAI format
* @param context
* @param item
* @return Structured XML Metadata in XOAI format
*/
public static Metadata retrieveMetadata(Context context, Item item) {
Metadata metadata;
// read all metadata into Metadata Object
metadata = new Metadata();
List<MetadataValue> vals = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
for (MetadataValue val : vals) {
MetadataField field = val.getMetadataField();
try {
// Don't expose fields that are hidden by configuration
if (metadataExposureService.isHidden(context, field.getMetadataSchema().getName(), field.getElement(),
field.getQualifier())) {
continue;
}
Element schema = getElement(metadata.getElement(), field.getMetadataSchema().getName());
if (schema == null) {
schema = create(field.getMetadataSchema().getName());
metadata.getElement().add(schema);
}
fillSchemaElement(schema, val);
} catch (SQLException se) {
throw new RuntimeException(se);
}
}
// Done! Metadata has been read! // Done! Metadata has been read!
// Now adding bitstream info // Now adding bitstream info
Element bundles = create("bundles");
metadata.getElement().add(bundles);
List<Bundle> bs;
try { try {
bs = item.getBundles(); Element bundles = createBundlesElement(context, item);
for (Bundle b : bs) { metadata.getElement().add(bundles);
Element bundle = create("bundle"); } catch (SQLException e) {
bundles.getElement().add(bundle); log.warn(e.getMessage(), e);
bundle.getField()
.add(createValue("name", b.getName()));
Element bitstreams = create("bitstreams");
bundle.getElement().add(bitstreams);
List<Bitstream> bits = b.getBitstreams();
for (Bitstream bit : bits) {
Element bitstream = create("bitstream");
bitstreams.getElement().add(bitstream);
String url = "";
String bsName = bit.getName();
String sid = String.valueOf(bit.getSequenceID());
String baseUrl = ConfigurationManager.getProperty("oai",
"bitstream.baseUrl");
String handle = null;
// get handle of parent Item of this bitstream, if there
// is one:
List<Bundle> bn = bit.getBundles();
if (!bn.isEmpty()) {
List<Item> bi = bn.get(0).getItems();
if (!bi.isEmpty()) {
handle = bi.get(0).getHandle();
} }
}
if (bsName == null) {
List<String> ext = bit.getFormat(context).getExtensions();
bsName = "bitstream_" + sid
+ (ext.isEmpty() ? "" : ext.get(0));
}
if (handle != null && baseUrl != null) {
url = baseUrl + "/bitstream/"
+ handle + "/"
+ sid + "/"
+ URLUtils.encode(bsName);
} else {
url = URLUtils.encode(bsName);
}
String cks = bit.getChecksum();
String cka = bit.getChecksumAlgorithm();
String oname = bit.getSource();
String name = bit.getName();
String description = bit.getDescription();
if (name != null) {
bitstream.getField().add(
createValue("name", name));
}
if (oname != null) {
bitstream.getField().add(
createValue("originalName", name));
}
if (description != null) {
bitstream.getField().add(
createValue("description", description));
}
bitstream.getField().add(
createValue("format", bit.getFormat(context)
.getMIMEType()));
bitstream.getField().add(
createValue("size", "" + bit.getSizeBytes()));
bitstream.getField().add(createValue("url", url));
bitstream.getField().add(
createValue("checksum", cks));
bitstream.getField().add(
createValue("checksumAlgorithm", cka));
bitstream.getField().add(
createValue("sid", bit.getSequenceID()
+ ""));
}
}
} catch (SQLException e1) {
e1.printStackTrace();
}
// Other info // Other info
Element other = create("others"); Element other = create("others");
other.getField().add( other.getField().add(createValue("handle", item.getHandle()));
createValue("handle", item.getHandle())); other.getField().add(createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle())));
other.getField().add( other.getField().add(createValue("lastModifyDate", item.getLastModified().toString()));
createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle())));
other.getField().add(
createValue("lastModifyDate", item
.getLastModified().toString()));
metadata.getElement().add(other); metadata.getElement().add(other);
// Repository Info // Repository Info
Element repository = create("repository"); Element repository = create("repository");
repository.getField().add( repository.getField().add(createValue("url", ConfigurationManager.getProperty("dspace.baseUrl")));
createValue("name", repository.getField().add(createValue("name", ConfigurationManager.getProperty("dspace.name")));
ConfigurationManager.getProperty("dspace.name"))); repository.getField().add(createValue("mail", ConfigurationManager.getProperty("mail.admin")));
repository.getField().add(
createValue("mail",
ConfigurationManager.getProperty("mail.admin")));
metadata.getElement().add(repository); metadata.getElement().add(repository);
// Licensing info // Licensing info
Element license = create("license");
List<Bundle> licBundles;
try { try {
licBundles = itemService.getBundles(item, Constants.LICENSE_BUNDLE_NAME); Element license = createLicenseElement(context, item);
if (!licBundles.isEmpty()) {
Bundle licBundle = licBundles.get(0);
List<Bitstream> licBits = licBundle.getBitstreams();
if (!licBits.isEmpty()) {
Bitstream licBit = licBits.get(0);
InputStream in;
try {
in = bitstreamService.retrieve(context, licBit);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Utils.bufferedCopy(in, out);
license.getField().add(
createValue("bin",
Base64Utils.encode(out.toString())));
metadata.getElement().add(license); metadata.getElement().add(license);
} catch (AuthorizeException | IOException | SQLException e) { } catch (AuthorizeException | IOException | SQLException e) {
log.warn(e.getMessage(), e); log.warn(e.getMessage(), e);
} }
}
}
} catch (SQLException e1) {
log.warn(e1.getMessage(), e1);
}
return metadata; return metadata;
} }
} }

View File

@@ -127,10 +127,13 @@ public class BitstreamRestController {
.withLength(bitstreamTuple.getRight()) .withLength(bitstreamTuple.getRight())
.withChecksum(bit.getChecksum()) .withChecksum(bit.getChecksum())
.withMimetype(mimetype) .withMimetype(mimetype)
.withLastModified(lastModified)
.with(request) .with(request)
.with(response); .with(response);
if (lastModified != null) {
sender.withLastModified(lastModified);
}
//Determine if we need to send the file as a download or if the browser can open it inline //Determine if we need to send the file as a download or if the browser can open it inline
long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold"); long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold");
if (dispositionThreshold >= 0 && bitstreamTuple.getRight() > dispositionThreshold) { if (dispositionThreshold >= 0 && bitstreamTuple.getRight() > dispositionThreshold) {

View File

@@ -3582,4 +3582,139 @@ public class DiscoveryRestControllerIT extends AbstractControllerIntegrationTest
} }
@Test
public void discoverSearchObjectsTestForWithdrawnOrPrivateItemsNonAdmin() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
//1. A community-collection structure with one parent community with sub-community and two collections.
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build();
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build();
//2. One public item, one private, one withdrawn.
Item publicItem1 = ItemBuilder.createItem(context, col1)
.withTitle("Test")
.withIssueDate("2010-10-17")
.withAuthor("Smith, Donald")
.withSubject("ExtraEntry")
.build();
Item publicItem2 = ItemBuilder.createItem(context, col2)
.withTitle("WithdrawnTest 2")
.withIssueDate("1990-02-13")
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
.withSubject("ExtraEntry")
.withdrawn()
.build();
Item publicItem3 = ItemBuilder.createItem(context, col2)
.withTitle("Private Test item 2")
.withIssueDate("2010-02-13")
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
.withSubject("AnotherTest").withSubject("ExtraEntry")
.makeUnDiscoverable()
.build();
String query = "Test";
//** WHEN **
//A non-admin user browses this endpoint to find the withdrawn or private objects in the system
//With a query stating 'Test'
getClient().perform(get("/api/discover/search/objects")
.param("configuration", "undiscoverable")
.param("query", query))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//The page object needs to look like this
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntry(0, 20)
)))
//The search results should be an empty list.
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects", Matchers.empty()))
//There always needs to be a self link available
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")))
;
}
@Test
public void discoverSearchObjectsTestForWithdrawnOrPrivateItemsByAdminUser() throws Exception {
//We turn off the authorization system in order to create the structure as defined below
context.turnOffAuthorisationSystem();
//** GIVEN **
//1. A community-collection structure with one parent community with sub-community and two collections.
parentCommunity = CommunityBuilder.createCommunity(context)
.withName("Parent Community")
.build();
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build();
Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build();
//2. One public item, one private, one withdrawn.
Item publicItem1 = ItemBuilder.createItem(context, col1)
.withTitle("Test")
.withIssueDate("2010-10-17")
.withAuthor("Smith, Donald")
.withSubject("ExtraEntry")
.build();
Item publicItem2 = ItemBuilder.createItem(context, col2)
.withTitle("Withdrawn Test 2")
.withIssueDate("1990-02-13")
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
.withSubject("ExtraEntry")
.withdrawn()
.build();
Item publicItem3 = ItemBuilder.createItem(context, col2)
.withTitle("Private Test item 2")
.withIssueDate("2010-02-13")
.withAuthor("Smith, Maria").withAuthor("Doe, Jane")
.withSubject("AnotherTest").withSubject("ExtraEntry")
.makeUnDiscoverable()
.build();
context.restoreAuthSystemState();
String query = "Test";
String adminToken = getAuthToken(admin.getEmail(), password);
//** WHEN **
// A system admin user browses this endpoint to find the withdrawn or private objects in the system
// With a query stating 'Test'
getClient(adminToken).perform(get("/api/discover/search/objects")
.param("configuration", "undiscoverable")
.param("query", query))
//** THEN **
//The status has to be 200 OK
.andExpect(status().isOk())
//The type has to be 'discover'
.andExpect(jsonPath("$.type", is("discover")))
//The page object needs to look like this
.andExpect(jsonPath("$._embedded.searchResult.page", is(
PageMatcher.pageEntry(0, 20)
)))
//The search results should be an empty list.
.andExpect(jsonPath("$._embedded.searchResult._embedded.objects",
Matchers.containsInAnyOrder(
SearchResultMatcher.matchOnItemName("item", "items", "Private Test item 2"),
SearchResultMatcher.matchOnItemName("item", "items", "Withdrawn Test 2")
)))
//There always needs to be a self link available
.andExpect(jsonPath("$._links.self.href", containsString("/api/discover/search/objects")))
;
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,394 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Following OpenAIRE Guidelines 4 -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:doc="http://www.lyncode.com/xoai">
<xsl:output indent="yes" method="xml" omit-xml-declaration="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!--
Formatting dc.date.issued
based on what OpenAIRE4 specifies for issued dates
https://openaire-guidelines-for-literature-repository-managers.readthedocs.io/en/v4.0.0/field_publicationdate.html
-->
<xsl:template
match="/doc:metadata/doc:element[@name='dc']/doc:element[@name='date']/doc:element[@name='issued']/doc:element/doc:field/text()">
<xsl:call-template name="formatdate">
<xsl:with-param name="datestr" select="."/>
</xsl:call-template>
</xsl:template>
<!--
Modifying and normalizing dc.language
to ISO 639-3 (from ISO 639-1) for each language available at the submission form
-->
<xsl:template
match="/doc:metadata/doc:element[@name='dc']/doc:element[@name='language']/doc:element[@name='iso']/doc:element/doc:field/text()">
<xsl:variable name="lc_value">
<xsl:call-template name="lowercase">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$lc_value = 'en_US'">
<xsl:text>eng</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'en'">
<xsl:text>eng</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'es'">
<xsl:text>spa</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'de'">
<xsl:text>deu</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'fr'">
<xsl:text>fra</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'it'">
<xsl:text>ita</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'ja'">
<xsl:text>jap</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'zh'">
<xsl:text>zho</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'pt'">
<xsl:text>por</xsl:text>
</xsl:when>
<xsl:when test="$lc_value = 'tr'">
<xsl:text>tur</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Modifying dc.rights -->
<!-- Removing unwanted -->
<xsl:template
match="/doc:metadata/doc:element[@name='dc']/doc:element[@name='rights']/doc:element/doc:element"/>
<!--
Normalizing dc.rights according to COAR Controlled Vocabulary for
Access Rights (Version 1.0) (http://vocabularies.coar-repositories.org/documentation/access_rights/)
available at
https://openaire-guidelines-for-literature-repository-managers.readthedocs.io/en/v4.0.0/field_accessrights.html#definition-and-usage-instruction
-->
<xsl:template
match="/doc:metadata/doc:element[@name='dc']/doc:element[@name='rights']/doc:element/doc:field/text()">
<xsl:variable name="value" select="."/>
<xsl:variable name="lc_value">
<xsl:call-template name="lowercase">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when
test="$lc_value = 'open access' or $lc_value = 'openaccess' or $value = 'http://purl.org/coar/access_right/c_abf2'">
<xsl:text>open access</xsl:text>
</xsl:when>
<xsl:when
test="$lc_value = 'embargoed access' or $lc_value = 'embargoedaccess' or $value = 'http://purl.org/coar/access_right/c_f1cf'">
<xsl:text>embargoed access</xsl:text>
</xsl:when>
<xsl:when
test="$lc_value = 'restricted access' or $lc_value = 'restrictedaccess' or $value = 'http://purl.org/coar/access_right/c_16ec'">
<xsl:text>restricted access</xsl:text>
</xsl:when>
<xsl:when
test="$lc_value = 'metadata only access' or $lc_value = 'closedaccess' or $value = 'http://purl.org/coar/access_right/c_14cb'">
<xsl:text>metadata only access</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Modifying and normalizing dc.type according to COAR Controlled Vocabulary for Resource Type
Genres (Version 2.0) (http://vocabularies.coar-repositories.org/documentation/resource_types/)
available at
https://openaire-guidelines-for-literature-repository-managers.readthedocs.io/en/v4.0.0/field_publicationtype.html#attribute-uri-m
-->
<xsl:template
match="/doc:metadata/doc:element[@name='dc']/doc:element[@name='type']/doc:element/doc:field/text()">
<xsl:variable name="dc_type" select="."/>
<xsl:variable name="lc_dc_type">
<xsl:call-template name="lowercase">
<xsl:with-param name="value" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when
test="$lc_dc_type = 'annotation' or $dc_type = 'http://purl.org/coar/resource_type/c_1162'">
<xsl:text>annotation</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'journal'">
<xsl:text>journal</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'journal article' or $lc_dc_type = 'article' or $lc_dc_type = 'journalarticle' or $dc_type = 'http://purl.org/coar/resource_type/c_6501'">
<xsl:text>journal article</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'editorial' or $dc_type = 'http://purl.org/coar/resource_type/c_b239'">
<xsl:text>editorial</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'bachelor thesis' or $lc_dc_type = 'bachelorthesis' or $dc_type = 'http://purl.org/coar/resource_type/c_7a1f'">
<xsl:text>bachelor thesis</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'bibliography' or $dc_type = 'http://purl.org/coar/resource_type/c_86bc'">
<xsl:text>bibliography</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'book' or $dc_type = 'http://purl.org/coar/resource_type/c_2f33'">
<xsl:text>book</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'book part' or $lc_dc_type = 'bookpart' or $dc_type = 'http://purl.org/coar/resource_type/c_3248'">
<xsl:text>book part</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'book review' or $lc_dc_type = 'bookreview' or $dc_type = 'http://purl.org/coar/resource_type/c_ba08'">
<xsl:text>book review</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'website' or $dc_type = 'http://purl.org/coar/resource_type/c_7ad9'">
<xsl:text>website</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'interactive resource' or $lc_dc_type = 'interactiveresource' or $dc_type = 'http://purl.org/coar/resource_type/c_e9a0'">
<xsl:text>interactive resource</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference proceedings' or $lc_dc_type = 'conferenceproceedings' or $dc_type = 'http://purl.org/coar/resource_type/c_f744'">
<xsl:text>conference proceedings</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference object' or $lc_dc_type = 'conferenceobject' or $dc_type = 'http://purl.org/coar/resource_type/c_c94f'">
<xsl:text>conference object</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference paper' or $lc_dc_type = 'conferencepaper' or $dc_type = 'http://purl.org/coar/resource_type/c_5794'">
<xsl:text>conference paper</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference poster' or $lc_dc_type = 'conferenceposter' or $dc_type = 'http://purl.org/coar/resource_type/c_6670'">
<xsl:text>conference poster</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'contribution to journal' or $lc_dc_type = 'contributiontojournal' or $dc_type = 'http://purl.org/coar/resource_type/c_3e5a'">
<xsl:text>contribution to journal</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'datapaper' or $dc_type = 'http://purl.org/coar/resource_type/c_beb9'">
<xsl:text>data paper</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'dataset' or $dc_type = 'http://purl.org/coar/resource_type/c_ddb1'">
<xsl:text>dataset</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'doctoral thesis' or $lc_dc_type = 'doctoralthesis' or $dc_type = 'http://purl.org/coar/resource_type/c_db06'">
<xsl:text>doctoral thesis</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'image' or $dc_type = 'http://purl.org/coar/resource_type/c_c513'">
<xsl:text>image</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'lecture' or $dc_type = 'http://purl.org/coar/resource_type/c_8544'">
<xsl:text>lecture</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'letter' or $dc_type = 'http://purl.org/coar/resource_type/c_0857'">
<xsl:text>letter</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'master thesis' or $lc_dc_type = 'masterthesis' or $dc_type = 'http://purl.org/coar/resource_type/c_bdcc'">
<xsl:text>master thesis</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'moving image' or $lc_dc_type = 'movingimage' or $dc_type = 'http://purl.org/coar/resource_type/c_8a7e'">
<xsl:text>moving image</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'periodical' or $dc_type = 'http://purl.org/coar/resource_type/c_2659'">
<xsl:text>periodical</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'letter to the editor' or $lc_dc_type = 'lettertotheeditor' or $dc_type = 'http://purl.org/coar/resource_type/c_545b'">
<xsl:text>letter to the editor</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'patent' or $dc_type = 'http://purl.org/coar/resource_type/c_15cd'">
<xsl:text>patent</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'preprint' or $dc_type = 'http://purl.org/coar/resource_type/c_816b'">
<xsl:text>preprint</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'report' or $dc_type = 'http://purl.org/coar/resource_type/c_93fc'">
<xsl:text>report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'report part' or $lc_dc_type = 'reportpart' or $dc_type = 'http://purl.org/coar/resource_type/c_ba1f'">
<xsl:text>report part</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'research proposal' or $lc_dc_type = 'researchproposal' or $dc_type = 'http://purl.org/coar/resource_type/c_baaf'">
<xsl:text>research proposal</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'review' or $dc_type = 'http://purl.org/coar/resource_type/c_efa0'">
<xsl:text>review</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'software' or $dc_type = 'http://purl.org/coar/resource_type/c_5ce6'">
<xsl:text>software</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'still image' or $lc_dc_type = 'stillimage' or $dc_type = 'http://purl.org/coar/resource_type/c_ecc8'">
<xsl:text>still image</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'technical documentation' or $lc_dc_type = 'technicaldocumentation' or $dc_type = 'http://purl.org/coar/resource_type/c_71bd'">
<xsl:text>technical documentation</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'workflow' or $dc_type = 'http://purl.org/coar/resource_type/c_393c'">
<xsl:text>workflow</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'working paper' or $lc_dc_type = 'workingpaper' or $dc_type = 'http://purl.org/coar/resource_type/c_8042'">
<xsl:text>working paper</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'thesis' or $dc_type = 'http://purl.org/coar/resource_type/c_46ec'">
<xsl:text>thesis</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'cartographic material' or $lc_dc_type = 'cartographicmaterial' or $dc_type = 'http://purl.org/coar/resource_type/c_12cc'">
<xsl:text>cartographic material</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'map' or $dc_type = 'http://purl.org/coar/resource_type/c_12cd'">
<xsl:text>map</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'video' or $dc_type = 'http://purl.org/coar/resource_type/c_12ce'">
<xsl:text>video</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'sound' or $dc_type = 'http://purl.org/coar/resource_type/c_18cc'">
<xsl:text>sound</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'musical composition' or $lc_dc_type = 'musicalcomposition' or $dc_type = 'http://purl.org/coar/resource_type/c_18cd'">
<xsl:text>musical composition</xsl:text>
</xsl:when>
<xsl:when test="$lc_dc_type = 'text' or $dc_type = 'http://purl.org/coar/resource_type/c_18cf'">
<xsl:text>text</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference paper not in proceedings' or $lc_dc_type = 'conferencepapernotinproceedings' or $dc_type = 'http://purl.org/coar/resource_type/c_18cp'">
<xsl:text>conference paper not in proceedings</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'conference poster not in proceedings' or $lc_dc_type = 'conferenceposternotinproceedings' or $dc_type = 'http://purl.org/coar/resource_type/c_18co'">
<xsl:text>conference poster not in proceedings</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'musical notation' or $dc_type = 'http://purl.org/coar/resource_type/c_18cw'">
<xsl:text>musical notation</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'internal report' or $lc_dc_type = 'internalreport' or $dc_type = 'http://purl.org/coar/resource_type/c_18ww'">
<xsl:text>internal report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'memorandum' or $dc_type = 'http://purl.org/coar/resource_type/c_18wz'">
<xsl:text>memorandum</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'other type of report' or $lc_dc_type = 'othertypeofreport' or $dc_type = 'http://purl.org/coar/resource_type/c_18wq'">
<xsl:text>other type of report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'policy report' or $lc_dc_type = 'policyreport' or $dc_type = 'http://purl.org/coar/resource_type/c_186u'">
<xsl:text>policy report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'project deliverable' or $lc_dc_type = 'projectdeliverable' or $dc_type = 'http://purl.org/coar/resource_type/c_18op'">
<xsl:text>project deliverable</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'report to funding agency' or $lc_dc_type = 'reporttofundingagency' or $dc_type = 'http://purl.org/coar/resource_type/c_18hj'">
<xsl:text>report to funding agency</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'research report' or $lc_dc_type = 'researchreport' or $dc_type = 'http://purl.org/coar/resource_type/c_18ws'">
<xsl:text>research report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'technical report' or $lc_dc_type = 'technicalreport' or $dc_type = 'http://purl.org/coar/resource_type/c_18gh'">
<xsl:text>technical report</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'review article' or $lc_dc_type = 'reviewarticle' or $dc_type = 'http://purl.org/coar/resource_type/c_dcae04bc'">
<xsl:text>review article</xsl:text>
</xsl:when>
<xsl:when
test="$lc_dc_type = 'research article' or $lc_dc_type = 'researcharticle' or $dc_type = 'http://purl.org/coar/resource_type/c_2df8fbb1'">
<xsl:text>research article</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>other</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- AUXILIARY TEMPLATES -->
<!--
Date format
This template is discarding the " 16:53:24.556" part from a date and time
like "2019-04-30 16:53:24.556" to support the YYYY-MM-DD format of
ISO 8601 [W3CDTF]
-->
<xsl:template name="formatdate">
<xsl:param name="datestr"/>
<xsl:variable name="sub">
<xsl:value-of select="substring($datestr,1,10)"/>
</xsl:variable>
<xsl:value-of select="$sub"/>
</xsl:template>
<!-- -->
<!-- Other Auxiliary templates -->
<!-- -->
<xsl:param name="smallcase" select="'abcdefghijklmnopqrstuvwxyzàèìòùáéíóúýâêîôûãñõäëïöüÿåæœçðø'"/>
<xsl:param name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÈÌÒÙÁÉÍÓÚÝÂÊÎÔÛÃÑÕÄËÏÖÜŸÅÆŒÇÐØ'"/>
<!-- to retrieve a string in uppercase -->
<xsl:template name="uppercase">
<xsl:param name="value"/>
<xsl:value-of select="translate($value, $smallcase, $uppercase)"/>
</xsl:template>
<!-- to retrieve a string in lowercase -->
<xsl:template name="lowercase">
<xsl:param name="value"/>
<xsl:value-of select="translate($value, $uppercase, $smallcase)"/>
</xsl:template>
<!-- to retrieve a string which the first letter is in uppercase -->
<xsl:template name="ucfirst">
<xsl:param name="value"/>
<xsl:call-template name="uppercase">
<xsl:with-param name="value" select="substring($value, 1, 1)"/>
</xsl:call-template>
<xsl:call-template name="lowercase">
<xsl:with-param name="value" select="substring($value, 2)"/>
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Configuration indented="false" maxListIdentifiersSize="100" maxListRecordsSize="100" <Configuration indented="false" maxListIdentifiersSize="100" maxListRecordsSize="100"
maxListSetsSize="100" stylesheet="static/style.xsl" maxListSetsSize="100" stylesheet="static/style.xsl" xmlns="http://www.lyncode.com/XOAIConfiguration">
xmlns="http://www.lyncode.com/XOAIConfiguration">
<Contexts> <Contexts>
<Context baseurl="request" name="Default Context"> <Context baseurl="request" name="Default Context">
@@ -70,6 +69,28 @@
This contexts complies with OpenAIRE Guidelines for Literature Repositories v3.0. This contexts complies with OpenAIRE Guidelines for Literature Repositories v3.0.
</Description> </Description>
</Context> </Context>
<!--
OpenAIRE Guidelines 4.0:
- https://openaire-guidelines-for-literature-repository-managers.readthedocs.io/en/v4.0.0/
There is a limitation over the embargoedEndDate parameter:
- Predefined DSpace fields don't allow to set this up with a default.
-->
<Context baseurl="openaire4" name="OpenAIRE 4 Context">
<!-- Date format, field prefixes, etc are ensured by the transformer -->
<Transformer ref="openaire4Transformer"/>
<!-- OpenAIRE filter -->
<Filter ref="openAIRE4Filter"/>
<!-- Metadata Formats -->
<Format ref="oaiopenaire"/>
<Description>
This contexts complies with OpenAIRE Guidelines for Literature Repositories v4.0.
</Description>
</Context>
</Contexts> </Contexts>
@@ -155,6 +176,15 @@
<Namespace>http://irdb.nii.ac.jp/oai</Namespace> <Namespace>http://irdb.nii.ac.jp/oai</Namespace>
<SchemaLocation>http://irdb.nii.ac.jp/oai/junii2-3-1.xsd</SchemaLocation> <SchemaLocation>http://irdb.nii.ac.jp/oai/junii2-3-1.xsd</SchemaLocation>
</Format> </Format>
<!-- Metadata format based on the OpenAIRE 4.0 guidelines
https://openaire-guidelines-for-literature-repository-managers.readthedocs.io/en/v4.0.0/use_of_oai_pmh.html
-->
<Format id="oaiopenaire">
<Prefix>oai_openaire</Prefix>
<XSLT>metadataFormats/oai_openaire.xsl</XSLT>
<Namespace>http://namespace.openaire.eu/schema/oaire/</Namespace>
<SchemaLocation>https://www.openaire.eu/schema/repo-lit/4.0/openaire.xsd</SchemaLocation>
</Format>
</Formats> </Formats>
<Transformers> <Transformers>
@@ -164,6 +194,9 @@
<Transformer id="openaireTransformer"> <Transformer id="openaireTransformer">
<XSLT>transformers/openaire.xsl</XSLT> <XSLT>transformers/openaire.xsl</XSLT>
</Transformer> </Transformer>
<Transformer id="openaire4Transformer">
<XSLT>transformers/openaire4.xsl</XSLT>
</Transformer>
</Transformers> </Transformers>
@@ -286,14 +319,19 @@
</Definition> </Definition>
</Filter> </Filter>
<!-- Default filter for records returned by OAI-PMH. <!-- OpenAIRE4 filter for records returned by OAI-PMH.
By default, return an Item record: By default, return an Item record:
* If it is publicly accessible * If it is publicly accessible
* OR it has been withdrawn (in order to display a tombstone record). * * OR it has been withdrawn (in order to display a tombstone record).
* AND doesn't have a relationship.type field
* * OR the relationship.type is a Publication
* limiting the results only to Publications as expected
This filter is used by the default context ([oai]/request). This filter is used by the default context ([oai]/request).
--> -->
<Filter id="defaultFilter"> <Filter id="openAIRE4Filter">
<Definition> <Definition>
<And>
<LeftCondition>
<Or> <Or>
<LeftCondition> <LeftCondition>
<Custom ref="itemAccessCondition"/> <Custom ref="itemAccessCondition"/>
@@ -302,6 +340,62 @@
<Custom ref="itemWithdrawnCondition"/> <Custom ref="itemWithdrawnCondition"/>
</RightCondition> </RightCondition>
</Or> </Or>
</LeftCondition>
<RightCondition>
<Or>
<LeftCondition>
<Not>
<Condition>
<Custom ref="relationshipTypeExistsCondition"/>
</Condition>
</Not>
</LeftCondition>
<RightCondition>
<Custom ref="isPublicationEntityCondition"/>
</RightCondition>
</Or>
</RightCondition>
</And>
</Definition>
</Filter>
<!-- Default filter for records returned by OAI-PMH.
By default, return an Item record:
* If it is publicly accessible
* * OR it has been withdrawn (in order to display a tombstone record).
* AND doesn't have a relationship.type field
* * OR the relationship.type is a Publication
* limiting the results only to Publications as expected
This filter is used by the default context ([oai]/request).
-->
<Filter id="defaultFilter">
<Definition>
<And>
<LeftCondition>
<Or>
<LeftCondition>
<Custom ref="itemAccessCondition"/>
</LeftCondition>
<RightCondition>
<Custom ref="itemWithdrawnCondition"/>
</RightCondition>
</Or>
</LeftCondition>
<RightCondition>
<Or>
<LeftCondition>
<Not>
<Condition>
<Custom ref="relationshipTypeExistsCondition"/>
</Condition>
</Not>
</LeftCondition>
<RightCondition>
<Custom ref="isPublicationEntityCondition"/>
</RightCondition>
</Or>
</RightCondition>
</And>
</Definition> </Definition>
</Filter> </Filter>
@@ -398,6 +492,30 @@
<string name="value">info:eu-repo/grantAgreement/</string> <string name="value">info:eu-repo/grantAgreement/</string>
</Configuration> </Configuration>
</CustomCondition> </CustomCondition>
<!-- This condition determines if an Item has a "relationship.type" -->
<CustomCondition id="relationshipTypeExistsCondition">
<Class>org.dspace.xoai.filter.DSpaceMetadataExistsFilter</Class>
<Configuration>
<string name="field">relationship.type</string>
</Configuration>
</CustomCondition>
<!-- This condition determines if an Item has a "relationship.type" field
specifying one of the valid DRIVER document types. -->
<CustomCondition id="isPublicationEntityCondition">
<Class>org.dspace.xoai.filter.DSpaceAtLeastOneMetadataFilter</Class>
<Configuration>
<string name="field">relationship.type</string>
<string name="operator">equal</string>
<list name="values">
<string>Publication</string>
<string>publication</string>
<!-- and other alternative names for publications types -->
</list>
</Configuration>
</CustomCondition>
</Filters> </Filters>
<Sets> <Sets>

View File

@@ -27,6 +27,7 @@
<bean id="solrServiceResourceIndexPlugin" class="org.dspace.discovery.SolrServiceResourceRestrictionPlugin" scope="prototype"/> <bean id="solrServiceResourceIndexPlugin" class="org.dspace.discovery.SolrServiceResourceRestrictionPlugin" scope="prototype"/>
<bean id="SolrServiceSpellIndexingPlugin" class="org.dspace.discovery.SolrServiceSpellIndexingPlugin" scope="prototype"/> <bean id="SolrServiceSpellIndexingPlugin" class="org.dspace.discovery.SolrServiceSpellIndexingPlugin" scope="prototype"/>
<bean id="solrServiceMetadataBrowseIndexingPlugin" class="org.dspace.discovery.SolrServiceMetadataBrowseIndexingPlugin" scope="prototype"/> <bean id="solrServiceMetadataBrowseIndexingPlugin" class="org.dspace.discovery.SolrServiceMetadataBrowseIndexingPlugin" scope="prototype"/>
<bean id="solrServicePrivateItemPlugin" class="org.dspace.discovery.SolrServicePrivateItemPlugin" scope="prototype"/>
<alias name="solrServiceResourceIndexPlugin" alias="org.dspace.discovery.SolrServiceResourceRestrictionPlugin"/> <alias name="solrServiceResourceIndexPlugin" alias="org.dspace.discovery.SolrServiceResourceRestrictionPlugin"/>
@@ -53,7 +54,7 @@
<!-- Used to show filters and results on MyDSpace --> <!-- Used to show filters and results on MyDSpace -->
<entry key="workspace" value-ref="workspaceConfiguration" /> <entry key="workspace" value-ref="workspaceConfiguration" />
<entry key="workflow" value-ref="workflowConfiguration" /> <entry key="workflow" value-ref="workflowConfiguration" />
<entry key="undiscoverable" value-ref="unDiscoverableItems" />
<entry key="publication" value-ref="publication"/> <entry key="publication" value-ref="publication"/>
<entry key="person" value-ref="person"/> <entry key="person" value-ref="person"/>
<entry key="organization" value-ref="organization"/> <entry key="organization" value-ref="organization"/>
@@ -249,6 +250,147 @@
<property name="spellCheckEnabled" value="true"/> <property name="spellCheckEnabled" value="true"/>
</bean> </bean>
<!--The configuration settings for discovery of withdrawn and indiscoverable items (admin only)-->
<bean id="unDiscoverableItems" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype">
<!--Which sidebar facets are to be displayed-->
<property name="sidebarFacets">
<list>
<ref bean="searchFilterAuthor" />
<ref bean="searchFilterSubject" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterContentInOriginalBundle"/>
<ref bean="searchFilterEntityType"/>
</list>
</property>
<!-- Set TagCloud configuration per discovery configuration -->
<property name="tagCloudFacetConfiguration" ref="defaultTagCloudFacetConfiguration"/>
<!--The search filters which can be used on the discovery search page-->
<property name="searchFilters">
<list>
<ref bean="searchFilterTitle" />
<ref bean="searchFilterAuthor" />
<ref bean="searchFilterSubject" />
<ref bean="searchFilterIssued" />
<ref bean="searchFilterContentInOriginalBundle"/>
<ref bean="searchFilterFileNameInOriginalBundle" />
<ref bean="searchFilterFileDescriptionInOriginalBundle" />
<ref bean="searchFilterEntityType"/>
<ref bean="searchFilterIsAuthorOfPublicationRelation"/>
<ref bean="searchFilterIsProjectOfPublicationRelation"/>
<ref bean="searchFilterIsOrgUnitOfPublicationRelation"/>
<ref bean="searchFilterIsPublicationOfJournalIssueRelation"/>
<ref bean="searchFilterIsJournalOfPublicationRelation"/>
</list>
</property>
<!--The sort filters for the discovery search-->
<property name="searchSortConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoverySortConfiguration">
<!--<property name="defaultSort" ref="sortDateIssued"/>-->
<!--DefaultSortOrder can either be desc or asc (desc is default)-->
<property name="defaultSortOrder" value="desc"/>
<property name="sortFields">
<list>
<ref bean="sortTitle" />
<ref bean="sortDateIssued" />
<ref bean="sortDateAccessioned"/>
</list>
</property>
</bean>
</property>
<!--Any default filter queries, these filter queries will be used for all
queries done by discovery for this configuration -->
<property name="defaultFilterQueries">
<list>
<!--Only find items-->
<value>search.resourcetype:2</value>
<!-- Only find withdrawn or undiscoverable-->
<value>withdrawn:true OR discoverable:false</value>
</list>
</property>
<!--The configuration for the recent submissions-->
<property name="recentSubmissionConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration">
<property name="metadataSortField" value="dc.date.accessioned" />
<property name="type" value="date"/>
<property name="max" value="20"/>
<!-- If enabled the collection home page will not display metadata but show a pageable list of recent submissions -->
<property name="useAsHomePage" value="false"/>
</bean>
</property>
<!--Default result per page -->
<property name="defaultRpp" value="10" />
<property name="hitHighlightingConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration">
<property name="metadataFields">
<list>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.contributor.author"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="relationship.type"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="person.identifier.jobtitle"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="project.identifier.name"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.description.abstract"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="2"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="dc.title"/>
<property name="snippets" value="5"/>
</bean>
<!-- By default, full text snippets are disabled, as snippets of embargoed/restricted bitstreams
may appear in search results when the Item is public. See DS-3498
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="project.identifier.status"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="orgunit.identifier.name"/>
<property name="snippets" value="5"/>
</bean>
<bean class="org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration">
<property name="field" value="orgunit.identifier.description"/>
<property name="maxSize" value="250"/>
<property name="snippets" value="5"/>
</bean>
-->
</list>
</property>
</bean>
</property>
<property name="moreLikeThisConfiguration">
<bean class="org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration">
<!--When altering this list also alter the "xmlui.Discovery.RelatedItems.help" key as it describes
the metadata fields below-->
<property name="similarityMetadataFields">
<list>
<value>dc.title</value>
<value>dc.contributor.author</value>
<value>dc.creator</value>
<value>dc.subject</value>
</list>
</property>
<!--The minimum number of matching terms across the metadata fields above before an item is found as related -->
<property name="minTermFrequency" value="5"/>
<!--The maximum number of related items displayed-->
<property name="max" value="3"/>
<!--The minimum word length below which words will be ignored-->
<property name="minWordLength" value="5"/>
</bean>
</property>
<!-- When true a "did you mean" example will be displayed, value can be true or false -->
<property name="spellCheckEnabled" value="true"/>
</bean>
<!--The Homepage specific configuration settings for discovery--> <!--The Homepage specific configuration settings for discovery-->
<bean id="homepageConfiguration" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype"> <bean id="homepageConfiguration" class="org.dspace.discovery.configuration.DiscoveryConfiguration" scope="prototype">

View File

@@ -0,0 +1,236 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-lazy-init="true">
<bean class="org.dspace.content.virtual.VirtualMetadataPopulator">
<property name="map">
<!-- This map contains keys and value-refs to Map objects
The keys will define which relationship type will add virtual metadata
to its relationship's item and the map will define which virtual metadata fields
are to be added to the item that has a relationship with this relationship type-->
<map>
<entry key="isAuthorOfPublication" value-ref="isAuthorOfPublicationMap"/>
<!-- relations based on OpenAIRE guidelines -->
<entry key="isContributorOfPublication" value-ref="isAuthorOfPublicationMap"/>
<entry key="isProjectOfPublication" value-ref="isProjectOfPublicationMap"/>
<entry key="isProjectOfFundingAgency" value-ref="isProjectOfFundingAgencyMap"/>
</map>
</property>
</bean>
<bean class="org.dspace.content.virtual.EntityTypeToFilterQueryService">
<property name="map">
<map>
<entry key="Publication" value="f.entityType=Publication,equals"/>
<entry key="Person" value="f.entityType=Person,equals"/>
<entry key="Journal" value="f.entityType=Journal,equals"/>
</map>
</property>
</bean>
<!-- Config like this will tell our VirtualMetadataPopulator to include the virtual metadata fields
like 'dc.contributor.author' and other specific for person.* on the appropriate item with the values
defined in the value-ref.
This value-ref should be a bean of type VirtualMetadataConfiguration -->
<util:map id="isAuthorOfPublicationMap">
<entry key="dc.contributor.author" value-ref="publicationAuthor_author"/>
<entry key="person.givenName" value-ref="publicationAuthor_givenName"/>
<entry key="person.familyName" value-ref="publicationAuthor_familyName"/>
<entry key="person.affiliation.name" value-ref="publicationAuthor_affiliation"/>
<entry key="person.identifier" value-ref="publicationAuthor_identifier"/>
<entry key="person.identifier.scopus-author-id" value-ref="publicationAuthor_identifierScopusAuthorID"/>
<entry key="person.identifier.ciencia-id" value-ref="publicationAuthor_identifierCienciaID"/>
<entry key="person.identifier.gsid" value-ref="publicationAuthor_identifierGSID"/>
<entry key="person.identifier.orcid" value-ref="publicationAuthor_identifierOrcid"/>
<entry key="person.identifier.rid" value-ref="publicationAuthor_identifierRID"/>
<entry key="person.identifier.isni" value-ref="publicationAuthor_identifierISNI"/>
<entry key="organization.legalName" value-ref="publicationAuthor_orgName"/>
<entry key="organization.identifier" value-ref="publicationAuthor_orgIdentifier"/>
</util:map>
<!--
If the related item has:
person.familyName = Smith
person.givenName = John
Then the original item will have, in this case:
dc.contributor.author = Smith, John -->
<bean class="org.dspace.content.virtual.Concatenate" id="publicationAuthor_author">
<property name="fields">
<util:list>
<value>person.familyName</value>
<value>person.givenName</value>
<value>organization.legalName</value>
</util:list>
</property>
<property name="separator">
<value>, </value>
</property>
<property name="useForPlace" value="true"/>
<property name="populateWithNameVariant" value="true"/>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_givenName">
<property name="fields">
<util:list>
<value>person.givenName</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_familyName">
<property name="fields">
<util:list>
<value>person.familyName</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_affiliation">
<property name="fields">
<util:list>
<value>person.affiliation.name</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifier">
<property name="fields">
<util:list>
<value>person.identifier</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierScopusAuthorID">
<property name="fields">
<util:list>
<value>person.identifier.scopus-author-id</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierRID">
<property name="fields">
<util:list>
<value>person.identifier.rid</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierCienciaID">
<property name="fields">
<util:list>
<value>person.identifier.ciencia-id</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierGSID">
<property name="fields">
<util:list>
<value>person.identifier.gsid</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierOrcid">
<property name="fields">
<util:list>
<value>person.identifier.orcid</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_identifierISNI">
<property name="fields">
<util:list>
<value>person.identifier.isni</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_orgName">
<property name="fields">
<util:list>
<value>organization.legalName</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationAuthor_orgIdentifier">
<property name="fields">
<util:list>
<value>organization.identifier</value>
</util:list>
</property>
</bean>
<!-- Config like this will tell our VirtualMetadataPopulator to include the virtual metadata fields
'dc.relation', 'oaire' funding related, and 'project.funder' and some other related with the appropriate
item with the values defined in the value-ref.
This value-ref should be a bean of type VirtualMetadataConfiguration -->
<util:map id="isProjectOfPublicationMap">
<entry key="dc.relation" value-ref="publicationProject_name"/>
<entry key="oaire.fundingStream" value-ref="publicationProject_fundingStream"/>
<entry key="oaire.awardNumber" value-ref="publicationProject_awardNumber"/>
<entry key="oaire.awardURI" value-ref="publicationProject_awardURI"/>
<entry key="oaire.awardTitle" value-ref="publicationProject_name"/>
<entry key="project.funder.name" value-ref="publicationProject_projectFunderName_related"/>
<entry key="project.funder.identifier" value-ref="publicationProject_projectFunderId_related"/>
</util:map>
<bean class="org.dspace.content.virtual.Collected" id="publicationProject_name">
<property name="fields">
<util:list>
<value>dc.title</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationProject_fundingStream">
<property name="fields">
<util:list>
<value>oaire.fundingStream</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationProject_awardNumber">
<property name="fields">
<util:list>
<value>dc.identifier</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="publicationProject_awardURI">
<property name="fields">
<util:list>
<value>dc.identifier.uri</value>
</util:list>
</property>
</bean>
<!-- This Related bean defines a relationship type that will be used on a publication (from a project).
-->
<bean class="org.dspace.content.virtual.Related" id="publicationProject_projectFunderName_related">
<property name="relationshipTypeString" value="isProjectOfFundingAgency"/>
<property name="place" value="1"/>
<property name="virtualMetadataConfiguration" ref="projectOrgUnit_orgName"/>
</bean>
<bean class="org.dspace.content.virtual.Related" id="publicationProject_projectFunderId_related">
<property name="relationshipTypeString" value="isProjectOfFundingAgency"/>
<property name="place" value="1"/>
<property name="virtualMetadataConfiguration" ref="projectOrgUnit_orgId"/>
</bean>
<!-- Config like this will tell our VirtualMetadataPopulator to include the virtual metadata field
'project.funder.*' on the appropriate item with the values defined in the value-ref.
This value-ref should be a bean of type VirtualMetadataConfiguration -->
<util:map id="isProjectOfFundingAgencyMap">
<entry key="project.funder.name" value-ref="projectOrgUnit_orgName"/>
<entry key="project.funder.identifier" value-ref="projectOrgUnit_orgId"/>
</util:map>
<bean class="org.dspace.content.virtual.Collected" id="projectOrgUnit_orgName">
<property name="fields">
<util:list>
<value>organization.legalName</value>
</util:list>
</property>
</bean>
<bean class="org.dspace.content.virtual.Collected" id="projectOrgUnit_orgId">
<property name="fields">
<util:list>
<value>organization.identifier</value>
</util:list>
</property>
</bean>
</beans>