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;
try {
sResponse = searcher.search(context, query, false);
sResponse = searcher.search(context, query);
List<FacetResult> commCount = sResponse.getFacetResult("location.comm");
List<FacetResult> collCount = sResponse.getFacetResult("location.coll");
for (FacetResult c : commCount) {

View File

@@ -169,9 +169,6 @@ public class SolrBrowseDAO implements BrowseDAO {
private DiscoverResult sResponse = null;
private boolean itemsWithdrawn = false;
private boolean itemsDiscoverable = true;
private boolean showFrequencies;
private DiscoverResult getSolrResponse() throws BrowseException {
@@ -217,8 +214,7 @@ public class SolrBrowseDAO implements BrowseDAO {
}
}
try {
sResponse = searcher.search(context, query, itemsWithdrawn
|| !itemsDiscoverable);
sResponse = searcher.search(context, query);
} catch (SearchServiceException e) {
throw new BrowseException(e);
}
@@ -227,21 +223,14 @@ public class SolrBrowseDAO implements BrowseDAO {
}
private void addStatusFilter(DiscoverQuery query) {
if (itemsWithdrawn) {
query.addFilterQueries("withdrawn:true");
} else if (!itemsDiscoverable) {
query.addFilterQueries("discoverable:false");
// TODO
try {
if (!authorizeService.isAdmin(context)
&& (authorizeService.isCommunityAdmin(context)
|| authorizeService.isCollectionAdmin(context))) {
query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context));
}
} catch (SQLException ex) {
log.error(ex);
try {
if (!authorizeService.isAdmin(context)
&& (authorizeService.isCommunityAdmin(context)
|| authorizeService.isCollectionAdmin(context))) {
query.addFilterQueries(searcher.createLocationQueryForAdministrableItems(context));
}
} catch (SQLException 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.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)");
}
boolean includeUnDiscoverable = itemsWithdrawn || !itemsDiscoverable;
DiscoverResult resp = null;
try {
resp = searcher.search(context, query, includeUnDiscoverable);
resp = searcher.search(context, query);
} catch (SearchServiceException e) {
throw new BrowseException(e);
}
@@ -693,11 +681,6 @@ public class SolrBrowseDAO implements BrowseDAO {
*/
@Override
public void setTable(String table) {
if (table.equals(BrowseIndex.getWithdrawnBrowseIndex().getTableName())) {
itemsWithdrawn = true;
} else if (table.equals(BrowseIndex.getPrivateBrowseIndex().getTableName())) {
itemsDiscoverable = false;
}
facetField = table;
}

View File

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

View File

@@ -14,6 +14,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.annotation.Nullable;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
@@ -222,5 +224,13 @@ public interface BitstreamService extends DSpaceObjectService<Bitstream>, DSpace
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)
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,
int max, String... filterquery);

View File

@@ -561,29 +561,40 @@ public class SolrServiceImpl implements SearchService, IndexingService {
// Query for all indexed Items, Collections and Communities,
// returning just their handle
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);
QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST);
SolrDocumentList docs = rsp.getResults();
Iterator iter = docs.iterator();
while (iter.hasNext()) {
// Get the total amount of results
QueryResponse totalResponse = getSolr().query(query);
long total = totalResponse.getResults().getNumFound();
SolrDocument doc = (SolrDocument) iter.next();
int start = 0;
int batch = 100;
String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID);
query.setRows(batch);
while (start < total) {
query.setStart(start);
QueryResponse rsp = getSolr().query(query, SolrRequest.METHOD.POST);
SolrDocumentList docs = rsp.getResults();
IndexableObject o = findIndexableObject(context, doc);
for (SolrDocument doc : docs) {
String uniqueID = (String) doc.getFieldValue(RESOURCE_UNIQUE_ID);
if (o == null) {
log.info("Deleting: " + uniqueID);
/*
* Use IndexWriter to delete, its easier to manage
* write.lock
*/
unIndexContent(context, uniqueID);
} else {
log.debug("Keeping: " + o.getUniqueIndexID());
IndexableObject o = findIndexableObject(context, doc);
if (o == null) {
log.info("Deleting: " + uniqueID);
/*
* Use IndexWriter to delete, its easier to manage
* write.lock
*/
unIndexContent(context, uniqueID);
} else {
log.debug("Keeping: " + o.getUniqueIndexID());
}
}
start += batch;
}
}
} catch (Exception e) {
@@ -1855,21 +1866,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
//========== SearchService implementation
@Override
public DiscoverResult search(Context context, DiscoverQuery query) throws SearchServiceException {
return search(context, query, false);
}
@Override
public DiscoverResult search(Context context, IndexableObject dso,
DiscoverQuery query)
public DiscoverResult search(Context context, IndexableObject dso, DiscoverQuery discoveryQuery)
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 instanceof Community) {
discoveryQuery.addFilterQueries("location:m" + dso.getID());
@@ -1879,19 +1879,19 @@ public class SolrServiceImpl implements SearchService, IndexingService {
discoveryQuery.addFilterQueries(HANDLE_FIELD + ":" + ((Item) dso).getHandle());
}
}
return search(context, discoveryQuery, includeUnDiscoverable);
return search(context, discoveryQuery);
}
@Override
public DiscoverResult search(Context context, DiscoverQuery discoveryQuery, boolean includeUnDiscoverable)
public DiscoverResult search(Context context, DiscoverQuery discoveryQuery )
throws SearchServiceException {
try {
if (getSolr() == null) {
return new DiscoverResult();
}
SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery, includeUnDiscoverable);
SolrQuery solrQuery = resolveToSolrQuery(context, discoveryQuery);
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,
boolean includeUnDiscoverable) throws SearchServiceException {
protected SolrQuery resolveToSolrQuery(Context context, DiscoverQuery discoveryQuery)
throws SearchServiceException {
SolrQuery solrQuery = new SolrQuery();
String query = "*:*";
@@ -1929,11 +1929,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
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++) {
String filterQuery = discoveryQuery.getFilterQueries().get(i);
solrQuery.addFilterQuery(filterQuery);
@@ -2401,8 +2396,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} catch (Exception e) {
log.error(
LogManager.getHeader(context, "Error while retrieving related items", "Handle: " + item.getHandle()),
e);
LogManager.getHeader(context, "Error while retrieving related items", "Handle: "
+ item.getHandle()), e);
}
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.UUID;
import javax.annotation.Nullable;
import org.apache.commons.collections4.MapUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
@@ -326,15 +328,16 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini
}
}
public Long getLastModified(Bitstream bitstream) {
Map wantedMetadata = new HashMap();
wantedMetadata.put("modified", null);
try {
wantedMetadata = stores.get(incoming).about(bitstream, wantedMetadata);
} catch (IOException e) {
log.error(e);
@Nullable
@Override
public Long getLastModified(Bitstream bitstream) throws IOException {
Map attrs = new HashMap();
attrs.put("modified", null);
attrs = stores.get(bitstream.getStoreNumber()).about(bitstream, attrs);
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.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import org.dspace.authorize.AuthorizeException;
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
* @return The last modified timestamp in milliseconds
* @param bitstream the bitstream.
* @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>
<!-- This is the path to the root [dspace-src] directory. -->
<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>
</properties>

View File

@@ -448,6 +448,12 @@ public class XOAI {
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();
XmlOutputContext xmlContext = XmlOutputContext.emptyContext(out, Second);
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.service.BitstreamService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
@@ -44,18 +45,22 @@ public class ItemUtils {
private static final Logger log = LogManager.getLogger(ItemUtils.class);
private static final MetadataExposureService metadataExposureService
= UtilServiceFactory.getInstance().getMetadataExposureService();
= UtilServiceFactory.getInstance().getMetadataExposureService();
private static final ItemService itemService
= ContentServiceFactory.getInstance().getItemService();
= ContentServiceFactory.getInstance().getItemService();
private static final RelationshipService relationshipService
= ContentServiceFactory.getInstance().getRelationshipService();
private static final BitstreamService bitstreamService
= ContentServiceFactory.getInstance().getBitstreamService();
= ContentServiceFactory.getInstance().getBitstreamService();
/**
* Default constructor
*/
private ItemUtils() { }
private ItemUtils() {
}
private static Element getElement(List<Element> list, String name) {
for (Element e : list) {
@@ -73,228 +78,223 @@ public class ItemUtils {
return e;
}
private static Element.Field createValue(
String name, String value) {
private static Element.Field createValue(String name, String value) {
Element.Field e = new Element.Field();
e.setValue(value);
e.setName(name);
return e;
}
private static Element createBundlesElement(Context context, Item item) throws SQLException {
Element bundles = create("bundles");
List<Bundle> bs;
bs = item.getBundles();
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();
Element valueElem = schema;
// Has element.. with XOAI one could have only schema and value
if (field.getElement() != null && !field.getElement().equals("")) {
Element element = getElement(schema.getElement(), field.getElement());
if (element == null) {
element = create(field.getElement());
schema.getElement().add(element);
}
valueElem = element;
// Qualified element?
if (field.getQualifier() != null && !field.getQualifier().equals("")) {
Element qualifier = getElement(element.getElement(), field.getQualifier());
if (qualifier == null) {
qualifier = create(field.getQualifier());
element.getElement().add(qualifier);
}
valueElem = qualifier;
}
}
// Language?
if (val.getLanguage() != null && !val.getLanguage().equals("")) {
Element language = getElement(valueElem.getElement(), val.getLanguage());
if (language == null) {
language = create(val.getLanguage());
valueElem.getElement().add(language);
}
valueElem = language;
} else {
Element language = getElement(valueElem.getElement(), "none");
if (language == null) {
language = create("none");
valueElem.getElement().add(language);
}
valueElem = language;
}
valueElem.getField().add(createValue("value", val.getValue()));
if (val.getAuthority() != null) {
valueElem.getField().add(createValue("authority", val.getAuthority()));
if (val.getConfidence() != Choices.CF_NOVALUE) {
valueElem.getField().add(createValue("confidence", val.getConfidence() + ""));
}
}
}
/**
* 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();
// Don't expose fields that are hidden by configuration
try {
if (metadataExposureService.isHidden(context,
field.getMetadataSchema().getName(),
field.getElement(),
field.getQualifier())) {
// 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);
}
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
if (field.getElement() != null && !field.getElement().equals("")) {
Element element = getElement(schema.getElement(),
field.getElement());
if (element == null) {
element = create(field.getElement());
schema.getElement().add(element);
}
valueElem = element;
// Qualified element?
if (field.getQualifier() != null && !field.getQualifier().equals("")) {
Element qualifier = getElement(element.getElement(),
field.getQualifier());
if (qualifier == null) {
qualifier = create(field.getQualifier());
element.getElement().add(qualifier);
}
valueElem = qualifier;
}
}
// Language?
if (val.getLanguage() != null && !val.getLanguage().equals("")) {
Element language = getElement(valueElem.getElement(),
val.getLanguage());
if (language == null) {
language = create(val.getLanguage());
valueElem.getElement().add(language);
}
valueElem = language;
} else {
Element language = getElement(valueElem.getElement(),
"none");
if (language == null) {
language = create("none");
valueElem.getElement().add(language);
}
valueElem = language;
}
valueElem.getField().add(createValue("value", val.getValue()));
if (val.getAuthority() != null) {
valueElem.getField().add(createValue("authority", val.getAuthority()));
if (val.getConfidence() != Choices.CF_NOVALUE) {
valueElem.getField().add(createValue("confidence", val.getConfidence() + ""));
}
}
}
// Done! Metadata has been read!
// Now adding bitstream info
Element bundles = create("bundles");
metadata.getElement().add(bundles);
List<Bundle> bs;
try {
bs = item.getBundles();
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()
+ ""));
}
}
} catch (SQLException e1) {
e1.printStackTrace();
Element bundles = createBundlesElement(context, item);
metadata.getElement().add(bundles);
} catch (SQLException e) {
log.warn(e.getMessage(), e);
}
// Other info
Element other = create("others");
other.getField().add(
createValue("handle", item.getHandle()));
other.getField().add(
createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle())));
other.getField().add(
createValue("lastModifyDate", item
.getLastModified().toString()));
other.getField().add(createValue("handle", item.getHandle()));
other.getField().add(createValue("identifier", DSpaceItem.buildIdentifier(item.getHandle())));
other.getField().add(createValue("lastModifyDate", item.getLastModified().toString()));
metadata.getElement().add(other);
// Repository Info
Element repository = create("repository");
repository.getField().add(
createValue("name",
ConfigurationManager.getProperty("dspace.name")));
repository.getField().add(
createValue("mail",
ConfigurationManager.getProperty("mail.admin")));
repository.getField().add(createValue("url", ConfigurationManager.getProperty("dspace.baseUrl")));
repository.getField().add(createValue("name", ConfigurationManager.getProperty("dspace.name")));
repository.getField().add(createValue("mail", ConfigurationManager.getProperty("mail.admin")));
metadata.getElement().add(repository);
// Licensing info
Element license = create("license");
List<Bundle> licBundles;
try {
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;
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);
} catch (AuthorizeException | IOException | SQLException e) {
log.warn(e.getMessage(), e);
}
}
}
} catch (SQLException e1) {
log.warn(e1.getMessage(), e1);
Element license = createLicenseElement(context, item);
metadata.getElement().add(license);
} catch (AuthorizeException | IOException | SQLException e) {
log.warn(e.getMessage(), e);
}
return metadata;

View File

@@ -127,10 +127,13 @@ public class BitstreamRestController {
.withLength(bitstreamTuple.getRight())
.withChecksum(bit.getChecksum())
.withMimetype(mimetype)
.withLastModified(lastModified)
.with(request)
.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
long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold");
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"?>
<Configuration indented="false" maxListIdentifiersSize="100" maxListRecordsSize="100"
maxListSetsSize="100" stylesheet="static/style.xsl"
xmlns="http://www.lyncode.com/XOAIConfiguration">
maxListSetsSize="100" stylesheet="static/style.xsl" xmlns="http://www.lyncode.com/XOAIConfiguration">
<Contexts>
<Context baseurl="request" name="Default Context">
@@ -70,6 +69,28 @@
This contexts complies with OpenAIRE Guidelines for Literature Repositories v3.0.
</Description>
</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>
@@ -155,6 +176,15 @@
<Namespace>http://irdb.nii.ac.jp/oai</Namespace>
<SchemaLocation>http://irdb.nii.ac.jp/oai/junii2-3-1.xsd</SchemaLocation>
</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>
<Transformers>
@@ -164,6 +194,9 @@
<Transformer id="openaireTransformer">
<XSLT>transformers/openaire.xsl</XSLT>
</Transformer>
<Transformer id="openaire4Transformer">
<XSLT>transformers/openaire4.xsl</XSLT>
</Transformer>
</Transformers>
@@ -286,22 +319,83 @@
</Definition>
</Filter>
<!-- Default filter for records returned by OAI-PMH.
<!-- OpenAIRE4 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).
* * 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="openAIRE4Filter">
<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>
</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>
<Or>
<And>
<LeftCondition>
<Custom ref="itemAccessCondition"/>
<Or>
<LeftCondition>
<Custom ref="itemAccessCondition"/>
</LeftCondition>
<RightCondition>
<Custom ref="itemWithdrawnCondition"/>
</RightCondition>
</Or>
</LeftCondition>
<RightCondition>
<Custom ref="itemWithdrawnCondition"/>
<Or>
<LeftCondition>
<Not>
<Condition>
<Custom ref="relationshipTypeExistsCondition"/>
</Condition>
</Not>
</LeftCondition>
<RightCondition>
<Custom ref="isPublicationEntityCondition"/>
</RightCondition>
</Or>
</RightCondition>
</Or>
</And>
</Definition>
</Filter>
@@ -398,6 +492,30 @@
<string name="value">info:eu-repo/grantAgreement/</string>
</Configuration>
</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>
<Sets>

View File

@@ -27,6 +27,7 @@
<bean id="solrServiceResourceIndexPlugin" class="org.dspace.discovery.SolrServiceResourceRestrictionPlugin" scope="prototype"/>
<bean id="SolrServiceSpellIndexingPlugin" class="org.dspace.discovery.SolrServiceSpellIndexingPlugin" 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"/>
@@ -51,9 +52,9 @@
<entry key="site" value-ref="homepageConfiguration" />
<!--<entry key="123456789/7621" value-ref="defaultConfiguration"/>-->
<!-- 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="undiscoverable" value-ref="unDiscoverableItems" />
<entry key="publication" value-ref="publication"/>
<entry key="person" value-ref="person"/>
<entry key="organization" value-ref="organization"/>
@@ -249,6 +250,147 @@
<property name="spellCheckEnabled" value="true"/>
</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-->
<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>