Merge branch 'master' into DS-4389-improving-patch-system-framework

This commit is contained in:
Kevin Van de Velde
2019-11-27 14:55:16 +01:00
350 changed files with 15118 additions and 3628 deletions

View File

@@ -780,8 +780,8 @@ public class MetadataImport {
} }
// Create the relationship // Create the relationship
int leftPlace = relationshipService.findLeftPlaceByLeftItem(c, leftItem) + 1; int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem);
int rightPlace = relationshipService.findRightPlaceByRightItem(c, rightItem) + 1; int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem);
Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem, Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem,
foundRelationshipType, leftPlace, rightPlace); foundRelationshipType, leftPlace, rightPlace);
relationshipService.update(c, persistedRelationship); relationshipService.update(c, persistedRelationship);

View File

@@ -13,6 +13,12 @@ import java.lang.reflect.Method;
import java.util.List; import java.util.List;
import java.util.TreeMap; import java.util.TreeMap;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
import org.dspace.servicemanager.DSpaceKernelImpl; import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit; import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService; import org.dspace.services.RequestService;
@@ -27,6 +33,9 @@ import org.jdom.input.SAXBuilder;
* @author Mark Diggory * @author Mark Diggory
*/ */
public class ScriptLauncher { public class ScriptLauncher {
private static final Logger log = Logger.getLogger(ScriptLauncher.class);
/** /**
* The service manager kernel * The service manager kernel
*/ */
@@ -76,8 +85,9 @@ public class ScriptLauncher {
} }
// Look up command in the configuration, and execute. // Look up command in the configuration, and execute.
int status;
status = runOneCommand(commandConfigs, args); CommandLineDSpaceRunnableHandler commandLineDSpaceRunnableHandler = new CommandLineDSpaceRunnableHandler();
int status = handleScript(args, commandConfigs, commandLineDSpaceRunnableHandler, kernelImpl);
// Destroy the service kernel if it is still alive // Destroy the service kernel if it is still alive
if (kernelImpl != null) { if (kernelImpl != null) {
@@ -86,6 +96,50 @@ public class ScriptLauncher {
} }
System.exit(status); System.exit(status);
}
/**
* This method will take the arguments from a commandline input and it'll find the script that the first argument
* refers to and it'll execute this script.
* It can return a 1 or a 0 depending on whether the script failed or passed respectively
* @param args The arguments for the script and the script as first one in the array
* @param commandConfigs The Document
* @param dSpaceRunnableHandler The DSpaceRunnableHandler for this execution
* @param kernelImpl The relevant DSpaceKernelImpl
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
public static int handleScript(String[] args, Document commandConfigs,
DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceKernelImpl kernelImpl) {
int status;
DSpaceRunnable script = ScriptServiceFactory.getInstance().getScriptService().getScriptForName(args[0]);
if (script != null) {
status = executeScript(args, dSpaceRunnableHandler, script);
} else {
status = runOneCommand(commandConfigs, args, kernelImpl);
}
return status;
}
/**
* This method will simply execute the script
* @param args The arguments of the script with the script name as first place in the array
* @param dSpaceRunnableHandler The relevant DSpaceRunnableHandler
* @param script The script to be executed
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
private static int executeScript(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceRunnable script) {
try {
script.initialize(args, dSpaceRunnableHandler);
script.run();
return 0;
} catch (ParseException e) {
script.printHelp();
e.printStackTrace();
return 1;
}
} }
protected static int runOneCommand(Document commandConfigs, String[] args) { protected static int runOneCommand(Document commandConfigs, String[] args) {
@@ -98,7 +152,7 @@ public class ScriptLauncher {
* @param commandConfigs Document * @param commandConfigs Document
* @param args the command line arguments given * @param args the command line arguments given
*/ */
public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) { protected static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
String request = args[0]; String request = args[0];
Element root = commandConfigs.getRootElement(); Element root = commandConfigs.getRootElement();
List<Element> commands = root.getChildren("command"); List<Element> commands = root.getChildren("command");

View File

@@ -15,6 +15,9 @@ import java.util.List;
* @author Andrea Bollini * @author Andrea Bollini
*/ */
public class SHERPAPublisher { public class SHERPAPublisher {
private String id;
private String name; private String name;
private String alias; private String alias;
@@ -49,7 +52,7 @@ public class SHERPAPublisher {
private String dateupdated; private String dateupdated;
public SHERPAPublisher(String name, String alias, String homeurl, public SHERPAPublisher(String id, String name, String alias, String homeurl,
String prearchiving, List<String> prerestriction, String prearchiving, List<String> prerestriction,
String postarchiving, List<String> postrestriction, String postarchiving, List<String> postrestriction,
String pubarchiving, List<String> pubrestriction, String pubarchiving, List<String> pubrestriction,
@@ -57,6 +60,8 @@ public class SHERPAPublisher {
String paidaccessname, String paidaccessnotes, String paidaccessname, String paidaccessnotes,
List<String[]> copyright, String romeocolour, String datedded, List<String[]> copyright, String romeocolour, String datedded,
String dateupdated) { String dateupdated) {
this.id = id;
this.name = name; this.name = name;
this.alias = alias; this.alias = alias;
@@ -160,4 +165,11 @@ public class SHERPAPublisher {
return dateupdated; return dateupdated;
} }
/**
* Generic getter for the id
* @return the id value of this SHERPAPublisher
*/
public String getId() {
return id;
}
} }

View File

@@ -14,6 +14,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.XMLUtils; import org.dspace.app.util.XMLUtils;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@@ -24,7 +25,9 @@ import org.w3c.dom.Element;
* @author Andrea Bollini * @author Andrea Bollini
*/ */
public class SHERPAResponse { public class SHERPAResponse {
private boolean error; private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPAResponse.class);
private int numHits;
private String message; private String message;
@@ -57,12 +60,13 @@ public class SHERPAResponse {
Element publishersElement = XMLUtils.getSingleElement(xmlRoot, Element publishersElement = XMLUtils.getSingleElement(xmlRoot,
"publishers"); "publishers");
message = XMLUtils.getElementValue(headersElement, "message"); String numhitsString = XMLUtils.getElementValue(headersElement, "numhits");
if (StringUtils.isNotBlank(numhitsString)) {
if (StringUtils.isNotBlank(message)) { numHits = Integer.parseInt(numhitsString);
error = true; } else {
return; numHits = 0;
} }
message = XMLUtils.getElementValue(headersElement, "message");
license = XMLUtils.getElementValue(headersElement, "license"); license = XMLUtils.getElementValue(headersElement, "license");
licenseURL = XMLUtils.getElementValue(headersElement, "licenseurl"); licenseURL = XMLUtils.getElementValue(headersElement, "licenseurl");
@@ -112,9 +116,8 @@ public class SHERPAResponse {
Element copyrightlinksElement = XMLUtils.getSingleElement( Element copyrightlinksElement = XMLUtils.getSingleElement(
publisherElement, "copyrightlinks"); publisherElement, "copyrightlinks");
publishers publishers
.add(new SHERPAPublisher(XMLUtils.getElementValue( .add(new SHERPAPublisher(publisherElement.getAttribute("id"), XMLUtils.getElementValue(
publisherElement, "name"), publisherElement, "name"),
XMLUtils.getElementValue(publisherElement, XMLUtils.getElementValue(publisherElement,
"alias"), XMLUtils.getElementValue( "alias"), XMLUtils.getElementValue(
@@ -162,17 +165,12 @@ public class SHERPAResponse {
} }
} }
} catch (Exception e) { } catch (Exception e) {
error = true; log.error("Error parsing SHERPA API Response", e);
} }
} }
public SHERPAResponse(String message) { public SHERPAResponse(String message) {
this.message = message; this.message = message;
this.error = true;
}
public boolean isError() {
return error;
} }
public String getMessage() { public String getMessage() {
@@ -198,4 +196,8 @@ public class SHERPAResponse {
public List<SHERPAPublisher> getPublishers() { public List<SHERPAPublisher> getPublishers() {
return publishers; return publishers;
} }
public int getNumHits() {
return numHits;
}
} }

View File

@@ -52,11 +52,11 @@ public class InitializeEntities {
private RelationshipService relationshipService; private RelationshipService relationshipService;
private EntityTypeService entityTypeService; private EntityTypeService entityTypeService;
private InitializeEntities() { private InitializeEntities() {
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService(); relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
relationshipService = ContentServiceFactory.getInstance().getRelationshipService(); relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService(); entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
} }
/** /**

View File

@@ -35,6 +35,7 @@ public abstract class AuthorityServiceFactory {
public abstract AuthorityService getAuthorityService(); public abstract AuthorityService getAuthorityService();
public abstract List<AuthorityIndexerInterface> getAuthorityIndexers(); public abstract List<AuthorityIndexerInterface> getAuthorityIndexers();
public static AuthorityServiceFactory getInstance() { public static AuthorityServiceFactory getInstance() {

View File

@@ -1,191 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.authority.orcid;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.SolrAuthorityInterface;
import org.dspace.authority.orcid.xml.XMLtoBio;
import org.dspace.authority.rest.RESTConnector;
import org.json.JSONObject;
import org.orcid.jaxb.model.record_v2.Person;
/**
* @author Jonas Van Goolen (jonas at atmire dot com)
* This class contains all methods for retrieving "Person" objects calling the ORCID (version 2) endpoints.
* Additionally, this can also create AuthorityValues based on these returned Person objects
*/
public class Orcidv2 implements SolrAuthorityInterface {
private static Logger log = LogManager.getLogger(Orcidv2.class);
public RESTConnector restConnector;
private String OAUTHUrl;
private String clientId;
private String clientSecret;
private String accessToken;
/**
* Initialize the accessToken that is required for all subsequent calls to ORCID.
*
* @throws java.io.IOException passed through from HTTPclient.
*/
public void init() throws IOException {
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) {
String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials";
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse getResponse = httpClient.execute(httpPost);
InputStream is = getResponse.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
JSONObject responseObject = null;
String inputStr;
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
try {
responseObject = new JSONObject(inputStr);
} catch (Exception e) {
//Not as valid as I'd hoped, move along
responseObject = null;
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
accessToken = (String) responseObject.get("access_token");
}
}
}
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private Orcidv2(String url, String OAUTHUrl, String clientId, String clientSecret) {
this.restConnector = new RESTConnector(url);
this.OAUTHUrl = OAUTHUrl;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private Orcidv2(String url) {
this.restConnector = new RESTConnector(url);
}
/**
* Makes an instance of the AuthorityValue with the given information.
* @param text search string
* @return List<AuthorityValue>
*/
@Override
public List<AuthorityValue> queryAuthorities(String text, int max) {
List<Person> bios = queryBio(text, max);
List<AuthorityValue> result = new ArrayList<>();
for (Person person : bios) {
AuthorityValue orcidAuthorityValue = Orcidv2AuthorityValue.create(person);
if (orcidAuthorityValue != null) {
result.add(orcidAuthorityValue);
}
}
return result;
}
/**
* Create an AuthorityValue from a Person retrieved using the given orcid identifier.
* @param id orcid identifier
* @return AuthorityValue
*/
public AuthorityValue queryAuthorityID(String id) {
Person person = getBio(id);
AuthorityValue valueFromPerson = Orcidv2AuthorityValue.create(person);
return valueFromPerson;
}
/**
* Retrieve a Person object based on a given orcid identifier
* @param id orcid identifier
* @return Person
*/
public Person getBio(String id) {
log.debug("getBio called with ID=" + id);
if (!isValid(id)) {
return null;
}
InputStream bioDocument = restConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
XMLtoBio converter = new XMLtoBio();
Person person = converter.convertSinglePerson(bioDocument);
return person;
}
/**
* Retrieve a list of Person objects.
* @param text search string
* @param start offset to use
* @param rows how many rows to return
* @return List<Person>
*/
public List<Person> queryBio(String text, int start, int rows) {
if (rows > 100) {
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
}
String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = restConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
List<Person> bios = converter.convert(bioDocument);
return bios;
}
/**
* Retrieve a list of Person objects.
* @param text search string
* @param max how many rows to return
* @return List<Person>
*/
public List<Person> queryBio(String text, int max) {
return queryBio(text, 0, max);
}
/**
* Check to see if the provided text has the correct ORCID syntax.
* Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a
* blank result anyway
*/
private boolean isValid(String text) {
return StringUtils.isNotBlank(text) && text.matches(Orcidv2AuthorityValue.ORCID_ID_SYNTAX);
}
}

View File

@@ -1,342 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.authority.orcid;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.AuthorityValueServiceImpl;
import org.dspace.authority.PersonAuthorityValue;
import org.dspace.utils.DSpace;
import org.orcid.jaxb.model.common_v2.ExternalId;
import org.orcid.jaxb.model.record_v2.ExternalIdentifiers;
import org.orcid.jaxb.model.record_v2.KeywordType;
import org.orcid.jaxb.model.record_v2.NameType;
import org.orcid.jaxb.model.record_v2.Person;
import org.orcid.jaxb.model.record_v2.ResearcherUrlType;
/**
* @author Jonas Van Goolen (jonas at atmire dot com)
*/
public class Orcidv2AuthorityValue extends PersonAuthorityValue {
/*
* The ORCID identifier
*/
private String orcid_id;
/*
* Map containing key-value pairs filled in by "setValues(Person person)".
* This represents all dynamic information of the object.
*/
private Map<String, List<String>> otherMetadata = new HashMap<String, List<String>>();
/**
* The syntax that the ORCID id needs to conform to
*/
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
/**
* Creates an instance of Orcidv2AuthorityValue with only uninitialized fields.
* This is meant to be filled in with values from an existing record.
* To create a brand new Orcidv2AuthorityValue, use create()
*/
public Orcidv2AuthorityValue() {
}
public Orcidv2AuthorityValue(SolrDocument document) {
super(document);
}
public String getOrcid_id() {
return orcid_id;
}
public void setOrcid_id(String orcid_id) {
this.orcid_id = orcid_id;
}
/**
* Create an empty authority.
* @return OrcidAuthorityValue
*/
public static Orcidv2AuthorityValue create() {
Orcidv2AuthorityValue orcidAuthorityValue = new Orcidv2AuthorityValue();
orcidAuthorityValue.setId(UUID.randomUUID().toString());
orcidAuthorityValue.updateLastModifiedDate();
orcidAuthorityValue.setCreationDate(new Date());
return orcidAuthorityValue;
}
/**
* Create an authority based on a given orcid bio
* @return OrcidAuthorityValue
*/
public static Orcidv2AuthorityValue create(Person person) {
if (person == null) {
return null;
}
Orcidv2AuthorityValue authority = Orcidv2AuthorityValue.create();
authority.setValues(person);
return authority;
}
/**
* Initialize this instance based on a Person object
* @param person Person
*/
protected void setValues(Person person) {
NameType name = person.getName();
if (!StringUtils.equals(name.getPath(), this.getOrcid_id())) {
this.setOrcid_id(name.getPath());
}
if (!StringUtils.equals(name.getFamilyName().getValue(), this.getLastName())) {
this.setLastName(name.getFamilyName().getValue());
}
if (!StringUtils.equals(name.getGivenNames().getValue(), this.getFirstName())) {
this.setFirstName(name.getGivenNames().getValue());
}
if (name.getCreditName() != null && StringUtils.isNotBlank(name.getCreditName().getValue())) {
if (!this.getNameVariants().contains(name.getCreditName().getValue())) {
this.addNameVariant(name.getCreditName().getValue());
}
}
if (person.getKeywords() != null) {
for (KeywordType keyword : person.getKeywords().getKeyword()) {
if (this.isNewMetadata("keyword", keyword.getContent())) {
this.addOtherMetadata("keyword", keyword.getContent());
}
}
}
ExternalIdentifiers externalIdentifiers = person.getExternalIdentifiers();
if (externalIdentifiers != null) {
for (ExternalId externalIdentifier : externalIdentifiers.getExternalIdentifier()) {
if (this.isNewMetadata("external_identifier", externalIdentifier.getExternalIdValue())) {
this.addOtherMetadata("external_identifier", externalIdentifier.getExternalIdValue());
}
}
}
if (person.getResearcherUrls() != null) {
for (ResearcherUrlType researcherUrl : person.getResearcherUrls().getResearcherUrl()) {
if (this.isNewMetadata("researcher_url", researcherUrl.getUrl().getValue())) {
this.addOtherMetadata("researcher_url", researcherUrl.getUrl().getValue());
}
}
}
if (person.getBiography() != null) {
if (this.isNewMetadata("biography", person.getBiography().getContent())) {
this.addOtherMetadata("biography", person.getBiography().getContent());
}
}
this.setValue(this.getName());
}
/**
* Makes an instance of the AuthorityValue with the given information.
* @param info string info
* @return AuthorityValue
*/
@Override
public AuthorityValue newInstance(String info) {
AuthorityValue authorityValue = null;
if (StringUtils.isNotBlank(info)) {
Orcidv2 orcid = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class);
authorityValue = orcid.queryAuthorityID(info);
} else {
authorityValue = this.create();
}
return authorityValue;
}
@Override
public void setValue(String value) {
super.setValue(value);
}
/**
* Check to see if the provided label / data pair is already present in the "otherMetadata" or not
* */
public boolean isNewMetadata(String label, String data) {
List<String> strings = getOtherMetadata().get(label);
boolean update;
if (strings == null) {
update = StringUtils.isNotBlank(data);
} else {
update = !strings.contains(data);
}
return update;
}
/**
* Add additional metadata to the otherMetadata map*/
public void addOtherMetadata(String label, String data) {
List<String> strings = otherMetadata.get(label);
if (strings == null) {
strings = new ArrayList<>();
}
strings.add(data);
otherMetadata.put(label, strings);
}
public Map<String, List<String>> getOtherMetadata() {
return otherMetadata;
}
/**
* Generate a solr record from this instance
* @return SolrInputDocument
*/
@Override
public SolrInputDocument getSolrInputDocument() {
SolrInputDocument doc = super.getSolrInputDocument();
if (StringUtils.isNotBlank(getOrcid_id())) {
doc.addField("orcid_id", getOrcid_id());
}
for (String t : otherMetadata.keySet()) {
List<String> data = otherMetadata.get(t);
for (String data_entry : data) {
doc.addField("label_" + t, data_entry);
}
}
return doc;
}
/**
* Information that can be used the choice ui
* @return map
*/
@Override
public Map<String, String> choiceSelectMap() {
Map<String, String> map = super.choiceSelectMap();
String orcid_id = getOrcid_id();
if (StringUtils.isNotBlank(orcid_id)) {
map.put("orcid", orcid_id);
}
return map;
}
@Override
public String getAuthorityType() {
return "orcid";
}
/**
* Provides a string that will allow this AuthorityType to be recognized and provides information to create a new
* instance to be created using public Orcidv2AuthorityValue newInstance(String info).
* @return see {@link org.dspace.authority.service.AuthorityValueService#GENERATE AuthorityValueService.GENERATE}
*/
@Override
public String generateString() {
String generateString = AuthorityValueServiceImpl.GENERATE + getAuthorityType() +
AuthorityValueServiceImpl.SPLIT;
if (StringUtils.isNotBlank(getOrcid_id())) {
generateString += getOrcid_id();
}
return generateString;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return orcid_id != null ? orcid_id.hashCode() : 0;
}
/**
* The regular equals() only checks if both AuthorityValues describe the same authority.
* This method checks if the AuthorityValues have different information
* E.g. it is used to decide when lastModified should be updated.
* @param o object
* @return true or false
*/
@Override
public boolean hasTheSameInformationAs(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.hasTheSameInformationAs(o)) {
return false;
}
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
return false;
}
for (String key : otherMetadata.keySet()) {
if (otherMetadata.get(key) != null) {
List<String> metadata = otherMetadata.get(key);
List<String> otherMetadata = that.otherMetadata.get(key);
if (otherMetadata == null) {
return false;
} else {
HashSet<String> metadataSet = new HashSet<String>(metadata);
HashSet<String> otherMetadataSet = new HashSet<String>(otherMetadata);
if (!metadataSet.equals(otherMetadataSet)) {
return false;
}
}
} else {
if (that.otherMetadata.get(key) != null) {
return false;
}
}
}
return true;
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.authority.rest; package org.dspace.authority.rest;
import org.dspace.authority.SolrAuthorityInterface; import org.dspace.authority.SolrAuthorityInterface;
import org.dspace.external.OrcidRestConnector;
/** /**
* @author Antoine Snyers (antoine at atmire.com) * @author Antoine Snyers (antoine at atmire.com)
@@ -17,9 +18,9 @@ import org.dspace.authority.SolrAuthorityInterface;
*/ */
public abstract class RestSource implements SolrAuthorityInterface { public abstract class RestSource implements SolrAuthorityInterface {
protected RESTConnector restConnector; protected OrcidRestConnector restConnector;
public RestSource(String url) { public RestSource(String url) {
this.restConnector = new RESTConnector(url); this.restConnector = new OrcidRestConnector(url);
} }
} }

View File

@@ -7,6 +7,10 @@
*/ */
package org.dspace.content; package org.dspace.content;
import static org.dspace.core.Constants.ADD;
import static org.dspace.core.Constants.REMOVE;
import static org.dspace.core.Constants.WRITE;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -268,6 +272,81 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl<Bundle> implement
return authorizeService.getPolicies(context, bundle); return authorizeService.getPolicies(context, bundle);
} }
@Override
public void updateBitstreamOrder(Context context, Bundle bundle, int from, int to)
throws AuthorizeException, SQLException {
List<Bitstream> bitstreams = bundle.getBitstreams();
if (bitstreams.size() < 1 || from >= bitstreams.size() || to >= bitstreams.size() || from < 0 || to < 0) {
throw new IllegalArgumentException(
"Invalid 'from' and 'to' arguments supplied for moving a bitstream within bundle " +
bundle.getID() + ". from: " + from + "; to: " + to
);
}
List<UUID> bitstreamIds = new LinkedList<>();
for (Bitstream bitstream : bitstreams) {
bitstreamIds.add(bitstream.getID());
}
if (from < to) {
bitstreamIds.add(to + 1, bitstreamIds.get(from));
bitstreamIds.remove(from);
} else {
bitstreamIds.add(to, bitstreamIds.get(from));
bitstreamIds.remove(from + 1);
}
setOrder(context, bundle, bitstreamIds.toArray(new UUID[bitstreamIds.size()]));
}
@Override
public void moveBitstreamToBundle(Context context, Bundle targetBundle, Bitstream bitstream)
throws SQLException, AuthorizeException, IOException {
List<Bundle> bundles = new LinkedList<>();
bundles.addAll(bitstream.getBundles());
if (hasSufficientMovePermissions(context, bundles, targetBundle)) {
this.addBitstream(context, targetBundle, bitstream);
this.update(context, targetBundle);
for (Bundle bundle : bundles) {
this.removeBitstream(context, bundle, bitstream);
this.update(context, bundle);
}
}
}
/**
* Verifies if the context (user) has sufficient rights to the bundles in order to move a bitstream
*
* @param context The context
* @param bundles The current bundles in which the bitstream resides
* @param targetBundle The target bundle
* @return true when the context has sufficient rights
* @throws AuthorizeException When one of the necessary rights is not present
*/
private boolean hasSufficientMovePermissions(final Context context, final List<Bundle> bundles,
final Bundle targetBundle) throws SQLException, AuthorizeException {
for (Bundle bundle : bundles) {
if (!authorizeService.authorizeActionBoolean(context, bundle, WRITE) || !authorizeService
.authorizeActionBoolean(context, bundle, REMOVE)) {
throw new AuthorizeException(
"The current user does not have WRITE and REMOVE access to the current bundle: " + bundle
.getID());
}
}
if (!authorizeService.authorizeActionBoolean(context, targetBundle, WRITE) || !authorizeService
.authorizeActionBoolean(context, targetBundle, ADD)) {
throw new AuthorizeException(
"The current user does not have WRITE and ADD access to the target bundle: " + targetBundle
.getID());
}
for (Item item : targetBundle.getItems()) {
if (!authorizeService.authorizeActionBoolean(context, item, WRITE)) {
throw new AuthorizeException(
"The current user does not have WRITE access to the target bundle's item: " + item.getID());
}
}
return true;
}
@Override @Override
public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws AuthorizeException, SQLException { public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws AuthorizeException, SQLException {
authorizeService.authorizeAction(context, bundle, Constants.WRITE); authorizeService.authorizeAction(context, bundle, Constants.WRITE);

View File

@@ -761,6 +761,8 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
// Remove any workflow roles // Remove any workflow roles
collectionRoleService.deleteByCollection(context, collection); collectionRoleService.deleteByCollection(context, collection);
collection.getResourcePolicies().clear();
// Remove default administrators group // Remove default administrators group
Group g = collection.getAdministrators(); Group g = collection.getAdministrators();

View File

@@ -250,8 +250,11 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
} }
} }
MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField); MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField);
//Set place to list length //Set place to list length of all metadatavalues for the given schema.element.qualifier combination.
metadataValue.setPlace(this.getMetadata(dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY).size()); // Subtract one to adhere to the 0 as first element rule
metadataValue.setPlace(
this.getMetadata(dso, metadataField.getMetadataSchema().getName(), metadataField.getElement(),
metadataField.getQualifier(), Item.ANY).size() - 1);
metadataValue.setLanguage(lang == null ? null : lang.trim()); metadataValue.setLanguage(lang == null ? null : lang.trim());

View File

@@ -695,6 +695,11 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
log.info(LogManager.getHeader(context, "delete_item", "item_id=" log.info(LogManager.getHeader(context, "delete_item", "item_id="
+ item.getID())); + item.getID()));
// Remove relationships
for (Relationship relationship : relationshipService.findByItem(context, item)) {
relationshipService.delete(context, relationship, false, false);
}
// Remove bundles // Remove bundles
removeAllBundles(context, item); removeAllBundles(context, item);

View File

@@ -0,0 +1,19 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;
/**
* This Enum holds a representation of all the possible states that a Process can be in
*/
public enum ProcessStatus {
SCHEDULED,
RUNNING,
COMPLETED,
FAILED
}

View File

@@ -7,9 +7,11 @@
*/ */
package org.dspace.content; package org.dspace.content;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.dspace.content.virtual.VirtualMetadataPopulator; import org.dspace.content.virtual.VirtualMetadataPopulator;
import org.dspace.core.Context;
/** /**
* Interface used for the {@link RelationshipMetadataServiceImpl} * Interface used for the {@link RelationshipMetadataServiceImpl}
@@ -27,4 +29,34 @@ public interface RelationshipMetadataService {
* @return The list of MetadataValue objects constructed through the Relationships * @return The list of MetadataValue objects constructed through the Relationships
*/ */
public List<RelationshipMetadataValue> getRelationshipMetadata(Item item, boolean enableVirtualMetadata); public List<RelationshipMetadataValue> getRelationshipMetadata(Item item, boolean enableVirtualMetadata);
/**
* Retrieves the list of RelationshipMetadataValue objects specific to only one Relationship of the item.
*
* This method processes one Relationship of an Item and will return a list of RelationshipMetadataValue objects
* that are generated for this specific relationship for the item through the config in VirtualMetadataPopulator
*
* It returns a combination of the output of the findVirtualMetadataFromConfiguration method and
* the getRelationMetadataFromOtherItem method.
*
* @param context The context
* @param item The item whose virtual metadata is requested
* @param entityType The entity type of the given item
* @param relationship The relationship whose virtual metadata is requested
* @param enableVirtualMetadata Determines whether the VirtualMetadataPopulator should be used.
* If false, only the relation."relationname" metadata is populated
* If true, fields from the spring config virtual metadata is included as well
* @return The list of virtual metadata values
*/
public List<RelationshipMetadataValue> findRelationshipMetadataValueForItemRelationship(
Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata)
throws SQLException;
/**
* This method will retrieve the EntityType String from an item
* @param item The Item for which the entityType String will be returned
* @return A String value indicating the entityType
*/
public String getEntityTypeStringFromMetadata(Item item);
} }

View File

@@ -44,8 +44,7 @@ public class RelationshipMetadataServiceImpl implements RelationshipMetadataServ
Context context = new Context(); Context context = new Context();
List<RelationshipMetadataValue> fullMetadataValueList = new LinkedList<>(); List<RelationshipMetadataValue> fullMetadataValueList = new LinkedList<>();
try { try {
List<MetadataValue> list = item.getMetadata(); String entityType = getEntityTypeStringFromMetadata(item);
String entityType = getEntityTypeStringFromMetadata(list);
if (StringUtils.isNotBlank(entityType)) { if (StringUtils.isNotBlank(entityType)) {
List<Relationship> relationships = relationshipService.findByItem(context, item); List<Relationship> relationships = relationshipService.findByItem(context, item);
for (Relationship relationship : relationships) { for (Relationship relationship : relationships) {
@@ -61,7 +60,8 @@ public class RelationshipMetadataServiceImpl implements RelationshipMetadataServ
return fullMetadataValueList; return fullMetadataValueList;
} }
private String getEntityTypeStringFromMetadata(List<MetadataValue> list) { public String getEntityTypeStringFromMetadata(Item item) {
List<MetadataValue> list = item.getMetadata();
for (MetadataValue mdv : list) { for (MetadataValue mdv : list) {
if (StringUtils.equals(mdv.getMetadataField().getMetadataSchema().getName(), if (StringUtils.equals(mdv.getMetadataField().getMetadataSchema().getName(),
"relationship") "relationship")
@@ -74,22 +74,8 @@ public class RelationshipMetadataServiceImpl implements RelationshipMetadataServ
return null; return null;
} }
/** @Override
* This method processes one Relationship of an Item and will return a list of RelationshipMetadataValue objects public List<RelationshipMetadataValue> findRelationshipMetadataValueForItemRelationship(
* that are generated for this specific relationship for the item through the config in VirtualMetadataPopulator
*
* It returns a combination of the output of the findVirtualMetadataFromConfiguration method and
*
* @param context The context
* @param item The item whose virtual metadata is requested
* @param entityType The entity type of the given item
* @param relationship The relationship whose virtual metadata is requested
* @param enableVirtualMetadata Determines whether the VirtualMetadataPopulator should be used.
* If false, only the relation."relationname" metadata is populated
* If true, fields from the spring config virtual metadata is included as well
* @return The list of virtual metadata values
*/
private List<RelationshipMetadataValue> findRelationshipMetadataValueForItemRelationship(
Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata) Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata)
throws SQLException { throws SQLException {
List<RelationshipMetadataValue> resultingMetadataValueList = new LinkedList<>(); List<RelationshipMetadataValue> resultingMetadataValueList = new LinkedList<>();

View File

@@ -43,6 +43,8 @@ public class RelationshipServiceImpl implements RelationshipService {
@Autowired(required = true) @Autowired(required = true)
protected RelationshipTypeService relationshipTypeService; protected RelationshipTypeService relationshipTypeService;
@Autowired
private RelationshipMetadataService relationshipMetadataService;
@Autowired @Autowired
private VirtualMetadataPopulator virtualMetadataPopulator; private VirtualMetadataPopulator virtualMetadataPopulator;
@@ -61,6 +63,8 @@ public class RelationshipServiceImpl implements RelationshipService {
return create(c, leftItem, rightItem, relationshipType, leftPlace, rightPlace, null, null); return create(c, leftItem, rightItem, relationshipType, leftPlace, rightPlace, null, null);
} }
@Override @Override
public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType, public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType,
int leftPlace, int rightPlace, String leftwardValue, String rightwardValue) int leftPlace, int rightPlace, String leftwardValue, String rightwardValue)
@@ -81,8 +85,12 @@ public class RelationshipServiceImpl implements RelationshipService {
if (isRelationshipValidToCreate(context, relationship)) { if (isRelationshipValidToCreate(context, relationship)) {
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) || if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) { authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
updatePlaceInRelationship(context, relationship, true); // This order of execution should be handled in the creation (create, updateplace, update relationship)
return relationshipDAO.create(context, relationship); // for a proper place allocation
Relationship relationshipToReturn = relationshipDAO.create(context, relationship);
updatePlaceInRelationship(context, relationshipToReturn);
update(context, relationshipToReturn);
return relationshipToReturn;
} else { } else {
throw new AuthorizeException( throw new AuthorizeException(
"You do not have write rights on this relationship's items"); "You do not have write rights on this relationship's items");
@@ -94,18 +102,34 @@ public class RelationshipServiceImpl implements RelationshipService {
} }
@Override @Override
public void updatePlaceInRelationship(Context context, Relationship relationship, boolean isCreation) public void updatePlaceInRelationship(Context context, Relationship relationship)
throws SQLException, AuthorizeException { throws SQLException, AuthorizeException {
Item leftItem = relationship.getLeftItem(); Item leftItem = relationship.getLeftItem();
// Max value is used to ensure that these will get added to the back of the list and thus receive the highest
// (last) place as it's set to a -1 for creation
if (relationship.getLeftPlace() == -1) {
relationship.setLeftPlace(Integer.MAX_VALUE);
}
Item rightItem = relationship.getRightItem();
if (relationship.getRightPlace() == -1) {
relationship.setRightPlace(Integer.MAX_VALUE);
}
List<Relationship> leftRelationships = findByItemAndRelationshipType(context, List<Relationship> leftRelationships = findByItemAndRelationshipType(context,
leftItem, leftItem,
relationship.getRelationshipType(), true); relationship.getRelationshipType(), true);
Item rightItem = relationship.getRightItem();
List<Relationship> rightRelationships = findByItemAndRelationshipType(context, List<Relationship> rightRelationships = findByItemAndRelationshipType(context,
rightItem, rightItem,
relationship.getRelationshipType(), relationship.getRelationshipType(),
false); false);
// These relationships are only deleted from the temporary lists incase they're present in them so that we can
// properly perform our place calculation later down the line in this method.
if (leftRelationships.contains(relationship)) {
leftRelationships.remove(relationship);
}
if (rightRelationships.contains(relationship)) {
rightRelationships.remove(relationship);
}
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
//If useForPlace for the leftwardType is false for the relationshipType, //If useForPlace for the leftwardType is false for the relationshipType,
// we need to sort the relationships here based on leftplace. // we need to sort the relationships here based on leftplace.
@@ -141,10 +165,6 @@ public class RelationshipServiceImpl implements RelationshipService {
updateItem(context, rightItem); updateItem(context, rightItem);
} }
if (isCreation) {
handleCreationPlaces(context, relationship);
}
context.restoreAuthSystemState(); context.restoreAuthSystemState();
} }
@@ -156,43 +176,14 @@ public class RelationshipServiceImpl implements RelationshipService {
itemService.update(context, relatedItem); itemService.update(context, relatedItem);
} }
@Override
//Sets the places for the Relationship properly if the updatePlaceInRelationship was called for a new creation public int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException {
//of this Relationship return relationshipDAO.findNextLeftPlaceByLeftItem(context, item);
private void handleCreationPlaces(Context context, Relationship relationship) throws SQLException {
List<Relationship> leftRelationships;
List<Relationship> rightRelationships;
leftRelationships = findByItemAndRelationshipType(context,
relationship.getLeftItem(),
relationship.getRelationshipType(), true);
rightRelationships = findByItemAndRelationshipType(context,
relationship.getRightItem(),
relationship.getRelationshipType(),
false);
leftRelationships.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace());
rightRelationships.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace());
if (!leftRelationships.isEmpty()) {
relationship.setLeftPlace(leftRelationships.get(0).getLeftPlace() + 1);
} else {
relationship.setLeftPlace(0);
}
if (!rightRelationships.isEmpty()) {
relationship.setRightPlace(rightRelationships.get(0).getRightPlace() + 1);
} else {
relationship.setRightPlace(0);
}
} }
@Override @Override
public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { public int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException {
return relationshipDAO.findLeftPlaceByLeftItem(context, item); return relationshipDAO.findNextRightPlaceByRightItem(context, item);
}
@Override
public int findRightPlaceByRightItem(Context context, Item item) throws SQLException {
return relationshipDAO.findRightPlaceByRightItem(context, item);
} }
private boolean isRelationshipValidToCreate(Context context, Relationship relationship) throws SQLException { private boolean isRelationshipValidToCreate(Context context, Relationship relationship) throws SQLException {
@@ -326,12 +317,25 @@ public class RelationshipServiceImpl implements RelationshipService {
@Override @Override
public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException { public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException {
if (isRelationshipValidToDelete(context, relationship)) { //TODO: retrieve default settings from configuration
delete(context, relationship, false, false);
}
@Override
public void delete(Context context, Relationship relationship, boolean copyToLeftItem, boolean copyToRightItem)
throws SQLException, AuthorizeException {
log.info(org.dspace.core.LogManager.getHeader(context, "delete_relationship",
"relationship_id=" + relationship.getID() + "&" +
"copyMetadataValuesToLeftItem=" + copyToLeftItem + "&" +
"copyMetadataValuesToRightItem=" + copyToRightItem));
if (isRelationshipValidToDelete(context, relationship) &&
copyToItemPermissionCheck(context, relationship, copyToLeftItem, copyToRightItem)) {
// To delete a relationship, a user must have WRITE permissions on one of the related Items // To delete a relationship, a user must have WRITE permissions on one of the related Items
copyMetadataValues(context, relationship, copyToLeftItem, copyToRightItem);
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) || if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) { authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
relationshipDAO.delete(context, relationship); relationshipDAO.delete(context, relationship);
updatePlaceInRelationship(context, relationship, false); updatePlaceInRelationship(context, relationship);
} else { } else {
throw new AuthorizeException( throw new AuthorizeException(
"You do not have write rights on this relationship's items"); "You do not have write rights on this relationship's items");
@@ -342,6 +346,71 @@ public class RelationshipServiceImpl implements RelationshipService {
} }
} }
/**
* Converts virtual metadata from RelationshipMetadataValue objects to actual item metadata.
*
* @param context The relevant DSpace context
* @param relationship The relationship containing the left and right items
* @param copyToLeftItem The boolean indicating whether we want to write to left item or not
* @param copyToRightItem The boolean indicating whether we want to write to right item or not
*/
private void copyMetadataValues(Context context, Relationship relationship, boolean copyToLeftItem,
boolean copyToRightItem)
throws SQLException, AuthorizeException {
if (copyToLeftItem) {
String entityTypeString = relationshipMetadataService
.getEntityTypeStringFromMetadata(relationship.getLeftItem());
List<RelationshipMetadataValue> relationshipMetadataValues =
relationshipMetadataService.findRelationshipMetadataValueForItemRelationship(context,
relationship.getLeftItem(), entityTypeString, relationship, true);
for (RelationshipMetadataValue relationshipMetadataValue : relationshipMetadataValues) {
itemService.addMetadata(context, relationship.getLeftItem(),
relationshipMetadataValue.getMetadataField(), null,
relationshipMetadataValue.getValue() );
}
itemService.update(context, relationship.getLeftItem());
}
if (copyToRightItem) {
String entityTypeString = relationshipMetadataService
.getEntityTypeStringFromMetadata(relationship.getRightItem());
List<RelationshipMetadataValue> relationshipMetadataValues =
relationshipMetadataService.findRelationshipMetadataValueForItemRelationship(context,
relationship.getRightItem(), entityTypeString, relationship, true);
for (RelationshipMetadataValue relationshipMetadataValue : relationshipMetadataValues) {
itemService.addMetadata(context, relationship.getRightItem(),
relationshipMetadataValue.getMetadataField(), null,
relationshipMetadataValue.getValue() );
}
itemService.update(context, relationship.getRightItem());
}
}
/**
* This method will check if the current user has sufficient rights to write to the respective items if requested
* @param context The relevant DSpace context
* @param relationship The relationship containing the left and right items
* @param copyToLeftItem The boolean indicating whether we want to write to left item or not
* @param copyToRightItem The boolean indicating whether we want to write to right item or not
* @return A boolean indicating whether the permissions are okay for this request
* @throws AuthorizeException If something goes wrong
* @throws SQLException If something goes wrong
*/
private boolean copyToItemPermissionCheck(Context context, Relationship relationship,
boolean copyToLeftItem, boolean copyToRightItem) throws SQLException {
boolean isPermissionCorrect = true;
if (copyToLeftItem) {
if (!authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE)) {
isPermissionCorrect = false;
}
}
if (copyToRightItem) {
if (!authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
isPermissionCorrect = false;
}
}
return isPermissionCorrect;
}
private boolean isRelationshipValidToDelete(Context context, Relationship relationship) throws SQLException { private boolean isRelationshipValidToDelete(Context context, Relationship relationship) throws SQLException {
if (relationship == null) { if (relationship == null) {
log.warn("The relationship has been deemed invalid since the relation was null"); log.warn("The relationship has been deemed invalid since the relation was null");

View File

@@ -1,59 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.authority;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import org.dspace.content.Collection;
/**
* Sample Journal-name authority based on SHERPA/RoMEO
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOProtocol
*/
public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol {
private static final String RESULT = "journal";
private static final String LABEL = "jtitle";
private static final String AUTHORITY = "issn";
public SHERPARoMEOJournalTitle() {
super();
}
@Override
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
// punt if there is no query text
if (text == null || text.trim().length() == 0) {
return new Choices(true);
}
// query args to add to SHERPA/RoMEO request URL
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("jtitle", text));
args.add(new BasicNameValuePair("qtype", "contains")); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null) {
result = new Choices(true);
}
return result;
}
@Override
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
return getMatches(text, collection, start, limit, locale);
}
}

View File

@@ -1,228 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.core.ConfigurationManager;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Choice Authority based on SHERPA/RoMEO - for Publishers and Journals
* See the subclasses SHERPARoMEOPublisher and SHERPARoMEOJournalTitle
* for actual choice plugin implementations. This is a superclass
* containing all the common protocol logic.
*
* Reads these DSpace Config properties:
*
* # contact URL for server
* sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOPublisher
* @see SHERPARoMEOJournalTitle
*/
public abstract class SHERPARoMEOProtocol implements ChoiceAuthority {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPARoMEOProtocol.class);
// contact URL from configuration
private static String url = null;
public SHERPARoMEOProtocol() {
if (url == null) {
url = ConfigurationManager.getProperty("sherpa.romeo.url");
// sanity check
if (url == null) {
throw new IllegalStateException("Missing DSpace configuration keys for SHERPA/RoMEO Query");
}
}
}
// this implements the specific RoMEO API args and XML tag naming
public abstract Choices getMatches(String text, Collection collection, int start, int limit, String locale);
@Override
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
return getMatches(field, text, collection, 0, 2, locale);
}
// XXX FIXME just punt, returning value, never got around to
// implementing a reverse query.
@Override
public String getLabel(String field, String key, String locale) {
return key;
}
// NOTE - ignore limit and start for now
protected Choices query(String result, String label, String authority,
List<BasicNameValuePair> args, int start, int limit) {
HttpClient hc = new DefaultHttpClient();
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
HttpGet get = new HttpGet(srUrl);
log.debug("Trying SHERPA/RoMEO Query, URL=" + srUrl);
try {
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
SRHandler handler = new SRHandler(result, label, authority);
// XXX FIXME: should turn off validation here explicitly, but
// it seems to be off by default.
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
xr.parse(new InputSource(response.getEntity().getContent()));
int confidence;
if (handler.total == 0) {
confidence = Choices.CF_NOTFOUND;
} else if (handler.total == 1) {
confidence = Choices.CF_UNCERTAIN;
} else {
confidence = Choices.CF_AMBIGUOUS;
}
return new Choices(handler.result, start, handler.total, confidence, false);
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return null;
} catch (ParserConfigurationException e) {
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
} catch (SAXException e) {
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
} finally {
get.releaseConnection();
}
return null;
}
// SAX handler to grab SHERPA/RoMEO (and eventually other details) from result
private static class SRHandler
extends DefaultHandler {
private Choice result[] = null;
int rindex = 0; // result index
int total = 0;
// name of element containing a result, e.g. <journal>
private String resultElement = null;
// name of element containing the label e.g. <name>
private String labelElement = null;
// name of element containing the authority value e.g. <issn>
private String authorityElement = null;
protected String textValue = null;
public SRHandler(String result, String label, String authority) {
super();
resultElement = result;
labelElement = label;
authorityElement = authority;
}
// NOTE: text value MAY be presented in multiple calls, even if
// it all one word, so be ready to splice it together.
// BEWARE: subclass's startElement method should call super()
// to null out 'value'. (Don't you miss the method combination
// options of a real object system like CLOS?)
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String newValue = new String(ch, start, length);
if (newValue.length() > 0) {
if (textValue == null) {
textValue = newValue;
} else {
textValue += newValue;
}
}
}
// if this was the FIRST "numhits" element, it's size of results:
@Override
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException {
if (localName.equals("numhits")) {
String stotal = textValue.trim();
if (stotal.length() > 0) {
total = Integer.parseInt(stotal);
result = new Choice[total];
if (total > 0) {
result[0] = new Choice();
log.debug("Got " + total + " records in results.");
}
}
} else if (localName.equals(resultElement)) {
// after start of result element, get next hit ready
if (++rindex < result.length) {
result[rindex] = new Choice();
}
} else if (localName.equals(labelElement) && textValue != null) {
// plug in label value
result[rindex].value = textValue.trim();
result[rindex].label = result[rindex].value;
} else if (authorityElement != null && localName.equals(authorityElement) && textValue != null) {
// plug in authority value
result[rindex].authority = textValue.trim();
} else if (localName.equals("message") && textValue != null) {
// error message
log.warn("SHERPA/RoMEO response error message: " + textValue.trim());
}
}
// subclass overriding this MUST call it with super()
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException {
textValue = null;
}
@Override
public void error(SAXParseException exception)
throws SAXException {
throw new SAXException(exception);
}
@Override
public void fatalError(SAXParseException exception)
throws SAXException {
throw new SAXException(exception);
}
}
}

View File

@@ -1,61 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.authority;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import org.dspace.content.Collection;
/**
* Sample Publisher name authority based on SHERPA/RoMEO
*
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOProtocol
*/
public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol {
protected static final String RESULT = "publisher";
protected static final String LABEL = "name";
// note: the publisher records have nothing we can use as authority code.
protected static final String AUTHORITY = null;
public SHERPARoMEOPublisher() {
super();
}
@Override
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
// punt if there is no query text
if (text == null || text.trim().length() == 0) {
return new Choices(true);
}
// query args to add to SHERPA/RoMEO request URL
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("pub", text));
args.add(new BasicNameValuePair("qtype", "all")); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null) {
result = new Choices(true);
}
return result;
}
@Override
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
return getMatches(text, collection, start, limit, locale);
}
}

View File

@@ -22,6 +22,7 @@ import org.dspace.content.Community;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.Site; import org.dspace.content.Site;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.packager.DSpaceAIPIngester; import org.dspace.content.packager.DSpaceAIPIngester;
import org.dspace.content.packager.METSManifest; import org.dspace.content.packager.METSManifest;
@@ -195,7 +196,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
public Element disseminateElement(Context context, DSpaceObject dso) public Element disseminateElement(Context context, DSpaceObject dso)
throws CrosswalkException, IOException, SQLException, throws CrosswalkException, IOException, SQLException,
AuthorizeException { AuthorizeException {
List<MockMetadataValue> dc = new ArrayList<>(); List<MetadataValueDTO> dc = new ArrayList<>();
if (dso.getType() == Constants.ITEM) { if (dso.getType() == Constants.ITEM) {
Item item = (Item) dso; Item item = (Item) dso;
EPerson is = item.getSubmitter(); EPerson is = item.getSubmitter();
@@ -282,8 +283,8 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
return XSLTDisseminationCrosswalk.createDIM(dso, dc); return XSLTDisseminationCrosswalk.createDIM(dso, dc);
} }
private static MockMetadataValue makeDC(String element, String qualifier, String value) { private static MetadataValueDTO makeDC(String element, String qualifier, String value) {
MockMetadataValue dcv = new MockMetadataValue(); MetadataValueDTO dcv = new MetadataValueDTO();
dcv.setSchema("dc"); dcv.setSchema("dc");
dcv.setLanguage(null); dcv.setLanguage(null);
dcv.setElement(element); dcv.setElement(element);

View File

@@ -29,6 +29,7 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.Site; import org.dspace.content.Site;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService; import org.dspace.content.service.CommunityService;
@@ -327,7 +328,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
private List<Element> disseminateListInternal(DSpaceObject dso, boolean addSchema) private List<Element> disseminateListInternal(DSpaceObject dso, boolean addSchema)
throws CrosswalkException, IOException, SQLException, AuthorizeException { throws CrosswalkException, IOException, SQLException, AuthorizeException {
List<MockMetadataValue> dcvs = null; List<MetadataValueDTO> dcvs = null;
if (dso.getType() == Constants.ITEM) { if (dso.getType() == Constants.ITEM) {
dcvs = item2Metadata((Item) dso); dcvs = item2Metadata((Item) dso);
} else if (dso.getType() == Constants.COLLECTION) { } else if (dso.getType() == Constants.COLLECTION) {
@@ -344,7 +345,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
List<Element> result = new ArrayList<Element>(dcvs.size()); List<Element> result = new ArrayList<Element>(dcvs.size());
for (MockMetadataValue dcv : dcvs) { for (MetadataValueDTO dcv : dcvs) {
String qdc = dcv.getSchema() + "." + dcv.getElement(); String qdc = dcv.getSchema() + "." + dcv.getElement();
if (dcv.getQualifier() != null) { if (dcv.getQualifier() != null) {
qdc += "." + dcv.getQualifier(); qdc += "." + dcv.getQualifier();
@@ -418,8 +419,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param site The site to derive metadata from * @param site The site to derive metadata from
* @return list of metadata * @return list of metadata
*/ */
protected List<MockMetadataValue> site2Metadata(Site site) { protected List<MetadataValueDTO> site2Metadata(Site site) {
List<MockMetadataValue> metadata = new ArrayList<>(); List<MetadataValueDTO> metadata = new ArrayList<>();
String identifier_uri = handleService.getCanonicalPrefix() String identifier_uri = handleService.getCanonicalPrefix()
+ site.getHandle(); + site.getHandle();
@@ -449,8 +450,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param community The community to derive metadata from * @param community The community to derive metadata from
* @return list of metadata * @return list of metadata
*/ */
protected List<MockMetadataValue> community2Metadata(Community community) { protected List<MetadataValueDTO> community2Metadata(Community community) {
List<MockMetadataValue> metadata = new ArrayList<>(); List<MetadataValueDTO> metadata = new ArrayList<>();
String description = communityService.getMetadata(community, "introductory_text"); String description = communityService.getMetadata(community, "introductory_text");
String description_abstract = communityService.getMetadata(community, "short_description"); String description_abstract = communityService.getMetadata(community, "short_description");
@@ -492,8 +493,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param collection The collection to derive metadata from * @param collection The collection to derive metadata from
* @return list of metadata * @return list of metadata
*/ */
protected List<MockMetadataValue> collection2Metadata(Collection collection) { protected List<MetadataValueDTO> collection2Metadata(Collection collection) {
List<MockMetadataValue> metadata = new ArrayList<>(); List<MetadataValueDTO> metadata = new ArrayList<>();
String description = collectionService.getMetadata(collection, "introductory_text"); String description = collectionService.getMetadata(collection, "introductory_text");
String description_abstract = collectionService.getMetadata(collection, "short_description"); String description_abstract = collectionService.getMetadata(collection, "short_description");
@@ -546,19 +547,19 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param item The item to derive metadata from * @param item The item to derive metadata from
* @return list of metadata * @return list of metadata
*/ */
protected List<MockMetadataValue> item2Metadata(Item item) { protected List<MetadataValueDTO> item2Metadata(Item item) {
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
Item.ANY); Item.ANY);
List<MockMetadataValue> result = new ArrayList<>(); List<MetadataValueDTO> result = new ArrayList<>();
for (MetadataValue metadataValue : dcvs) { for (MetadataValue metadataValue : dcvs) {
result.add(new MockMetadataValue(metadataValue)); result.add(new MetadataValueDTO(metadataValue));
} }
return result; return result;
} }
protected MockMetadataValue createDCValue(String element, String qualifier, String value) { protected MetadataValueDTO createDCValue(String element, String qualifier, String value) {
MockMetadataValue dcv = new MockMetadataValue(); MetadataValueDTO dcv = new MetadataValueDTO();
dcv.setSchema("dc"); dcv.setSchema("dc");
dcv.setElement(element); dcv.setElement(element);
dcv.setQualifier(qualifier); dcv.setQualifier(qualifier);

View File

@@ -1,101 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.crosswalk;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
/**
* Metadata Value is bound to a database, the dissemination crosswalk require mock metadata just need for desimanation
* This class provides a wrapper for this.
* This class should only be used for the dissemniation metadata values that aren't to be written to the database
*
* @author kevinvandevelde at atmire.com
*/
public class MockMetadataValue {
private String schema;
private String element;
private String qualifier;
private String language;
private String value;
private String authority;
private int confidence;
public MockMetadataValue(MetadataValue metadataValue) {
MetadataField metadataField = metadataValue.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
schema = metadataSchema.getName();
element = metadataField.getElement();
qualifier = metadataField.getQualifier();
language = metadataValue.getLanguage();
value = metadataValue.getValue();
authority = metadataValue.getAuthority();
confidence = metadataValue.getConfidence();
}
public MockMetadataValue() {
}
public String getSchema() {
return schema;
}
public String getElement() {
return element;
}
public String getQualifier() {
return qualifier;
}
public String getValue() {
return value;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setValue(String value) {
this.value = value;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public int getConfidence() {
return confidence;
}
public void setConfidence(int confidence) {
this.confidence = confidence;
}
}

View File

@@ -31,6 +31,7 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.Site; import org.dspace.content.Site;
import org.dspace.content.authority.Choices; import org.dspace.content.authority.Choices;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService; import org.dspace.content.service.CommunityService;
@@ -307,13 +308,13 @@ public class XSLTDisseminationCrosswalk
* @param dcvs list of metadata * @param dcvs list of metadata
* @return element * @return element
*/ */
public static Element createDIM(DSpaceObject dso, List<MockMetadataValue> dcvs) { public static Element createDIM(DSpaceObject dso, List<MetadataValueDTO> dcvs) {
Element dim = new Element("dim", DIM_NS); Element dim = new Element("dim", DIM_NS);
String type = Constants.typeText[dso.getType()]; String type = Constants.typeText[dso.getType()];
dim.setAttribute("dspaceType", type); dim.setAttribute("dspaceType", type);
for (int i = 0; i < dcvs.size(); i++) { for (int i = 0; i < dcvs.size(); i++) {
MockMetadataValue dcv = dcvs.get(i); MetadataValueDTO dcv = dcvs.get(i);
Element field = Element field =
createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(), createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(),
dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence()); dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence());
@@ -390,12 +391,12 @@ public class XSLTDisseminationCrosswalk
} }
} }
protected static List<MockMetadataValue> item2Metadata(Item item) { protected static List<MetadataValueDTO> item2Metadata(Item item) {
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
Item.ANY); Item.ANY);
List<MockMetadataValue> result = new ArrayList<>(); List<MetadataValueDTO> result = new ArrayList<>();
for (MetadataValue metadataValue : dcvs) { for (MetadataValue metadataValue : dcvs) {
result.add(new MockMetadataValue(metadataValue)); result.add(new MetadataValueDTO(metadataValue));
} }
return result; return result;

View File

@@ -0,0 +1,57 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
import org.dspace.scripts.Process;
/**
* This is the Data Access Object for the {@link Process} object
*/
public interface ProcessDAO extends GenericDAO<Process> {
/**
* This method will return all the Process objects in the database in a list and it'll be sorted by script name
* @param context The relevant DSpace context
* @return The list of all Process objects in the database sorted on scriptname
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByScript(Context context) throws SQLException;
/**
* This method will return all the Process objects in the database in a list and it'll be sorted by start time.
* The most recent one will be shown first
* @param context The relevant DSpace context
* @return The list of all Process objects in the database sorted by starttime
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByStartTime(Context context) throws SQLException;
/**
* Returns a list of all Process objects in the database
* @param context The relevant DSpace context
* @param limit The limit for the amount of Processes returned
* @param offset The offset for the Processes to be returned
* @return The list of all Process objects in the Database
* @throws SQLException If something goes wrong
*/
List<Process> findAll(Context context, int limit, int offset) throws SQLException;
/**
* Returns the total amount of Process objects in the dataase
* @param context The relevant DSpace context
* @return An integer that describes the amount of Process objects in the database
* @throws SQLException If something goes wrong
*/
int countRows(Context context) throws SQLException;
}

View File

@@ -51,26 +51,26 @@ public interface RelationshipDAO extends GenericDAO<Relationship> {
List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset) throws SQLException; List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset) throws SQLException;
/** /**
* This method returns the highest leftplace integer for all the relationships where this * This method returns the next leftplace integer to use for a relationship with this item as the leftItem
* item is the leftitem so that we can set a proper leftplace attribute on the next relationship *
* @param context The relevant DSpace context * @param context The relevant DSpace context
* @param item The item to be matched on leftItem * @param item The item to be matched on leftItem
* @return The integer for the highest leftPlace value for all the relatonship objects * @return The next integer to be used for the leftplace of a relationship with the given item
* that have the given item as leftItem * as a left item
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException; int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException;
/** /**
* This method returns the highest rightplace integer for all the relationships where this * This method returns the next rightplace integer to use for a relationship with this item as the rightItem
* item is the rightitem so that we can set a proper rightplace attribute on the next relationship *
* @param context The relevant DSpace context * @param context The relevant DSpace context
* @param item The item to be matched on rightItem * @param item The item to be matched on rightItem
* @return The integer for the highest rightPlace value for all the relatonship objects * @return The next integer to be used for the rightplace of a relationship with the given item
* that have the given item as rightItem * as a right item
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
int findRightPlaceByRightItem(Context context, Item item) throws SQLException; int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException;
/** /**
* This method returns a list of Relationship objects for the given RelationshipType object. * This method returns a list of Relationship objects for the given RelationshipType object.
@@ -157,7 +157,6 @@ public interface RelationshipDAO extends GenericDAO<Relationship> {
List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset) List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset)
throws SQLException; throws SQLException;
/** /**
* Count total number of relationships (rows in relationship table) * Count total number of relationships (rows in relationship table)
* *

View File

@@ -9,7 +9,6 @@ package org.dspace.content.dao.impl;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -64,11 +63,20 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> imple
public List<Collection> findAll(Context context, MetadataField order, Integer limit, Integer offset) public List<Collection> findAll(Context context, MetadataField order, Integer limit, Integer offset)
throws SQLException { throws SQLException {
StringBuilder query = new StringBuilder(); StringBuilder query = new StringBuilder();
query.append("SELECT ").append(Collection.class.getSimpleName()).append(" FROM Collection as ")
.append(Collection.class.getSimpleName()).append(" ");
addMetadataLeftJoin(query, Collection.class.getSimpleName(), Arrays.asList(order));
addMetadataSortQuery(query, Arrays.asList(order), null);
// The query has to be rather complex because we want to sort the retrieval of Collections based on the title
// We'll join the Collections with the metadata fields on the sortfield specified in the parameters
// then we'll sort on this metadata field (this is usually the title). We're also making sure that the place
// is the lowest place in the metadata fields list so that we avoid the duplication bug
query.append("SELECT c" +
" FROM Collection c" +
" left join c.metadata title on title.metadataField = :sortField and" +
" title.dSpaceObject = c.id and" +
" title.place = (select min(internal.place) " +
"from c.metadata internal " +
"where internal.metadataField = :sortField and" +
" internal.dSpaceObject = c.id)" +
" ORDER BY LOWER(title.value)");
Query hibernateQuery = createQuery(context, query.toString()); Query hibernateQuery = createQuery(context, query.toString());
if (offset != null) { if (offset != null) {
hibernateQuery.setFirstResult(offset); hibernateQuery.setFirstResult(offset);
@@ -76,7 +84,7 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> imple
if (limit != null) { if (limit != null) {
hibernateQuery.setMaxResults(limit); hibernateQuery.setMaxResults(limit);
} }
hibernateQuery.setParameter(order.toString(), order.getID()); hibernateQuery.setParameter("sortField", order);
return list(hibernateQuery); return list(hibernateQuery);
} }

View File

@@ -0,0 +1,75 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao.impl;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.dao.ProcessDAO;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
import org.dspace.scripts.Process;
import org.dspace.scripts.Process_;
/**
* Implementation class for {@link ProcessDAO}
*/
public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements ProcessDAO {
@Override
public List<Process> findAllSortByScript(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.asc(processRoot.get(Process_.name)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
@Override
public List<Process> findAllSortByStartTime(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.desc(processRoot.get(Process_.startTime)),
criteriaBuilder.desc(processRoot.get(Process_.processId)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
@Override
public List<Process> findAll(Context context, int limit, int offset) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
return list(context, criteriaQuery, false, Process.class, limit, offset);
}
@Override
public int countRows(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
return count(context, criteriaQuery, criteriaBuilder, processRoot);
}
}

View File

@@ -61,7 +61,7 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO<Relationship> impl
} }
@Override @Override
public int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException { public int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class); Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
@@ -70,25 +70,25 @@ public class RelationshipDAOImpl extends AbstractHibernateDAO<Relationship> impl
List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1); List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1);
list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace());
if (!list.isEmpty()) { if (!list.isEmpty()) {
return list.get(0).getLeftPlace(); return list.get(0).getLeftPlace() + 1;
} else { } else {
return 1; return 0;
} }
} }
@Override @Override
public int findRightPlaceByRightItem(Context context, Item item) throws SQLException { public int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class); CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class); Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot); criteriaQuery.select(relationshipRoot);
criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)); criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item));
List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1); List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1);
list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace()); list.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace());
if (!list.isEmpty()) { if (!list.isEmpty()) {
return list.get(0).getLeftPlace(); return list.get(0).getRightPlace() + 1;
} else { } else {
return 1; return 0;
} }
} }

View File

@@ -0,0 +1,139 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dto;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
/**
* This class acts as Data transfer object in which we can store data like in a regular MetadataValue object, but this
* one isn't saved in the DB. This can freely be used to represent Metadata without it being saved in the database,
* this will typically be used when transferring data
*
* @author kevinvandevelde at atmire.com
*/
public class MetadataValueDTO {
private String schema;
private String element;
private String qualifier;
private String language;
private String value;
private String authority;
private int confidence = Choices.CF_UNSET;
public MetadataValueDTO(MetadataValue metadataValue) {
MetadataField metadataField = metadataValue.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
schema = metadataSchema.getName();
element = metadataField.getElement();
qualifier = metadataField.getQualifier();
language = metadataValue.getLanguage();
value = metadataValue.getValue();
authority = metadataValue.getAuthority();
confidence = metadataValue.getConfidence();
}
public MetadataValueDTO() {
}
/**
* Constructor for the MetadataValueDTO class
* @param schema The schema to be assigned to this MetadataValueDTO object
* @param element The element to be assigned to this MetadataValueDTO object
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
* @param language The language to be assigend to this MetadataValueDTO object
* @param value The value to be assigned to this MetadataValueDTO object
* @param authority The authority to be assigned to this MetadataValueDTO object
* @param confidence The confidence to be assigned to this MetadataValueDTO object
*/
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value,
String authority, int confidence) {
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
this.authority = authority;
this.confidence = confidence;
}
/**
* Constructor for the MetadataValueDTO class
* @param schema The schema to be assigned to this MetadataValueDTO object
* @param element The element to be assigned to this MetadataValueDTO object
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
* @param language The language to be assigend to this MetadataValueDTO object
* @param value The value to be assigned to this MetadataValueDTO object
*/
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value) {
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
}
public String getSchema() {
return schema;
}
public String getElement() {
return element;
}
public String getQualifier() {
return qualifier;
}
public String getValue() {
return value;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setValue(String value) {
this.value = value;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public int getConfidence() {
return confidence;
}
public void setConfidence(int confidence) {
this.confidence = confidence;
}
}

View File

@@ -109,6 +109,31 @@ public interface BundleService extends DSpaceObjectService<Bundle>, DSpaceObject
public List<ResourcePolicy> getBundlePolicies(Context context, Bundle bundle) throws SQLException; public List<ResourcePolicy> getBundlePolicies(Context context, Bundle bundle) throws SQLException;
/**
* Moves a bitstream within a bundle from one place to another, shifting all other bitstreams in the process
*
* @param context DSpace Context
* @param bundle The bitstream bundle
* @param from The index of the bitstream to move
* @param to The index to move the bitstream to
* @throws AuthorizeException when an SQL error has occurred (querying DSpace)
* @throws SQLException If the user can't make the changes
*/
public void updateBitstreamOrder(Context context, Bundle bundle, int from, int to) throws AuthorizeException,
SQLException;
/**
* Moves a bitstream from its current bundle to a new target bundle
* @param context DSpace Context
* @param targetBundle The target bundle where bitstream will be moved to
* @param bitstream The bitstream being moved
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @throws IOException if IO error
*/
public void moveBitstreamToBundle(Context context, Bundle targetBundle, Bitstream bitstream) throws SQLException,
AuthorizeException, IOException;
/** /**
* Changes bitstream order according to the array * Changes bitstream order according to the array
* *

View File

@@ -74,26 +74,26 @@ public interface RelationshipService extends DSpaceCRUDService<Relationship> {
public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException; public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException;
/** /**
* Retrieves the highest integer value for the leftplace property of a Relationship for all relationships * This method returns the next leftplace integer to use for a relationship with this item as the leftItem
* that have the given item as a left item *
* @param context The relevant DSpace context * @param context The relevant DSpace context
* @param item The item that has to be the leftItem of a relationship for it to qualify * @param item The item that has to be the leftItem of a relationship for it to qualify
* @return The integer value of the highest left place property of all relationships * @return The next integer to be used for the leftplace of a relationship with the given item
* that have the given item as a leftitem property * as a left item
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
int findLeftPlaceByLeftItem(Context context, Item item) throws SQLException; int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException;
/** /**
* Retrieves the highest integer value for the rightplace property of a Relationship for all relationships * This method returns the next rightplace integer to use for a relationship with this item as the rightItem
* that have the given item as a right item *
* @param context The relevant DSpace context * @param context The relevant DSpace context
* @param item The item that has to be the rightitem of a relationship for it to qualify * @param item The item that has to be the rightitem of a relationship for it to qualify
* @return The integer value of the highest right place property of all relationships * @return The next integer to be used for the rightplace of a relationship with the given item
* that have the given item as a rightitem property * as a right item
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
int findRightPlaceByRightItem(Context context, Item item) throws SQLException; int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException;
/** /**
* This method returns a list of Relationships for which the leftItem or rightItem is equal to the given * This method returns a list of Relationships for which the leftItem or rightItem is equal to the given
@@ -147,10 +147,9 @@ public interface RelationshipService extends DSpaceCRUDService<Relationship> {
* @param context The relevant DSpace context * @param context The relevant DSpace context
* @param relationship The Relationship object that will have it's place updated and that will be used * @param relationship The Relationship object that will have it's place updated and that will be used
* to retrieve the other relationships whose place might need to be updated * to retrieve the other relationships whose place might need to be updated
* @param isCreation Is the relationship new or did it already exist
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
public void updatePlaceInRelationship(Context context, Relationship relationship, boolean isCreation) public void updatePlaceInRelationship(Context context, Relationship relationship)
throws SQLException, AuthorizeException; throws SQLException, AuthorizeException;
/** /**
@@ -305,4 +304,15 @@ public interface RelationshipService extends DSpaceCRUDService<Relationship> {
*/ */
int countByTypeName(Context context, String typeName) int countByTypeName(Context context, String typeName)
throws SQLException; throws SQLException;
/**
* This method is used to delete a Relationship whilst given the possibility to copy the Virtual Metadata created
* by this relationship to the left and/or right item
* @param context The relevant DSpace context
* @param relationship The relationship to be deleted
* @param copyToLeftItem A boolean indicating whether we should copy metadata to the left item or not
* @param copyToRightItem A boolean indicating whether we should copy metadata to the right item or not
*/
void delete(Context context, Relationship relationship, boolean copyToLeftItem, boolean copyToRightItem)
throws SQLException, AuthorizeException;
} }

View File

@@ -13,11 +13,8 @@ import java.util.Iterator;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser; import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection; import org.dspace.content.Collection;
import org.dspace.content.Community; import org.dspace.content.Community;
import org.dspace.content.Item; import org.dspace.content.Item;
@@ -26,103 +23,26 @@ import org.dspace.content.service.ItemService;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.scripts.DSpaceRunnable;
import org.springframework.beans.factory.annotation.Autowired;
/** /**
* Class used to reindex dspace communities/collections/items into discovery * Class used to reindex dspace communities/collections/items into discovery
*
* @author Kevin Van de Velde (kevin at atmire dot com)
* @author Mark Diggory (markd at atmire dot com)
* @author Ben Bosman (ben at atmire dot com)
*/ */
public class IndexClient { public class IndexClient extends DSpaceRunnable {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(IndexClient.class); private Context context;
/** @Autowired
* Default constructor private IndexingService indexer;
*/
private IndexClient() { }
/** private IndexClientOptions indexClientOptions;
* When invoked as a command-line tool, creates, updates, removes content
* from the whole index
*
* @param args the command-line arguments, none used
* @throws SQLException An exception that provides information on a database access error or other errors.
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SearchServiceException if something went wrong with querying the solr server
*/
public static void main(String[] args) throws SQLException, IOException, SearchServiceException {
Context context = new Context(Context.Mode.READ_ONLY); @Override
context.turnOffAuthorisationSystem(); public void internalRun() throws Exception {
if (indexClientOptions == IndexClientOptions.HELP) {
String usage = "org.dspace.discovery.IndexClient [-cbhf] | [-r <handle>] | [-i <handle>] or nothing to " + printHelp();
"update/clean an existing index."; return;
Options options = new Options();
HelpFormatter formatter = new HelpFormatter();
CommandLine line = null;
options.addOption(OptionBuilder
.withArgName("handle to remove")
.hasArg(true)
.withDescription(
"remove an Item, Collection or Community from index based on its handle")
.create("r"));
options.addOption(OptionBuilder
.withArgName("handle or uuid to add or update")
.hasArg(true)
.withDescription(
"add or update an Item, Collection or Community based on its handle or uuid")
.create("i"));
options.addOption(OptionBuilder
.isRequired(false)
.withDescription(
"clean existing index removing any documents that no longer exist in the db")
.create("c"));
options.addOption(OptionBuilder
.isRequired(false)
.withDescription(
"(re)build index, wiping out current one if it exists")
.create("b"));
options.addOption(OptionBuilder
.isRequired(false)
.withDescription(
"Rebuild the spellchecker, can be combined with -b and -f.")
.create("s"));
options.addOption(OptionBuilder
.isRequired(false)
.withDescription(
"if updating existing index, force each handle to be reindexed even if uptodate")
.create("f"));
options.addOption(OptionBuilder
.isRequired(false)
.withDescription(
"print this help message")
.create("h"));
options.addOption(OptionBuilder.isRequired(false).withDescription(
"optimize search core").create("o"));
try {
line = new PosixParser().parse(options, args);
} catch (Exception e) {
// automatically generate the help statement
formatter.printHelp(usage, e.getMessage(), options, "");
System.exit(1);
}
if (line.hasOption("h")) {
// automatically generate the help statement
formatter.printHelp(usage, options);
System.exit(1);
} }
/** Acquire from dspace-services in future */ /** Acquire from dspace-services in future */
@@ -130,28 +50,29 @@ public class IndexClient {
* new DSpace.getServiceManager().getServiceByName("org.dspace.discovery.SolrIndexer"); * new DSpace.getServiceManager().getServiceByName("org.dspace.discovery.SolrIndexer");
*/ */
IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName( if (indexClientOptions == IndexClientOptions.REMOVE) {
IndexingService.class.getName(), handler.logInfo("Removing " + commandLine.getOptionValue("r") + " from Index");
IndexingService.class indexer.unIndexContent(context, commandLine.getOptionValue("r"));
); } else if (indexClientOptions == IndexClientOptions.CLEAN) {
handler.logInfo("Cleaning Index");
if (line.hasOption("r")) { indexer.cleanIndex(false);
log.info("Removing " + line.getOptionValue("r") + " from Index"); } else if (indexClientOptions == IndexClientOptions.FORCECLEAN) {
indexer.unIndexContent(context, line.getOptionValue("r")); handler.logInfo("Cleaning Index");
} else if (line.hasOption("c")) { indexer.cleanIndex(true);
log.info("Cleaning Index"); } else if (indexClientOptions == IndexClientOptions.BUILD ||
indexer.cleanIndex(line.hasOption("f")); indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
} else if (line.hasOption("b")) { handler.logInfo("(Re)building index from scratch.");
log.info("(Re)building index from scratch.");
indexer.createIndex(context); indexer.createIndex(context);
checkRebuildSpellCheck(line, indexer); if (indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
} else if (line.hasOption("o")) { checkRebuildSpellCheck(commandLine, indexer);
log.info("Optimizing search core."); }
} else if (indexClientOptions == IndexClientOptions.OPTIMIZE) {
handler.logInfo("Optimizing search core.");
indexer.optimize(); indexer.optimize();
} else if (line.hasOption('s')) { } else if (indexClientOptions == IndexClientOptions.SPELLCHECK) {
checkRebuildSpellCheck(line, indexer); checkRebuildSpellCheck(commandLine, indexer);
} else if (line.hasOption('i')) { } else if (indexClientOptions == IndexClientOptions.INDEX) {
final String param = line.getOptionValue('i'); final String param = commandLine.getOptionValue('i');
UUID uuid = null; UUID uuid = null;
try { try {
uuid = UUID.fromString(param); uuid = UUID.fromString(param);
@@ -176,19 +97,50 @@ public class IndexClient {
if (dso == null) { if (dso == null) {
throw new IllegalArgumentException("Cannot resolve " + param + " to a DSpace object"); throw new IllegalArgumentException("Cannot resolve " + param + " to a DSpace object");
} }
log.info("Indexing " + param + " force " + line.hasOption("f")); handler.logInfo("Indexing " + param + " force " + commandLine.hasOption("f"));
final long startTimeMillis = System.currentTimeMillis(); final long startTimeMillis = System.currentTimeMillis();
final long count = indexAll(indexer, ContentServiceFactory.getInstance().getItemService(), context, dso); final long count = indexAll(indexer, ContentServiceFactory.getInstance().getItemService(), context,
dso);
final long seconds = (System.currentTimeMillis() - startTimeMillis) / 1000; final long seconds = (System.currentTimeMillis() - startTimeMillis) / 1000;
log.info("Indexed " + count + " object" + (count > 1 ? "s" : "") + " in " + seconds + " seconds"); handler.logInfo("Indexed " + count + " object" + (count > 1 ? "s" : "") + " in " + seconds + " seconds");
} else { } else if (indexClientOptions == IndexClientOptions.UPDATE ||
log.info("Updating and Cleaning Index"); indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
indexer.cleanIndex(line.hasOption("f")); handler.logInfo("Updating and Cleaning Index");
indexer.updateIndex(context, line.hasOption("f")); indexer.cleanIndex(false);
checkRebuildSpellCheck(line, indexer); indexer.updateIndex(context, false);
if (indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
} else if (indexClientOptions == IndexClientOptions.FORCEUPDATE ||
indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
handler.logInfo("Updating and Cleaning Index");
indexer.cleanIndex(true);
indexer.updateIndex(context, true);
if (indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
} }
log.info("Done with indexing"); handler.logInfo("Done with indexing");
}
public void setup() throws ParseException {
try {
context = new Context(Context.Mode.READ_ONLY);
context.turnOffAuthorisationSystem();
} catch (Exception e) {
throw new ParseException("Unable to create a new DSpace Context: " + e.getMessage());
}
indexClientOptions = IndexClientOptions.getIndexClientOption(commandLine);
}
/**
* Constructor for this class. This will ensure that the Options are created and set appropriately.
*/
private IndexClient() {
Options options = IndexClientOptions.constructOptions();
this.options = options;
} }
/** /**
@@ -273,13 +225,12 @@ public class IndexClient {
* @param line the command line options * @param line the command line options
* @param indexer the solr indexer * @param indexer the solr indexer
* @throws SearchServiceException in case of a solr exception * @throws SearchServiceException in case of a solr exception
* @throws java.io.IOException passed through * @throws IOException passed through
*/ */
protected static void checkRebuildSpellCheck(CommandLine line, IndexingService indexer) protected void checkRebuildSpellCheck(CommandLine line, IndexingService indexer)
throws SearchServiceException, IOException { throws SearchServiceException, IOException {
if (line.hasOption("s")) { handler.logInfo("Rebuilding spell checker.");
log.info("Rebuilding spell checker.");
indexer.buildSpellCheck(); indexer.buildSpellCheck();
} }
}
} }

View File

@@ -0,0 +1,97 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
/**
* This Enum holds all the possible options and combinations for the Index discovery script
*/
public enum IndexClientOptions {
REMOVE,
CLEAN,
FORCECLEAN,
BUILD,
BUILDANDSPELLCHECK,
OPTIMIZE,
SPELLCHECK,
INDEX,
UPDATE,
FORCEUPDATE,
UPDATEANDSPELLCHECK,
FORCEUPDATEANDSPELLCHECK,
HELP;
/**
* This method resolves the CommandLine parameters to figure out which action the index-discovery script should
* perform
* @param commandLine The relevant CommandLine for the index-discovery script
* @return The index-discovery option to be ran, parsed from the CommandLine
*/
protected static IndexClientOptions getIndexClientOption(CommandLine commandLine) {
if (commandLine.hasOption("h")) {
return IndexClientOptions.HELP;
} else if (commandLine.hasOption("r")) {
return IndexClientOptions.REMOVE;
} else if (commandLine.hasOption("c")) {
if (commandLine.hasOption("f")) {
return IndexClientOptions.FORCECLEAN;
} else {
return IndexClientOptions.CLEAN;
}
} else if (commandLine.hasOption("b")) {
if (commandLine.hasOption("s")) {
return IndexClientOptions.BUILDANDSPELLCHECK;
} else {
return IndexClientOptions.BUILD;
}
} else if (commandLine.hasOption("o")) {
return IndexClientOptions.OPTIMIZE;
} else if (commandLine.hasOption("s")) {
return IndexClientOptions.SPELLCHECK;
} else if (commandLine.hasOption("i")) {
return IndexClientOptions.INDEX;
} else {
if (commandLine.hasOption("f") && commandLine.hasOption("s")) {
return IndexClientOptions.FORCEUPDATEANDSPELLCHECK;
} else if (commandLine.hasOption("f")) {
return IndexClientOptions.FORCEUPDATE;
} else if (commandLine.hasOption("s")) {
return IndexClientOptions.UPDATEANDSPELLCHECK;
} else {
return IndexClientOptions.UPDATE;
}
}
}
protected static Options constructOptions() {
Options options = new Options();
options
.addOption("r", "remove", true, "remove an Item, Collection or Community from index based on its handle");
options.getOption("r").setType(String.class);
options.addOption("i", "index", true,
"add or update an Item, Collection or Community based on its handle or uuid");
options.getOption("i").setType(boolean.class);
options.addOption("c", "clean", false,
"clean existing index removing any documents that no longer exist in the db");
options.getOption("c").setType(boolean.class);
options.addOption("b", "build", false, "(re)build index, wiping out current one if it exists");
options.getOption("b").setType(boolean.class);
options.addOption("s", "spellchecker", false, "Rebuild the spellchecker, can be combined with -b and -f.");
options.getOption("s").setType(boolean.class);
options.addOption("f", "force", false,
"if updating existing index, force each handle to be reindexed even if uptodate");
options.getOption("f").setType(boolean.class);
options.addOption("h", "help", false, "print this help message");
options.getOption("h").setType(boolean.class);
return options;
}
}

View File

@@ -5,7 +5,7 @@
* *
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.authority.rest; package org.dspace.external;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner; import java.util.Scanner;
@@ -23,16 +23,16 @@ import org.apache.logging.log4j.Logger;
* @author Ben Bosman (ben at atmire dot com) * @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com) * @author Mark Diggory (markd at atmire dot com)
*/ */
public class RESTConnector { public class OrcidRestConnector {
/** /**
* log4j logger * log4j logger
*/ */
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RESTConnector.class); private static Logger log = org.apache.logging.log4j.LogManager.getLogger(OrcidRestConnector.class);
private String url; private String url;
public RESTConnector(String url) { public OrcidRestConnector(String url) {
this.url = url; this.url = url;
} }

View File

@@ -0,0 +1,34 @@
/**
* 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.external.factory;
import org.dspace.external.service.ExternalDataService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Abstract factory to get services for the External package. Use ExternalServiceFactory.getInstance() to retrieve
* an implementation
*/
public abstract class ExternalServiceFactory {
/**
* Calling this method will provide an ExternalDataService bean
* @return An implementation of the ExternalDataService
*/
public abstract ExternalDataService getExternalDataService();
/**
* This method will provide you with an implementation of this class to work with
* @return An implementation of this class to work with
*/
public static ExternalServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("externalServiceFactory", ExternalServiceFactory.class);
}
}

View File

@@ -0,0 +1,26 @@
/**
* 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.external.factory;
import org.dspace.external.service.ExternalDataService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Abstract factory to get services for the External package. Use ExternalServiceFactory.getInstance() to retrieve
* an implementation
*/
public class ExternalServiceFactoryImpl extends ExternalServiceFactory {
@Autowired(required = true)
private ExternalDataService externalDataService;
@Override
public ExternalDataService getExternalDataService() {
return externalDataService;
}
}

View File

@@ -0,0 +1,146 @@
/**
* 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.external.model;
import java.util.LinkedList;
import java.util.List;
import org.dspace.content.dto.MetadataValueDTO;
/**
* The representation model object for external data
*/
public class ExternalDataObject {
/**
* This field determines the ID for the ExternalDataObject
*/
private String id;
/**
* This field determines the value for the ExternalDataObject
*/
private String value;
/**
* This field determines where the ExternalData came from
*/
private String source;
/**
* The list of Metadata values. These our MetadataValueDTO because they won't exist in the DB
*/
private List<MetadataValueDTO> metadata = new LinkedList<>();
/**
* The display value of the ExternalDataObject
*/
private String displayValue;
/**
* Default constructor
*/
public ExternalDataObject() {
}
/**
* Constructor for the ExternalDataObject with as parameter the source of where it came from
* @param source The source where the ExternalDataObject came from
*/
public ExternalDataObject(String source) {
this.source = source;
}
/**
* Generic getter for the source
* @return The source
*/
public String getSource() {
return source;
}
/**
* Generic setter for the source
* @param source The source to be set
*/
public void setSource(String source) {
this.source = source;
}
/**
* Generic getter for the Metadata
* @return The metadata
*/
public List<MetadataValueDTO> getMetadata() {
return metadata;
}
/**
* Generic setter for the Metadata
* @param metadata The metadata to be set
*/
public void setMetadata(List<MetadataValueDTO> metadata) {
this.metadata = metadata;
}
/**
* This method will add a Metadata value to the list of metadata values
* @param metadataValueDTO The metadatavalue to be added
*/
public void addMetadata(MetadataValueDTO metadataValueDTO) {
if (metadata == null) {
metadata = new LinkedList<>();
}
metadata.add(metadataValueDTO);
}
/**
* Generic getter for the display value
* @return The display value
*/
public String getDisplayValue() {
return displayValue;
}
/**
* Generic setter for the display value
* @param displayValue The display value to be set
*/
public void setDisplayValue(String displayValue) {
this.displayValue = displayValue;
}
/**
* Generic getter for the ID
* @return The id
*/
public String getId() {
return id;
}
/**
* Generic setter for the ID
* @param id The id to be set
*/
public void setId(String id) {
this.id = id;
}
/**
* Generic getter for the value
* @return the value value of this ExternalDataObject
*/
public String getValue() {
return value;
}
/**
* Generic setter for the value
* @param value The value to be set on this ExternalDataObject
*/
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -0,0 +1,60 @@
/**
* 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.external.provider;
import java.util.List;
import java.util.Optional;
import org.dspace.external.model.ExternalDataObject;
/**
* This interface should be implemented by all providers that will deal with external data
*/
public interface ExternalDataProvider {
/**
* This method will return the SourceIdentifier for the ExternalDataProvider that implements the interface
* @return The source identifier as a String
*/
public String getSourceIdentifier();
/**
* This method will take a String id as a parameter and it'll call the ExternalDataProvider's endpoint or data
* source to retrieve and build the ExternalDataObject
* @param id The id on which will be searched
* @return An Optional object of ExternalDataObject. This is to indicate that this object may be null.
* This ExternalDataObject will return all the data returned by the ExternalDataProvider
*/
Optional<ExternalDataObject> getExternalDataObject(String id);
/**
* This method will query the ExternalDataProvider's endpoint or data source to retrieve and build a list of
* ExternalDataObjects through a search with the given parameters
* @param query The query for the search
* @param start The start of the search
* @param limit The max amount of records to be returned by the search
* @return A list of ExternalDataObjects that were retrieved and built by this search
*/
List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit);
/**
* This method will return a boolean indicating whether this ExternalDataProvider can deal with the given source
* or not
* @param source The source on which the check needs to be done
* @return A boolean indicating whether this ExternalDataProvider can deal with this source or not
*/
public boolean supports(String source);
/**
* Returns the total amount of results that this source can return for the given query
* @param query The query to be search on and give the total amount of results
* @return The total amount of results that the source can return for the given query
*/
public int getNumberOfResults(String query);
}

View File

@@ -5,27 +5,32 @@
* *
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.content.authority; package org.dspace.external.provider.impl;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.content.DCPersonName; import org.dspace.content.DCPersonName;
import org.dspace.core.ConfigurationManager; import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@@ -51,16 +56,14 @@ import org.xml.sax.helpers.DefaultHandler;
* *
* lcname.url = http://alcme.oclc.org/srw/search/lcnaf * lcname.url = http://alcme.oclc.org/srw/search/lcnaf
* *
* TODO: make # of results to ask for (and return) configurable.
*
* @author Larry Stone * @author Larry Stone
* @version $Revision $ * @version $Revision $
*/ */
public class LCNameAuthority implements ChoiceAuthority { public class LCNameDataProvider implements ExternalDataProvider {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(LCNameAuthority.class); private static final Logger log = LogManager.getLogger(LCNameDataProvider.class);
// get these from configuration private String url;
protected static String url = null; private String sourceIdentifier;
// NS URI for SRU respones // NS URI for SRU respones
protected static final String NS_SRU = "http://www.loc.gov/zing/srw/"; protected static final String NS_SRU = "http://www.loc.gov/zing/srw/";
@@ -68,53 +71,53 @@ public class LCNameAuthority implements ChoiceAuthority {
// NS URI for MARC/XML // NS URI for MARC/XML
protected static final String NS_MX = "http://www.loc.gov/MARC21/slim"; protected static final String NS_MX = "http://www.loc.gov/MARC21/slim";
// constructor does static init too..
public LCNameAuthority() {
if (url == null) {
url = ConfigurationManager.getProperty("lcname.url");
// sanity check public String getSourceIdentifier() {
if (url == null) { return sourceIdentifier;
throw new IllegalStateException("Missing DSpace configuration keys for LCName Query"); }
}
} public Optional<ExternalDataObject> getExternalDataObject(String id) {
StringBuilder query = new StringBuilder();
query.append("local.LCCN = \"").append(id).append("\"");
List<ExternalDataObject> list = doLookup(0, 10, query);
if (list.size() > 0) {
return Optional.of(list.get(0));
} else {
return Optional.empty();
} }
// punt! this is a poor implementation..
@Override
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
return getMatches(field, text, collection, 0, 2, locale);
} }
/** /**
* Match a proposed value against name authority records * Generic getter for the url
* Value is assumed to be in "Lastname, Firstname" format. * @return the url value of this LCNameDataProvider
*/ */
@Override public String getUrl() {
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) { return url;
Choices result = queryPerson(text, start, limit);
if (result == null) {
result = new Choices(true);
}
return result;
}
// punt; supposed to get the canonical display form of a metadata authority key
// XXX FIXME implement this with a query on the authority key, cache results
@Override
public String getLabel(String field, String key, String locale) {
return key;
} }
/** /**
* Guts of the implementation, returns a complete Choices result, or * Generic setter for the url
* null for a failure. * @param url The url to be set on this LCNameDataProvider
*/ */
private Choices queryPerson(String text, int start, int limit) { public void setUrl(String url) {
this.url = url;
}
/**
* Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this LCNameDataProvider
*/
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String text, int start, int limit) {
// punt if there is no query text // punt if there is no query text
if (text == null || text.trim().length() == 0) { if (text == null || text.trim().length() == 0) {
return new Choices(true); return Collections.EMPTY_LIST;
} }
// 1. build CQL query // 1. build CQL query
@@ -123,12 +126,51 @@ public class LCNameAuthority implements ChoiceAuthority {
query.append("local.FirstName = \"").append(pn.getFirstNames()). query.append("local.FirstName = \"").append(pn.getFirstNames()).
append("\" and local.FamilyName = \"").append(pn.getLastName()). append("\" and local.FamilyName = \"").append(pn.getLastName()).
append("\""); append("\"");
return doLookup(start, limit, query);
}
private List<ExternalDataObject> doLookup(int start, int limit, StringBuilder query) {
// XXX arbitrary default limit - should be configurable? // XXX arbitrary default limit - should be configurable?
if (limit == 0) { if (limit == 0) {
limit = 50; limit = 50;
} }
HttpGet get = constructHttpGet(query, start, limit);
// 2. web request
try {
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SRUHandler handler = parseResponseToSRUHandler(response);
// this probably just means more results available..
if (handler.hits != handler.result.size()) {
log.warn("Discrepency in results, result.length=" + handler.result.size() +
", yet expected results=" + handler.hits);
}
return handler.result;
}
} catch (IOException e) {
log.error("SRU query failed: ", e);
return Collections.EMPTY_LIST;
} catch (ParserConfigurationException e) {
log.warn("Failed parsing SRU result: ", e);
return Collections.EMPTY_LIST;
} catch (SAXException e) {
log.warn("Failed parsing SRU result: ", e);
return Collections.EMPTY_LIST;
} finally {
get.releaseConnection();
}
return Collections.EMPTY_LIST;
}
public boolean supports(String source) {
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
}
private HttpGet constructHttpGet(StringBuilder query, int start, int limit) {
URI sruUri; URI sruUri;
try { try {
URIBuilder builder = new URIBuilder(url); URIBuilder builder = new URIBuilder(url);
@@ -141,21 +183,55 @@ public class LCNameAuthority implements ChoiceAuthority {
sruUri = builder.build(); sruUri = builder.build();
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
log.error("SRU query failed: ", e); log.error("SRU query failed: ", e);
return new Choices(true); return null;
} }
HttpGet get = new HttpGet(sruUri); HttpGet get = new HttpGet(sruUri);
log.debug("Trying SRU query, URL=" + sruUri); log.debug("Trying SRU query, URL=" + sruUri);
return get;
}
@Override
public int getNumberOfResults(String query) {
// punt if there is no query text
if (query == null || query.trim().length() == 0) {
return 0;
}
// 1. build CQL query
DCPersonName pn = new DCPersonName(query);
StringBuilder queryStringBuilder = new StringBuilder();
queryStringBuilder.append("local.FirstName = \"").append(pn.getFirstNames()).
append("\" and local.FamilyName = \"").append(pn.getLastName()).
append("\"");
HttpGet get = constructHttpGet(queryStringBuilder, 0, 1);
// 2. web request // 2. web request
try { try {
HttpClient hc = new DefaultHttpClient(); HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get); HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) { if (response.getStatusLine().getStatusCode() == 200) {
SRUHandler handler = parseResponseToSRUHandler(response);
return handler.hits;
}
} catch (IOException | ParserConfigurationException | SAXException e) {
log.warn("Failed parsing SRU result: ", e);
return 0;
} finally {
get.releaseConnection();
}
return 0;
}
private SRUHandler parseResponseToSRUHandler(HttpResponse response)
throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser(); SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader(); XMLReader xr = sp.getXMLReader();
SRUHandler handler = new SRUHandler(); SRUHandler handler = new SRUHandler(sourceIdentifier);
// XXX FIXME: should turn off validation here explicitly, but // XXX FIXME: should turn off validation here explicitly, but
// it seems to be off by default. // it seems to be off by default.
@@ -165,42 +241,7 @@ public class LCNameAuthority implements ChoiceAuthority {
HttpEntity responseBody = response.getEntity(); HttpEntity responseBody = response.getEntity();
xr.parse(new InputSource(responseBody.getContent())); xr.parse(new InputSource(responseBody.getContent()));
// this probably just means more results available.. return handler;
if (handler.hits != handler.result.size()) {
log.warn("Discrepency in results, result.length=" + handler.result.size() +
", yet expected results=" + handler.hits);
}
boolean more = handler.hits > (start + handler.result.size());
// XXX add non-auth option; perhaps the UI should do this?
// XXX it's really a policy matter if they allow unauth result.
// XXX good, stop it.
// handler.result.add(new Choice("", text, "Non-Authority: \""+text+"\""));
int confidence;
if (handler.hits == 0) {
confidence = Choices.CF_NOTFOUND;
} else if (handler.hits == 1) {
confidence = Choices.CF_UNCERTAIN;
} else {
confidence = Choices.CF_AMBIGUOUS;
}
return new Choices(handler.result.toArray(new Choice[handler.result.size()]),
start, handler.hits, confidence, more);
}
} catch (IOException e) {
log.error("SRU query failed: ", e);
return new Choices(true);
} catch (ParserConfigurationException e) {
log.warn("Failed parsing SRU result: ", e);
return new Choices(true);
} catch (SAXException e) {
log.warn("Failed parsing SRU result: ", e);
return new Choices(true);
} finally {
get.releaseConnection();
}
return new Choices(true);
} }
/** /**
@@ -212,14 +253,21 @@ public class LCNameAuthority implements ChoiceAuthority {
*/ */
private static class SRUHandler private static class SRUHandler
extends DefaultHandler { extends DefaultHandler {
private List<Choice> result = new ArrayList<Choice>(); private String sourceIdentifier;
private List<ExternalDataObject> result = new ArrayList<ExternalDataObject>();
private int hits = -1; private int hits = -1;
private String textValue = null; private String textValue = null;
private String name = null; private String name = null;
private String birthDate = null;
private String lccn = null; private String lccn = null;
private String lastTag = null; private String lastTag = null;
private String lastCode = null; private String lastCode = null;
public SRUHandler(String sourceIdentifier) {
super();
this.sourceIdentifier = sourceIdentifier;
}
// NOTE: text value MAY be presented in multiple calls, even if // NOTE: text value MAY be presented in multiple calls, even if
// it all one word, so be ready to splice it together. // it all one word, so be ready to splice it together.
// BEWARE: subclass's startElement method should call super() // BEWARE: subclass's startElement method should call super()
@@ -259,14 +307,33 @@ public class LCNameAuthority implements ChoiceAuthority {
name = name.substring(0, name.length() - 1); name = name.substring(0, name.length() - 1);
} }
// XXX DEBUG ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
// log.debug("Got result, name="+name+", lccn="+lccn); externalDataObject.setDisplayValue(name);
result.add(new Choice(lccn, name, name)); externalDataObject.setValue(name);
externalDataObject.setId(lccn);
String[] names = name.split(", ");
String familyName = names[0];
String givenName = names.length > 1 ? names[1] : null;
if (StringUtils.isNotBlank(familyName)) {
externalDataObject
.addMetadata(new MetadataValueDTO("person", "familyName", null, null, familyName));
}
if (StringUtils.isNotBlank(givenName)) {
externalDataObject
.addMetadata(new MetadataValueDTO("person", "givenName", null, null, givenName));
}
if (StringUtils.isNotBlank(birthDate)) {
externalDataObject
.addMetadata(new MetadataValueDTO("person", "date", "birth", null, birthDate));
}
externalDataObject.addMetadata(new MetadataValueDTO("person", "identifier", "lccn", null, lccn));
result.add(externalDataObject);
} else { } else {
log.warn("Got anomalous result, at least one of these null: lccn=" + lccn + ", name=" + name); log.warn("Got anomalous result, at least one of these null: lccn=" + lccn + ", name=" + name);
} }
name = null; name = null;
lccn = null; lccn = null;
birthDate = null;
} else if (localName.equals("subfield") && namespaceURI.equals(NS_MX)) { } else if (localName.equals("subfield") && namespaceURI.equals(NS_MX)) {
if (lastTag != null && lastCode != null) { if (lastTag != null && lastCode != null) {
if (lastTag.equals("010") && lastCode.equals("a")) { if (lastTag.equals("010") && lastCode.equals("a")) {
@@ -276,9 +343,8 @@ public class LCNameAuthority implements ChoiceAuthority {
// 100.a is the personal name // 100.a is the personal name
name = textValue; name = textValue;
} }
if (lastTag.equals("100") && lastCode.equals("d")) {
if (lastTag.equals("100") && lastCode.equals("d") && (name != null)) { birthDate = textValue;
name = name + " " + textValue;
} }
} }
} }

View File

@@ -0,0 +1,280 @@
/**
* 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.external.provider.impl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.OrcidRestConnector;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
import org.dspace.external.provider.orcid.xml.XMLtoBio;
import org.json.JSONObject;
import org.orcid.jaxb.model.common_v2.OrcidId;
import org.orcid.jaxb.model.record_v2.Person;
import org.orcid.jaxb.model.search_v2.Result;
import org.springframework.beans.factory.annotation.Required;
/**
* This class is the implementation of the ExternalDataProvider interface that will deal with the OrcidV2 External
* Data lookup
*/
public class OrcidV2AuthorDataProvider implements ExternalDataProvider {
private static Logger log = LogManager.getLogger(OrcidV2AuthorDataProvider.class);
private OrcidRestConnector orcidRestConnector;
private String OAUTHUrl;
private String clientId;
private String clientSecret;
private String accessToken;
private String sourceIdentifier;
private String orcidUrl;
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
@Override
public String getSourceIdentifier() {
return sourceIdentifier;
}
/**
* Initialize the accessToken that is required for all subsequent calls to ORCID.
*
* @throws java.io.IOException passed through from HTTPclient.
*/
public void init() throws IOException {
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) {
String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials";
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse getResponse = httpClient.execute(httpPost);
JSONObject responseObject = null;
try (InputStream is = getResponse.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String inputStr;
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
try {
responseObject = new JSONObject(inputStr);
} catch (Exception e) {
//Not as valid as I'd hoped, move along
responseObject = null;
}
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
accessToken = (String) responseObject.get("access_token");
}
}
}
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private OrcidV2AuthorDataProvider(String url) {
this.orcidRestConnector = new OrcidRestConnector(url);
}
@Override
public Optional<ExternalDataObject> getExternalDataObject(String id) {
Person person = getBio(id);
ExternalDataObject externalDataObject = convertToExternalDataObject(person);
return Optional.of(externalDataObject);
}
protected ExternalDataObject convertToExternalDataObject(Person person) {
ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
String lastName = "";
String firstName = "";
if (person.getName().getFamilyName() != null) {
lastName = person.getName().getFamilyName().getValue();
externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null,
lastName));
}
if (person.getName().getGivenNames() != null) {
firstName = person.getName().getGivenNames().getValue();
externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null,
firstName));
}
externalDataObject.setId(person.getName().getPath());
externalDataObject
.addMetadata(new MetadataValueDTO("dc", "identifier", "orcid", null, person.getName().getPath()));
externalDataObject
.addMetadata(new MetadataValueDTO("dc", "identifier", "uri", null, orcidUrl + person.getName().getPath()));
if (!StringUtils.isBlank(lastName) && !StringUtils.isBlank(firstName)) {
externalDataObject.setDisplayValue(lastName + ", " + firstName);
externalDataObject.setValue(lastName + ", " + firstName);
} else if (StringUtils.isBlank(firstName)) {
externalDataObject.setDisplayValue(lastName);
externalDataObject.setValue(lastName);
} else if (StringUtils.isBlank(lastName)) {
externalDataObject.setDisplayValue(firstName);
externalDataObject.setValue(firstName);
}
return externalDataObject;
}
/**
* Retrieve a Person object based on a given orcid identifier
* @param id orcid identifier
* @return Person
*/
public Person getBio(String id) {
log.debug("getBio called with ID=" + id);
if (!isValid(id)) {
return null;
}
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
XMLtoBio converter = new XMLtoBio();
Person person = converter.convertSinglePerson(bioDocument);
try {
bioDocument.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return person;
}
/**
* Check to see if the provided text has the correct ORCID syntax.
* Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a
* blank result anyway
*/
private boolean isValid(String text) {
return StringUtils.isNotBlank(text) && text.matches(ORCID_ID_SYNTAX);
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
if (limit > 100) {
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
}
String searchPath = "search?q=" + URLEncoder.encode(query) + "&start=" + start + "&rows=" + limit;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
List<Result> results = converter.convert(bioDocument);
List<Person> bios = new LinkedList<>();
for (Result result : results) {
OrcidId orcidIdentifier = result.getOrcidIdentifier();
if (orcidIdentifier != null) {
log.debug("Found OrcidId=" + orcidIdentifier.toString());
String orcid = orcidIdentifier.getUriPath();
Person bio = getBio(orcid);
if (bio != null) {
bios.add(bio);
}
}
}
try {
bioDocument.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
if (bios == null) {
return Collections.emptyList();
} else {
return bios.stream().map(bio -> convertToExternalDataObject(bio)).collect(Collectors.toList());
}
}
@Override
public boolean supports(String source) {
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
}
@Override
public int getNumberOfResults(String query) {
String searchPath = "search?q=" + URLEncoder.encode(query) + "&start=" + 0 + "&rows=" + 0;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = orcidRestConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
return converter.getNumberOfResultsFromXml(bioDocument);
}
/**
* Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this OrcidV2AuthorDataProvider
*/
@Required
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
/**
* Generic getter for the orcidUrl
* @return the orcidUrl value of this OrcidV2AuthorDataProvider
*/
public String getOrcidUrl() {
return orcidUrl;
}
/**
* Generic setter for the orcidUrl
* @param orcidUrl The orcidUrl to be set on this OrcidV2AuthorDataProvider
*/
@Required
public void setOrcidUrl(String orcidUrl) {
this.orcidUrl = orcidUrl;
}
/**
* Generic setter for the OAUTHUrl
* @param OAUTHUrl The OAUTHUrl to be set on this OrcidV2AuthorDataProvider
*/
public void setOAUTHUrl(String OAUTHUrl) {
this.OAUTHUrl = OAUTHUrl;
}
/**
* Generic setter for the clientId
* @param clientId The clientId to be set on this OrcidV2AuthorDataProvider
*/
public void setClientId(String clientId) {
this.clientId = clientId;
}
/**
* Generic setter for the clientSecret
* @param clientSecret The clientSecret to be set on this OrcidV2AuthorDataProvider
*/
public void setClientSecret(String clientSecret) {
this.clientSecret = clientSecret;
}
}

View File

@@ -0,0 +1,236 @@
/**
* 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.external.provider.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger;
import org.dspace.app.sherpa.SHERPAJournal;
import org.dspace.app.sherpa.SHERPAResponse;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
/**
* This class is the implementation of the ExternalDataProvider interface that will deal with SherpaJournal External
* data lookups
*/
public class SherpaJournalDataProvider implements ExternalDataProvider {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SherpaJournalDataProvider.class);
private String url;
private String sourceIdentifier;
private String apiKey;
private CloseableHttpClient client = null;
@Override
public String getSourceIdentifier() {
return sourceIdentifier;
}
/**
* Initialise the client that we need to call the endpoint
* @throws IOException If something goes wrong
*/
public void init() throws IOException {
HttpClientBuilder builder = HttpClientBuilder.create();
// httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
// not to hammer the SHERPA service too much.
client = builder
.disableAutomaticRetries()
.setMaxConnTotal(5)
.build();
}
@Override
public Optional<ExternalDataObject> getExternalDataObject(String id) {
HttpGet method = null;
SHERPAResponse sherpaResponse = null;
int timeout = 5000;
URIBuilder uriBuilder = null;
try {
uriBuilder = new URIBuilder(url);
uriBuilder.addParameter("jtitle", id);
if (StringUtils.isNotBlank(apiKey)) {
uriBuilder.addParameter("ak", apiKey);
}
method = new HttpGet(uriBuilder.build());
method.setConfig(RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build());
// Execute the method.
HttpResponse response = client.execute(method);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
+ statusCode);
}
HttpEntity responseBody = response.getEntity();
if (null != responseBody) {
sherpaResponse = new SHERPAResponse(responseBody.getContent());
} else {
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
}
} catch (Exception e) {
log.error("SHERPA/RoMEO query failed: ", e);
}
if (sherpaResponse == null) {
sherpaResponse = new SHERPAResponse(
"Error processing the SHERPA/RoMEO answer");
}
if (CollectionUtils.isNotEmpty(sherpaResponse.getJournals())) {
SHERPAJournal sherpaJournal = sherpaResponse.getJournals().get(0);
ExternalDataObject externalDataObject = constructExternalDataObjectFromSherpaJournal(sherpaJournal);
return Optional.of(externalDataObject);
}
return null;
}
private ExternalDataObject constructExternalDataObjectFromSherpaJournal(SHERPAJournal sherpaJournal) {
ExternalDataObject externalDataObject = new ExternalDataObject();
externalDataObject.setSource(sourceIdentifier);
externalDataObject.setId(sherpaJournal.getTitle());
externalDataObject
.addMetadata(new MetadataValueDTO("dc", "title", null, null, sherpaJournal.getTitle()));
externalDataObject
.addMetadata(new MetadataValueDTO("dc", "identifier", "issn", null, sherpaJournal.getIssn()));
externalDataObject.setValue(sherpaJournal.getTitle());
externalDataObject.setDisplayValue(sherpaJournal.getTitle());
return externalDataObject;
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
// query args to add to SHERPA/RoMEO request URL
HttpGet get = constructHttpGet(query);
try {
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
List<ExternalDataObject> list = sherpaResponse.getJournals().stream().map(
sherpaJournal -> constructExternalDataObjectFromSherpaJournal(sherpaJournal)).collect(
Collectors.toList());
// This is because Sherpa returns everything by default so we can't specifiy a start and limit
// in the query itself
return list.subList(start, Math.min(start + limit, list.size()));
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return null;
} finally {
get.releaseConnection();
}
return null;
}
private HttpGet constructHttpGet(String query) {
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("jtitle", query));
args.add(new BasicNameValuePair("qtype", "contains"));
args.add(new BasicNameValuePair("ak", apiKey));
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
return new HttpGet(srUrl);
}
@Override
public boolean supports(String source) {
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
}
@Override
public int getNumberOfResults(String query) {
HttpGet get = constructHttpGet(query);
try {
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
return sherpaResponse.getNumHits();
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return 0;
} finally {
get.releaseConnection();
}
return 0;
}
/**
* Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this SherpaJournalDataProvider
*/
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
/**
* Generic getter for the url
* @return the url value of this SherpaJournalDataProvider
*/
public String getUrl() {
return url;
}
/**
* Generic setter for the url
* @param url The url to be set on this SherpaJournalDataProvider
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Generic getter for the apiKey
* @return the apiKey value of this SherpaJournalDataProvider
*/
public String getApiKey() {
return apiKey;
}
/**
* Generic setter for the apiKey
* @param apiKey The apiKey to be set on this SherpaJournalDataProvider
*/
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -0,0 +1,194 @@
/**
* 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.external.provider.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger;
import org.dspace.app.sherpa.SHERPAPublisher;
import org.dspace.app.sherpa.SHERPAResponse;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
/**
* This class is the implementation of the ExternalDataProvider interface that will deal with SherpaPublisher External
* data lookups
*/
public class SherpaPublisherDataProvider implements ExternalDataProvider {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SherpaPublisherDataProvider.class);
private String sourceIdentifier;
private String url;
private String apiKey;
@Override
public String getSourceIdentifier() {
return sourceIdentifier;
}
@Override
public Optional<ExternalDataObject> getExternalDataObject(String id) {
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("id", id));
args.add(new BasicNameValuePair("ak", apiKey));
HttpClient hc = new DefaultHttpClient();
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
HttpGet get = new HttpGet(srUrl);
try {
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
List<SHERPAPublisher> list = sherpaResponse.getPublishers();
if (CollectionUtils.isNotEmpty(list)) {
return Optional.of(constructExternalDataObjectFromSherpaPublisher(list.get(0)));
}
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return null;
} finally {
get.releaseConnection();
}
return null;
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
HttpGet get = constructHttpGet(query);
try {
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
List<ExternalDataObject> list = sherpaResponse.getPublishers().stream().map(
sherpaPublisher -> constructExternalDataObjectFromSherpaPublisher(sherpaPublisher)).collect(
Collectors.toList());
// This is because Sherpa returns everything by default so we can't specifiy a start and limit
// in the query itself
return list.subList(start, Math.min(start + limit, list.size()));
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return null;
} finally {
get.releaseConnection();
}
return null;
}
private HttpGet constructHttpGet(String query) {
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("pub", query));
args.add(new BasicNameValuePair("qtype", "all"));
args.add(new BasicNameValuePair("ak", apiKey));
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
return new HttpGet(srUrl);
}
private ExternalDataObject constructExternalDataObjectFromSherpaPublisher(SHERPAPublisher sherpaPublisher) {
ExternalDataObject externalDataObject = new ExternalDataObject();
externalDataObject.setSource(sourceIdentifier);
//Text value == name
externalDataObject.addMetadata(new MetadataValueDTO("dc", "title", null, null, sherpaPublisher.getName()));
externalDataObject.setDisplayValue(sherpaPublisher.getName());
externalDataObject.setValue(sherpaPublisher.getName());
if (StringUtils.isNotBlank(sherpaPublisher.getId())) {
externalDataObject.setId(sherpaPublisher.getId());
externalDataObject
.addMetadata(
new MetadataValueDTO("dc", "identifier", "sherpaPublisher", null, sherpaPublisher.getId()));
}
//Text value == homeurl
externalDataObject
.addMetadata(new MetadataValueDTO("dc", "identifier", "other", null, sherpaPublisher.getHomeurl()));
return externalDataObject;
}
@Override
public boolean supports(String source) {
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
}
@Override
public int getNumberOfResults(String query) {
HttpGet get = constructHttpGet(query);
try {
HttpClient hc = new DefaultHttpClient();
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SHERPAResponse sherpaResponse = new SHERPAResponse(response.getEntity().getContent());
return sherpaResponse.getNumHits();
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return 0;
} finally {
get.releaseConnection();
}
return 0;
}
/**
* Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this SherpaPublisherDataProvider
*/
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
/**
* Generic getter for the url
* @return the url value of this SherpaPublisherDataProvider
*/
public String getUrl() {
return url;
}
/**
* Generic setter for the url
* @param url The url to be set on this SherpaPublisherDataProvider
*/
public void setUrl(String url) {
this.url = url;
}
/**
* Generic getter for the apiKey
* @return the apiKey value of this SherpaPublisherDataProvider
*/
public String getApiKey() {
return apiKey;
}
/**
* Generic setter for the apiKey
* @param apiKey The apiKey to be set on this SherpaPublisherDataProvider
*/
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
}

View File

@@ -5,11 +5,10 @@
* *
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.authority.orcid.xml; package org.dspace.external.provider.orcid.xml;
import java.io.InputStream; import java.io.InputStream;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException; import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller; import javax.xml.bind.Unmarshaller;

View File

@@ -5,7 +5,7 @@
* *
* http://www.dspace.org/license/ * http://www.dspace.org/license/
*/ */
package org.dspace.authority.orcid.xml; package org.dspace.external.provider.orcid.xml;
import java.io.InputStream; import java.io.InputStream;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -13,9 +13,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authority.orcid.Orcidv2;
import org.dspace.utils.DSpace;
import org.orcid.jaxb.model.common_v2.OrcidId;
import org.orcid.jaxb.model.record_v2.Person; import org.orcid.jaxb.model.record_v2.Person;
import org.orcid.jaxb.model.search_v2.Result; import org.orcid.jaxb.model.search_v2.Result;
import org.orcid.jaxb.model.search_v2.Search; import org.orcid.jaxb.model.search_v2.Search;
@@ -27,7 +24,7 @@ import org.xml.sax.SAXException;
* @author Ben Bosman (ben at atmire dot com) * @author Ben Bosman (ben at atmire dot com)
* @author Mark Diggory (markd at atmire dot com) * @author Mark Diggory (markd at atmire dot com)
*/ */
public class XMLtoBio extends Converter { public class XMLtoBio extends Converter<List<Result>> {
/** /**
* log4j logger * log4j logger
@@ -35,29 +32,26 @@ public class XMLtoBio extends Converter {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(XMLtoBio.class); private static Logger log = org.apache.logging.log4j.LogManager.getLogger(XMLtoBio.class);
@Override @Override
public List<Person> convert(InputStream xml) { public List<Result> convert(InputStream xml) {
List<Person> bios = new ArrayList<>(); List<Result> bios = new ArrayList<>();
try { try {
Orcidv2 connector = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class);
Search search = (Search) unmarshall(xml, Search.class); Search search = (Search) unmarshall(xml, Search.class);
for (Result result : search.getResult()) { bios = search.getResult();
OrcidId orcidIdentifier = result.getOrcidIdentifier();
if (orcidIdentifier != null) {
log.debug("Found OrcidId=" + orcidIdentifier.toString());
String orcid = orcidIdentifier.getUriPath();
Person bio = connector.getBio(orcid);
if (bio != null) {
bios.add(bio);
}
}
}
} catch (SAXException | URISyntaxException e) { } catch (SAXException | URISyntaxException e) {
log.error(e); log.error(e);
} }
return bios; return bios;
} }
public int getNumberOfResultsFromXml(InputStream xml) {
try {
Search search = (Search) unmarshall(xml, Search.class);
return search.getNumFound().intValue();
} catch (SAXException | URISyntaxException e) {
log.error(e);
}
return 0;
}
public Person convertSinglePerson(InputStream xml) { public Person convertSinglePerson(InputStream xml) {
Person person = null; Person person = null;
try { try {

View File

@@ -0,0 +1,62 @@
/**
* 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.external.service;
import java.util.List;
import java.util.Optional;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
/**
* This is an interface that will deal with all Service level calls for External Data
*/
public interface ExternalDataService {
/**
* This method will return a list of ExternalDataProvider objects defined by all ExternalDataProvider spring beans
* @return A list of all ExternalDataProvider objects
*/
public List<ExternalDataProvider> getExternalDataProviders();
/**
* This method will return a single ExternalDataProvider which will support the given sourceIdentifier param
* @param sourceIdentifier The source identifier that the ExternalDataProvider that will be returned by this
* method has to support
* @return The ExternalDataProvider that supports the given source identifier
*/
public ExternalDataProvider getExternalDataProvider(String sourceIdentifier);
/**
* This method will return an Optional instance of ExternalDataObject for the given source and identifier
* It will try to retrieve one through an ExternalDataProvider as defined by the source with the given identifier
* @param source The source in which the lookup will be done
* @param identifier The identifier which will be looked up
* @return An Optional instance of ExternalDataObject
*/
public Optional<ExternalDataObject> getExternalDataObject(String source, String identifier);
/**
* This method will return a list of ExternalDataObjects as defined through the source in which they will be
* searched for, the given query start and limit parameters
* @param source The source that defines which ExternalDataProvider is to be used
* @param query The query for which the search will be done
* @param start The start of the search
* @param limit The maximum amount of records to be returned by the search
* @return A list of ExternalDataObjects that obey the rules in the parameters
*/
public List<ExternalDataObject> searchExternalDataObjects(String source, String query, int start, int limit);
/**
* This method wil return the total amount of results that will be found for the given query in the given source
* @param source The source in which the query will happen to return the number of results
* @param query The query to be ran in this source to retrieve the total amount of results
* @return The total amount of results that can be returned for this query in the given source
*/
public int getNumberOfResults(String source, String query);
}

View File

@@ -0,0 +1,68 @@
/**
* 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.external.service.impl;
import java.util.List;
import java.util.Optional;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
import org.dspace.external.service.ExternalDataService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Implementation of {@link ExternalDataService}
*/
public class ExternalDataServiceImpl implements ExternalDataService {
@Autowired
private List<ExternalDataProvider> externalDataProviders;
@Override
public Optional<ExternalDataObject> getExternalDataObject(String source, String id) {
ExternalDataProvider provider = getExternalDataProvider(source);
if (provider == null) {
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
}
return provider.getExternalDataObject(id);
}
@Override
public List<ExternalDataObject> searchExternalDataObjects(String source, String query, int start, int limit) {
ExternalDataProvider provider = getExternalDataProvider(source);
if (provider == null) {
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
}
return provider.searchExternalDataObjects(query, start, limit);
}
@Override
public List<ExternalDataProvider> getExternalDataProviders() {
return externalDataProviders;
}
@Override
public ExternalDataProvider getExternalDataProvider(String sourceIdentifier) {
for (ExternalDataProvider externalDataProvider : externalDataProviders) {
if (externalDataProvider.supports(sourceIdentifier)) {
return externalDataProvider;
}
}
return null;
}
@Override
public int getNumberOfResults(String source, String query) {
ExternalDataProvider provider = getExternalDataProvider(source);
if (provider == null) {
throw new IllegalArgumentException("Provider for: " + source + " couldn't be found");
}
return provider.getNumberOfResults(query);
}
}

View File

@@ -13,11 +13,11 @@ import java.sql.SQLException;
import java.util.Iterator; import java.util.Iterator;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.launcher.ScriptLauncher;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataValueService; import org.dspace.content.service.MetadataValueService;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.discovery.IndexClient;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
@@ -139,7 +139,7 @@ public class UpdateHandlePrefix {
try { try {
// Reinitialise the search and browse system // Reinitialise the search and browse system
IndexClient.main(new String[] {"-b"}); ScriptLauncher.main(new String[] {"index-discovery", "-b"});
System.out.println("Browse and search indexes are ready now."); System.out.println("Browse and search indexes are ready now.");
// All done // All done
System.out.println("\nAll done successfully. Please check the DSpace logs!\n"); System.out.println("\nAll done successfully. Please check the DSpace logs!\n");

View File

@@ -0,0 +1,108 @@
/**
* 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.scripts;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
/**
* This class serves as a representation of a command line parameter by holding a String name and a String value
*/
public class DSpaceCommandLineParameter {
private String name;
private String value;
public static String SEPARATOR = "|||";
/**
* This constructor will take a String key and String value and store them in their appriopriate fields
* @param key The String value to be stored as the name of the parameter
* @param value The String value to be stored as the value of the parameter
*/
public DSpaceCommandLineParameter(String key, String value) {
this.name = key;
if (StringUtils.isBlank(value)) {
this.value = null;
} else {
this.value = value;
}
}
/**
* This constructors accepts a single parameter String that is defined as e.g. "-c test" and it'll parse this
* String into the key "-c" and value "test" to then call the other constructor with those parameters
* @param parameter The String parameter
*/
protected DSpaceCommandLineParameter(String parameter) {
this(StringUtils.substringBefore(parameter, " "), StringUtils.substringAfter(parameter, " "));
}
public String getName() {
return name;
}
public void setName(String key) {
this.name = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
/**
* Converts the DSpaceCommandLineParameter into a String format by concatenating the value and the name String
* values by separating them with a space
* @return The String representation of a DSpaceCommandlineParameter object
*/
public String toString() {
String stringToReturn = "";
stringToReturn += getName();
if (StringUtils.isNotBlank(getValue())) {
stringToReturn += " ";
stringToReturn += getValue();
}
return stringToReturn;
}
/**
* This method will convert a list of DSpaceCommandLineParameter objects into a single String. This is done by
* calling the toString() method on each of the DSpaceCommandLineParameter objects in the list and concatenating
* them with the Separator defined in this class
* @param parameterList The list of DSpaceCommandLineParameter objects to be converted into a String
* @return The resulting String
*/
public static String concatenate(List<DSpaceCommandLineParameter> parameterList) {
if (parameterList.isEmpty()) {
return null;
}
return parameterList.stream().map(parameter -> parameter.toString()).collect(Collectors.joining(SEPARATOR));
}
/**
* Will return a boolean indicating whether the given param is equal to this object
* @param other The other object
* @return A boolean indicating equality
*/
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (other.getClass() != DSpaceCommandLineParameter.class) {
return false;
}
return StringUtils.equals(this.getName(), ((DSpaceCommandLineParameter) other).getName()) && StringUtils
.equals(this.getValue(), ((DSpaceCommandLineParameter) other).getValue());
}
}

View File

@@ -0,0 +1,156 @@
/**
* 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.scripts;
import java.sql.SQLException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
/**
* This abstract class is the class that should be extended by each script.
* it provides the basic variables to be hold by the script as well as the means to initialize, parse and run the script
* Every DSpaceRunnable that is implemented in this way should be defined in the scripts.xml config file as a bean
*/
public abstract class DSpaceRunnable implements Runnable {
/**
* The name of the script
*/
private String name;
/**
* The description of the script
*/
private String description;
/**
* The CommandLine object for the script that'll hold the information
*/
protected CommandLine commandLine;
/**
* The possible options for this script
*/
protected Options options;
/**
* The handler that deals with this script. This handler can currently either be a RestDSpaceRunnableHandler or
* a CommandlineDSpaceRunnableHandler depending from where the script is called
*/
protected DSpaceRunnableHandler handler;
@Autowired
private AuthorizeService authorizeService;
public String getName() {
return name;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
@Required
public void setDescription(String description) {
this.description = description;
}
public Options getOptions() {
return options;
}
/**
* This method will take the primitive array of String objects that represent the parameters given to the String
* and it'll parse these into a CommandLine object that can be used by the script to retrieve the data
* @param args The primitive array of Strings representing the parameters
* @throws ParseException If something goes wrong
*/
private void parse(String[] args) throws ParseException {
commandLine = new DefaultParser().parse(getOptions(), args);
setup();
}
/**
* This method will call upon the {@link DSpaceRunnableHandler#printHelp(Options, String)} method with the script's
* options and name
*/
public void printHelp() {
handler.printHelp(options, name);
}
/**
* This is the run() method from the Runnable interface that we implement. This method will handle the running
* of the script and all the database modifications needed for the Process object that resulted from this script
*/
@Override
public void run() {
try {
handler.start();
internalRun();
handler.handleCompletion();
} catch (Exception e) {
handler.handleException(e);
}
}
private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
this.handler = dSpaceRunnableHandler;
}
/**
* This method sets the appropriate DSpaceRunnableHandler depending on where it was ran from and it parses
* the arguments given to the script
* @param args The arguments given to the script
* @param dSpaceRunnableHandler The DSpaceRunnableHandler object that defines from where the script was ran
* @throws ParseException If something goes wrong
*/
public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler) throws ParseException {
this.setHandler(dSpaceRunnableHandler);
this.parse(args);
}
/**
* This method has to be included in every script and this will be the main execution block for the script that'll
* contain all the logic needed
* @throws Exception If something goes wrong
*/
public abstract void internalRun() throws Exception;
/**
* This method has to be included in every script and handles the setup of the script by parsing the CommandLine
* and setting the variables
* @throws ParseException If something goes wrong
*/
public abstract void setup() throws ParseException;
/**
* This method will return if the script is allowed to execute in the given context. This is by default set
* to the currentUser in the context being an admin, however this can be overwritten by each script individually
* if different rules apply
* @param context The relevant DSpace context
* @return A boolean indicating whether the script is allowed to execute or not
*/
public boolean isAllowedToExecute(Context context) {
try {
return authorizeService.isAdmin(context);
} catch (SQLException e) {
handler.logError("Error occured when trying to verify permissions for script: " + name);
}
return false;
}
}

View File

@@ -0,0 +1,242 @@
/**
* 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.scripts;
import java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.dspace.content.Bitstream;
import org.dspace.content.ProcessStatus;
import org.dspace.core.ReloadableEntity;
import org.dspace.eperson.EPerson;
/**
* This class is the DB Entity representation of the Process object to be stored in the Database
*/
@Entity
@Table(name = "process")
public class Process implements ReloadableEntity<Integer> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "process_id_seq")
@SequenceGenerator(name = "process_id_seq", sequenceName = "process_id_seq", allocationSize = 1)
@Column(name = "process_id", unique = true, nullable = false)
private Integer processId;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private EPerson ePerson;
@Column(name = "start_time")
@Temporal(TemporalType.TIMESTAMP)
private Date startTime;
@Column(name = "finished_time")
@Temporal(TemporalType.TIMESTAMP)
private Date finishedTime;
@Column(name = "script", nullable = false)
private String name;
@Column(name = "status")
@Enumerated(EnumType.STRING)
private ProcessStatus processStatus;
@Column(name = "parameters")
private String parameters;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "process2bitstream",
joinColumns = {@JoinColumn(name = "process_id")},
inverseJoinColumns = {@JoinColumn(name = "bitstream_id")}
)
private List<Bitstream> bitstreams;
@Column(name = "creation_time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date creationTime;
protected Process() {
}
/**
* This method returns the ID that the Process holds within the Database
* @return The ID that the process holds within the database
*/
public Integer getID() {
return processId;
}
public void setProcessId(Integer processId) {
this.processId = processId;
}
/**
* This method returns an EPerson object. This EPerson object is the EPerson that initially created the process
* @return The EPerson that created the process
*/
public EPerson getEPerson() {
return ePerson;
}
public void setEPerson(EPerson ePerson) {
this.ePerson = ePerson;
}
/**
* This method returns the Start time for the Process. This reflects the time when the Process was actually started
* @return The start time for the Process
*/
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
/**
* This method returns the time that Process was finished
* @return The finished time for the Process
*/
public Date getFinishedTime() {
return finishedTime;
}
public void setFinishedTime(Date finishedTime) {
this.finishedTime = finishedTime;
}
/**
* This method returns the name of the Process. For example filter-media
* @return The name of the Process
*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* This method returns a ProcessStatus value that represents the current state of the Process. These values
* can be found within the {@link ProcessStatus} enum
* @return The status of the Process
*/
public ProcessStatus getProcessStatus() {
return processStatus;
}
public void setProcessStatus(ProcessStatus processStatus) {
this.processStatus = processStatus;
}
/**
* To get the parameters, use ProcessService.getParameters() to get a parsed list of DSpaceCommandLineParameters
* This String representation is the parameter in an unparsed fashion. For example "-c test"
*/
protected String getParameters() {
return parameters;
}
public void setParameters(String parameters) {
this.parameters = parameters;
}
/**
* This method returns a list of Bitstreams that will be used or created by the Process. This list contains both
* input and output bitstreams.
* @return The Bitstreams that are used or created by the process
*/
public List<Bitstream> getBitstreams() {
return bitstreams;
}
public void setBitstreams(List<Bitstream> bitstreams) {
this.bitstreams = bitstreams;
}
public void removeBitstream(Bitstream bitstream) {
getBitstreams().remove(bitstream);
}
public void addBitstream(Bitstream bitstream) {
getBitstreams().add(bitstream);
}
public void setCreationTime(Date creationTime) {
this.creationTime = creationTime;
}
/**
* This method will return the time when the Process was created. Note that this is potentially different from
* the StartTime (for example if the Process was queued)
* @return The creation time of the Process
*/
public Date getCreationTime() {
return creationTime;
}
/**
* Return <code>true</code> if <code>other</code> is the same Process
* as this object, <code>false</code> otherwise
*
* @param other object to compare to
* @return <code>true</code> if object passed in represents the same
* collection as this object
*/
@Override
public boolean equals(Object other) {
return (other instanceof Process &&
new EqualsBuilder().append(this.getID(), ((Process) other).getID())
.append(this.getName(), ((Process) other).getName())
.append(this.getBitstreams(), ((Process) other).getBitstreams())
.append(this.getProcessStatus(), ((Process) other).getProcessStatus())
.append(this.getFinishedTime(), ((Process) other).getFinishedTime())
.append(this.getStartTime(), ((Process) other).getStartTime())
.append(this.getParameters(), ((Process) other).getParameters())
.append(this.getCreationTime(), ((Process) other).getCreationTime())
.append(this.getEPerson(), ((Process) other).getEPerson())
.isEquals());
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(this.getID())
.append(this.getName())
.append(this.getBitstreams())
.append(this.getProcessStatus())
.append(this.getFinishedTime())
.append(this.getStartTime())
.append(this.getParameters())
.append(this.getCreationTime())
.append(this.getEPerson())
.toHashCode();
}
}

View File

@@ -0,0 +1,148 @@
/**
* 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.scripts;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.content.ProcessStatus;
import org.dspace.content.dao.ProcessDAO;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.service.ProcessService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The implementation for the {@link ProcessService} class
*/
public class ProcessServiceImpl implements ProcessService {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ProcessService.class);
@Autowired
private ProcessDAO processDAO;
@Override
public Process create(Context context, EPerson ePerson, String scriptName,
List<DSpaceCommandLineParameter> parameters) throws SQLException {
Process process = new Process();
process.setEPerson(ePerson);
process.setName(scriptName);
process.setParameters(DSpaceCommandLineParameter.concatenate(parameters));
process.setCreationTime(new Date());
Process createdProcess = processDAO.create(context, process);
log.info(LogManager.getHeader(context, "process_create",
"Process has been created for eperson with email " + ePerson.getEmail()
+ " with ID " + createdProcess.getID() + " and scriptName " +
scriptName + " and parameters " + parameters));
return createdProcess;
}
@Override
public Process find(Context context, int processId) throws SQLException {
return processDAO.findByID(context, Process.class, processId);
}
@Override
public List<Process> findAll(Context context) throws SQLException {
return processDAO.findAll(context, Process.class);
}
@Override
public List<Process> findAll(Context context, int limit, int offset) throws SQLException {
return processDAO.findAll(context, limit, offset);
}
@Override
public List<Process> findAllSortByScript(Context context) throws SQLException {
return processDAO.findAllSortByScript(context);
}
@Override
public List<Process> findAllSortByStartTime(Context context) throws SQLException {
List<Process> processes = findAll(context);
Comparator<Process> comparing = Comparator
.comparing(Process::getStartTime, Comparator.nullsLast(Comparator.naturalOrder()));
comparing = comparing.thenComparing(Process::getID);
processes.sort(comparing);
return processes;
}
@Override
public void start(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.RUNNING);
process.setStartTime(new Date());
update(context, process);
log.info(LogManager.getHeader(context, "process_start", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has started"));
}
@Override
public void fail(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.FAILED);
process.setFinishedTime(new Date());
update(context, process);
log.info(LogManager.getHeader(context, "process_fail", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has failed"));
}
@Override
public void complete(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.COMPLETED);
process.setFinishedTime(new Date());
update(context, process);
log.info(LogManager.getHeader(context, "process_complete", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has been completed"));
}
@Override
public void delete(Context context, Process process) throws SQLException {
processDAO.delete(context, process);
log.info(LogManager.getHeader(context, "process_delete", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has been deleted"));
}
@Override
public void update(Context context, Process process) throws SQLException {
processDAO.save(context, process);
}
@Override
public List<DSpaceCommandLineParameter> getParameters(Process process) {
if (StringUtils.isBlank(process.getParameters())) {
return Collections.emptyList();
}
String[] parameterArray = process.getParameters().split(Pattern.quote(DSpaceCommandLineParameter.SEPARATOR));
List<DSpaceCommandLineParameter> parameterList = new ArrayList<>();
for (String parameter : parameterArray) {
parameterList.add(new DSpaceCommandLineParameter(parameter));
}
return parameterList;
}
public int countTotal(Context context) throws SQLException {
return processDAO.countRows(context);
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.scripts;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.dspace.core.Context;
import org.dspace.scripts.service.ScriptService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The implementation for the {@link ScriptService}
*/
public class ScriptServiceImpl implements ScriptService {
@Autowired
private List<DSpaceRunnable> dSpaceRunnables;
@Override
public DSpaceRunnable getScriptForName(String name) {
return dSpaceRunnables.stream()
.filter(dSpaceRunnable -> StringUtils.equalsIgnoreCase(dSpaceRunnable.getName(), name))
.findFirst()
.orElse(null);
}
@Override
public List<DSpaceRunnable> getDSpaceRunnables(Context context) {
return dSpaceRunnables.stream().filter(
dSpaceRunnable -> dSpaceRunnable.isAllowedToExecute(context)).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,41 @@
/**
* 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.scripts.factory;
import org.dspace.scripts.service.ProcessService;
import org.dspace.scripts.service.ScriptService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Abstract factory to get services for the Script workload, use ScriptServiceFactory.getInstance() to retrieve an
* implementation
*
*/
public abstract class ScriptServiceFactory {
/**
* This method will return an instance of the ScriptService
* @return An instance of the ScriptService
*/
public abstract ScriptService getScriptService();
/**
* This method will return an instance of the ProcessService
* @return An instance of the ProcessService
*/
public abstract ProcessService getProcessService();
/**
* Use this method to retrieve an implementation of the ScriptServiceFactory to use to retrieve the different beans
* @return An implementation of the ScriptServiceFactory
*/
public static ScriptServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("scriptServiceFactory", ScriptServiceFactory.class);
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.scripts.factory.impl;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.service.ProcessService;
import org.dspace.scripts.service.ScriptService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The implementation for the {@link ScriptServiceFactory}
*/
public class ScriptServiceFactoryImpl extends ScriptServiceFactory {
@Autowired(required = true)
private ScriptService scriptService;
@Autowired(required = true)
private ProcessService processService;
@Override
public ScriptService getScriptService() {
return scriptService;
}
@Override
public ProcessService getProcessService() {
return processService;
}
}

View File

@@ -0,0 +1,81 @@
/**
* 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.scripts.handler;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
/**
* This is an interface meant to be implemented by any DSpaceRunnableHandler to specify specific execution methods
* of the script depending on where it was called from
*/
public interface DSpaceRunnableHandler {
/**
* This method handles the start of the script
* @throws SQLException If something goes wrong
*/
public void start() throws SQLException;
/**
* This method handles the completion of the script
* @throws SQLException If something goes wrong
*/
public void handleCompletion() throws SQLException;
/**
* This method handles an exception thrown by the script
* @param e The exception thrown by the script
*/
public void handleException(Exception e);
/**
* This method handles an exception thrown by the script
* @param message The String message for the exception thrown by the script
*/
public void handleException(String message);
/**
* This method handles an exception thrown by the script
* @param message The String message for the exception thrown by the script
* @param e The exception thrown by the script
*/
public void handleException(String message, Exception e);
/**
* This method will perform the debug logging of the message given
* @param message The message to be logged as debug
*/
public void logDebug(String message);
/**
* This method will perform the info logging of the message given
* @param message The message to be logged as info
*/
public void logInfo(String message);
/**
* This method will perform the warning logging of the message given
* @param message The message to be logged as warning
*/
public void logWarning(String message);
/**
* This method will perform the error logging of the message given
* @param message The message to be logged as an error
*/
public void logError(String message);
/**
* This method will print the help for the options and name
* @param options The options for the script
* @param name The name of the script
*/
public void printHelp(Options options, String name);
}

View File

@@ -0,0 +1,87 @@
/**
* 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.scripts.handler.impl;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.logging.log4j.Logger;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
* This is an implementation for the CommandLineDSpaceRunnables which means that these implementations
* are used by DSpaceRunnables which are called from the CommandLine
*/
public class CommandLineDSpaceRunnableHandler implements DSpaceRunnableHandler {
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(CommandLineDSpaceRunnableHandler.class);
@Override
public void start() {
System.out.println("The script has started");
}
@Override
public void handleCompletion() {
System.out.println("The script has completed");
}
@Override
public void handleException(Exception e) {
handleException(null, e);
}
@Override
public void handleException(String message) {
handleException(message, null);
}
@Override
public void handleException(String message, Exception e) {
if (message != null) {
System.err.println(message);
log.error(message);
}
if (e != null) {
e.printStackTrace();
log.error(e.getMessage(), e);
}
System.exit(1);
}
@Override
public void logDebug(String message) {
log.debug(message);
}
@Override
public void logInfo(String message) {
System.out.println(message);
log.info(message);
}
@Override
public void logWarning(String message) {
System.out.println(message);
log.warn(message);
}
@Override
public void logError(String message) {
System.err.println(message);
log.error(message);
}
@Override
public void printHelp(Options options, String name) {
if (options != null) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(name, options);
}
}
}

View File

@@ -0,0 +1,139 @@
/**
* 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.scripts.service;
import java.sql.SQLException;
import java.util.List;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.dspace.scripts.Process;
/**
* An interface for the ProcessService with methods regarding the Process workload
*/
public interface ProcessService {
/**
* This method will create a Process object in the database
* @param context The relevant DSpace context
* @param ePerson The ePerson for which this process will be created on
* @param scriptName The script name to be used for the process
* @param parameters The parameters to be used for the process
* @return The created process
* @throws SQLException If something goes wrong
*/
public Process create(Context context, EPerson ePerson, String scriptName,
List<DSpaceCommandLineParameter> parameters) throws SQLException;
/**
* This method will retrieve a Process object from the Database with the given ID
* @param context The relevant DSpace context
* @param processId The process id on which we'll search for in the database
* @return The process that holds the given process id
* @throws SQLException If something goes wrong
*/
public Process find(Context context, int processId) throws SQLException;
/**
* Returns a list of all Process objects in the database
* @param context The relevant DSpace context
* @return The list of all Process objects in the Database
* @throws SQLException If something goes wrong
*/
public List<Process> findAll(Context context) throws SQLException;
/**
* Returns a list of all Process objects in the database
* @param context The relevant DSpace context
* @param limit The limit for the amount of Processes returned
* @param offset The offset for the Processes to be returned
* @return The list of all Process objects in the Database
* @throws SQLException If something goes wrong
*/
public List<Process> findAll(Context context, int limit, int offset) throws SQLException;
/**
* Returns a list of all Process objects in the database sorted by script name
* @param context The relevant DSpace context
* @return The list of all Process objects in the database sorted by script name
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByScript(Context context) throws SQLException;
/**
* Returns a list of all Process objects in the database sorted by start time
* The most recent one will be shown first
* @param context The relevant DSpace context
* @return The list of all Process objects sorted by start time
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByStartTime(Context context) throws SQLException;
/**
* This method will perform the logic needed to update the Process object in the database to represent a
* started state. A started state refers to {@link org.dspace.content.ProcessStatus#RUNNING}
* @param context The relevant DSpace context
* @param process The Process object to be updated
* @throws SQLException If something goes wrong
*/
public void start(Context context, Process process) throws SQLException;
/**
* This method will perform the logic needed to update the Process object in the database to represent
* a failed state
* @param context The relevant DSpace context
* @param process The Process object to be updated
* @throws SQLException If something goes wrong
*/
public void fail(Context context, Process process) throws SQLException;
/**
* This method will perform the logic needed to update the Process object in the database to represent
* a complete state
* @param context The relevant DSpace context
* @param process The Process object to be updated
* @throws SQLException If something goes wrong
*/
public void complete(Context context, Process process) throws SQLException;
/**
* This method will delete the given Process object from the database
* @param context The relevant DSpace context
* @param process The Process object to be deleted
* @throws SQLException If something goes wrong
*/
public void delete(Context context, Process process) throws SQLException;
/**
* This method will be used to update the given Process object in the database
* @param context The relevant DSpace context
* @param process The Process object to be updated
* @throws SQLException If something goes wrong
*/
public void update(Context context, Process process) throws SQLException;
/**
* This method will retrieve the list of parameters from the Process in its String format and it will parse
* these parameters to a list of {@link DSpaceCommandLineParameter} objects for better usability throughout DSpace
* @param process The Process object for which we'll return the parameters
* @return The list of parsed parameters from the Process object
*/
public List<DSpaceCommandLineParameter> getParameters(Process process);
/**
* Returns the total amount of Process objects in the dataase
* @param context The relevant DSpace context
* @return An integer that describes the amount of Process objects in the database
* @throws SQLException If something goes wrong
*/
int countTotal(Context context) throws SQLException;
}

View File

@@ -0,0 +1,33 @@
/**
* 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.scripts.service;
import java.util.List;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceRunnable;
/**
* This service will deal with logic to handle DSpaceRunnable objects
*/
public interface ScriptService {
/**
* This method will return the DSpaceRunnable that has the name that's equal to the name given in the parameters
* @param name The name that the script has to match
* @return The matching DSpaceRunnable script
*/
DSpaceRunnable getScriptForName(String name);
/**
* This method will return a list of DSpaceRunnable objects for which the given Context is authorized to use them
* @param context The relevant DSpace context
* @return The list of accessible DSpaceRunnable scripts for this context
*/
List<DSpaceRunnable> getDSpaceRunnables(Context context);
}

View File

@@ -189,16 +189,19 @@ ALTER TABLE item2bundle add primary key (item_id,bundle_id);
--Migrate Bundle2Bitsteam --Migrate Bundle2Bitsteam
ALTER TABLE bundle2bitstream ALTER COLUMN bundle_id rename to bundle_legacy_id; ALTER TABLE bundle2bitstream ALTER COLUMN bundle_id rename to bundle_legacy_id;
ALTER TABLE bundle2bitstream ALTER COLUMN bitstream_id rename to bitstream_legacy_id; ALTER TABLE bundle2bitstream ALTER COLUMN bitstream_id rename to bitstream_legacy_id;
ALTER TABLE bundle2bitstream ALTER COLUMN bitstream_order rename to bitstream_order_legacy;
ALTER TABLE bundle2bitstream ADD COLUMN bundle_id UUID NOT NULL; ALTER TABLE bundle2bitstream ADD COLUMN bundle_id UUID NOT NULL;
ALTER TABLE bundle2bitstream ADD CONSTRAINT bundle2bitstream_bundle_id_fk FOREIGN KEY (bundle_id) REFERENCES bundle; ALTER TABLE bundle2bitstream ADD CONSTRAINT bundle2bitstream_bundle_id_fk FOREIGN KEY (bundle_id) REFERENCES bundle;
ALTER TABLE bundle2bitstream ADD COLUMN bitstream_id UUID NOT NULL; ALTER TABLE bundle2bitstream ADD COLUMN bitstream_id UUID NOT NULL;
ALTER TABLE bundle2bitstream ADD CONSTRAINT bundle2bitstream_bitstream_id_fk FOREIGN KEY (bitstream_id) REFERENCES bitstream; ALTER TABLE bundle2bitstream ADD CONSTRAINT bundle2bitstream_bitstream_id_fk FOREIGN KEY (bitstream_id) REFERENCES bitstream;
ALTER TABLE bundle2bitstream ADD COLUMN bitstream_order INTEGER NOT NULL;
UPDATE bundle2bitstream SET bundle_id = (SELECT bundle.uuid FROM bundle WHERE bundle2bitstream.bundle_legacy_id = bundle.bundle_id); UPDATE bundle2bitstream SET bundle_id = (SELECT bundle.uuid FROM bundle WHERE bundle2bitstream.bundle_legacy_id = bundle.bundle_id);
UPDATE bundle2bitstream SET bitstream_id = (SELECT bitstream.uuid FROM bitstream WHERE bundle2bitstream.bitstream_legacy_id = bitstream.bitstream_id); UPDATE bundle2bitstream SET bitstream_id = (SELECT bitstream.uuid FROM bitstream WHERE bundle2bitstream.bitstream_legacy_id = bitstream.bitstream_id);
ALTER TABLE bundle2bitstream DROP COLUMN bundle_legacy_id; ALTER TABLE bundle2bitstream DROP COLUMN bundle_legacy_id;
ALTER TABLE bundle2bitstream DROP COLUMN bitstream_legacy_id; ALTER TABLE bundle2bitstream DROP COLUMN bitstream_legacy_id;
ALTER TABLE bundle2bitstream DROP COLUMN bitstream_order_legacy;
ALTER TABLE bundle2bitstream DROP COLUMN id; ALTER TABLE bundle2bitstream DROP COLUMN id;
ALTER TABLE bundle2bitstream add primary key (bitstream_id,bundle_id); ALTER TABLE bundle2bitstream add primary key (bitstream_id,bundle_id,bitstream_order);
-- Migrate item -- Migrate item

View File

@@ -0,0 +1,40 @@
--
-- 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/
--
-- ===============================================================
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
--
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
-- http://flywaydb.org/
-- ===============================================================
CREATE SEQUENCE process_id_seq;
CREATE TABLE process
(
process_id INTEGER NOT NULL PRIMARY KEY,
user_id UUID NOT NULL,
start_time TIMESTAMP,
finished_time TIMESTAMP,
creation_time TIMESTAMP NOT NULL,
script VARCHAR(256) NOT NULL,
status VARCHAR(32),
parameters VARCHAR(512)
);
CREATE TABLE process2bitstream
(
process_id INTEGER REFERENCES process(process_id),
bitstream_id UUID REFERENCES bitstream(uuid),
CONSTRAINT PK_process2bitstream PRIMARY KEY (process_id, bitstream_id)
);
CREATE INDEX process_user_id_idx ON process(user_id);
CREATE INDEX process_status_idx ON process(status);
CREATE INDEX process_name_idx on process(script);
CREATE INDEX process_start_time_idx on process(start_time);

View File

@@ -0,0 +1,40 @@
--
-- 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/
--
-- ===============================================================
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
--
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
-- http://flywaydb.org/
-- ===============================================================
CREATE SEQUENCE process_id_seq;
CREATE TABLE process
(
process_id INTEGER NOT NULL PRIMARY KEY,
user_id RAW(16) NOT NULL,
start_time TIMESTAMP,
finished_time TIMESTAMP,
creation_time TIMESTAMP NOT NULL,
script VARCHAR(256) NOT NULL,
status VARCHAR(32),
parameters VARCHAR(512)
);
CREATE TABLE process2bitstream
(
process_id INTEGER REFERENCES process(process_id),
bitstream_id RAW(16) REFERENCES bitstream(uuid),
CONSTRAINT PK_process2bitstream PRIMARY KEY (process_id, bitstream_id)
);
CREATE INDEX process_user_id_idx ON process(user_id);
CREATE INDEX process_status_idx ON process(status);
CREATE INDEX process_name_idx on process(script);
CREATE INDEX process_start_time_idx on process(start_time);

View File

@@ -0,0 +1,40 @@
--
-- 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/
--
-- ===============================================================
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
--
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
-- http://flywaydb.org/
-- ===============================================================
CREATE SEQUENCE process_id_seq;
CREATE TABLE process
(
process_id INTEGER NOT NULL PRIMARY KEY,
user_id UUID NOT NULL,
start_time TIMESTAMP,
finished_time TIMESTAMP,
creation_time TIMESTAMP NOT NULL,
script VARCHAR(256) NOT NULL,
status VARCHAR(32),
parameters VARCHAR(512)
);
CREATE TABLE process2bitstream
(
process_id INTEGER REFERENCES process(process_id),
bitstream_id UUID REFERENCES bitstream(uuid),
CONSTRAINT PK_process2bitstream PRIMARY KEY (process_id, bitstream_id)
);
CREATE INDEX process_user_id_idx ON process(user_id);
CREATE INDEX process_status_idx ON process(status);
CREATE INDEX process_name_idx on process(script);
CREATE INDEX process_start_time_idx on process(start_time);

View File

@@ -0,0 +1,14 @@
<?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.external.service.impl.ExternalDataServiceImpl"/>
<bean class="org.dspace.external.provider.impl.MockDataProvider" init-method="init">
<property name="sourceIdentifier" value="mock"/>
</bean>
</beans>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="indexClient" class="org.dspace.discovery.IndexClient" scope="prototype">
<property name="name" value="index-discovery"/>
<property name="description" value="Update Discovery Solr Search Index"/>
</bean>
<bean id="MockScript" class="org.dspace.scripts.impl.MockDSpaceRunnableScript" scope="prototype">
<property name="name" value="mock-script" />
<property name="description" value="Mocking a script for testing purposes" />
</bean>
</beans>

View File

@@ -8,6 +8,7 @@
package org.dspace.content; package org.dspace.content;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@@ -49,8 +50,10 @@ public class RelationshipMetadataServiceTest extends AbstractUnitTest {
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService(); protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService(); protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
Item item; Item leftItem;
Item authorItem; Item rightItem;
Relationship relationship;
RelationshipType isAuthorOfPublicationRelationshipType;
/** /**
* This method will be run before every test as per @Before. It will * This method will be run before every test as per @Before. It will
@@ -68,11 +71,11 @@ public class RelationshipMetadataServiceTest extends AbstractUnitTest {
Community community = communityService.create(null, context); Community community = communityService.create(null, context);
Collection col = collectionService.create(context, community); Collection col = collectionService.create(context, community);
WorkspaceItem is = workspaceItemService.create(context, col, false); WorkspaceItem leftIs = workspaceItemService.create(context, col, false);
WorkspaceItem authorIs = workspaceItemService.create(context, col, false); WorkspaceItem rightIs = workspaceItemService.create(context, col, false);
item = installItemService.installItem(context, is); leftItem = installItemService.installItem(context, leftIs);
authorItem = installItemService.installItem(context, authorIs); rightItem = installItemService.installItem(context, rightIs);
context.restoreAuthSystemState(); context.restoreAuthSystemState();
} catch (AuthorizeException ex) { } catch (AuthorizeException ex) {
log.error("Authorization Error in init", ex); log.error("Authorization Error in init", ex);
@@ -81,7 +84,6 @@ public class RelationshipMetadataServiceTest extends AbstractUnitTest {
log.error("SQL Error in init", ex); log.error("SQL Error in init", ex);
fail("SQL Error in init: " + ex.getMessage()); fail("SQL Error in init: " + ex.getMessage());
} }
} }
/** /**
@@ -98,34 +100,66 @@ public class RelationshipMetadataServiceTest extends AbstractUnitTest {
super.destroy(); super.destroy();
} }
/**
@Test * Common function to convert leftItem to a publication item, convert rightItem to an author item,
public void testGetRelationshipMetadata() throws Exception { * and relating them to each other stored in the relationship field
*/
private void initPublicationAuthor() throws SQLException, AuthorizeException {
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
itemService.addMetadata(context, item, "relationship", "type", null, null, "Publication"); itemService.addMetadata(context, leftItem, "relationship", "type", null, null, "Publication");
itemService.addMetadata(context, authorItem, "relationship", "type", null, null, "Author"); itemService.addMetadata(context, rightItem, "relationship", "type", null, null, "Author");
itemService.addMetadata(context, authorItem, "person", "familyName", null, null, "familyName"); itemService.addMetadata(context, rightItem, "person", "familyName", null, null, "familyName");
itemService.addMetadata(context, authorItem, "person", "givenName", null, null, "firstName"); itemService.addMetadata(context, rightItem, "person", "givenName", null, null, "firstName");
EntityType publicationEntityType = entityTypeService.create(context, "Publication"); EntityType publicationEntityType = entityTypeService.create(context, "Publication");
EntityType authorEntityType = entityTypeService.create(context, "Author"); EntityType authorEntityType = entityTypeService.create(context, "Author");
RelationshipType isAuthorOfPublication = relationshipTypeService isAuthorOfPublicationRelationshipType = relationshipTypeService
.create(context, publicationEntityType, authorEntityType, "isAuthorOfPublication", "isPublicationOfAuthor", .create(context, publicationEntityType, authorEntityType,
"isAuthorOfPublication", "isPublicationOfAuthor",
null, null, null, null); null, null, null, null);
Relationship relationship = relationshipService.create(context, item, authorItem, isAuthorOfPublication, 0, 0); relationship = relationshipService.create(context, leftItem, rightItem,
isAuthorOfPublicationRelationshipType, 0, 0);
context.restoreAuthSystemState(); context.restoreAuthSystemState();
}
List<MetadataValue> authorList = itemService.getMetadata(item, "dc", "contributor", "author", Item.ANY); /**
* Common function to convert leftItem to a journal issue item, convert rightItem to a journal volume item,
* and relating them to each other stored in the relationship field
*/
private void initJournalVolumeIssue() throws SQLException, AuthorizeException {
context.turnOffAuthorisationSystem();
itemService.addMetadata(context, leftItem, "relationship", "type", null, null, "JournalIssue");
itemService.addMetadata(context, rightItem, "relationship", "type", null, null, "JournalVolume");
itemService.addMetadata(context, leftItem, "publicationissue", "issueNumber", null, null, "2");
itemService.addMetadata(context, rightItem, "publicationvolume", "volumeNumber", null, null, "30");
EntityType journalIssueEntityType = entityTypeService.create(context, "JournalIssue");
EntityType publicationVolumeEntityType = entityTypeService.create(context, "JournalVolume");
RelationshipType isIssueOfVolume = relationshipTypeService
.create(context, journalIssueEntityType, publicationVolumeEntityType,
"isJournalVolumeOfIssue", "isIssueOfJournalVolume",
null, null, null, null);
relationship = relationshipService.create(context, leftItem, rightItem, isIssueOfVolume, 0, 0);
context.restoreAuthSystemState();
}
@Test
public void testGetAuthorRelationshipMetadata() throws SQLException, AuthorizeException {
initPublicationAuthor();
//leftItem is the publication
//verify the dc.contributor.author virtual metadata
List<MetadataValue> authorList = itemService.getMetadata(leftItem, "dc", "contributor", "author", Item.ANY);
assertThat(authorList.size(), equalTo(1)); assertThat(authorList.size(), equalTo(1));
assertThat(authorList.get(0).getValue(), equalTo("familyName, firstName")); assertThat(authorList.get(0).getValue(), equalTo("familyName, firstName"));
//verify the relation.isAuthorOfPublication virtual metadata
List<MetadataValue> relationshipMetadataList = itemService List<MetadataValue> relationshipMetadataList = itemService
.getMetadata(item, "relation", "isAuthorOfPublication", null, Item.ANY); .getMetadata(leftItem, MetadataSchemaEnum.RELATION.getName(), "isAuthorOfPublication", null, Item.ANY);
assertThat(relationshipMetadataList.size(), equalTo(1)); assertThat(relationshipMetadataList.size(), equalTo(1));
assertThat(relationshipMetadataList.get(0).getValue(), equalTo(String.valueOf(authorItem.getID()))); assertThat(relationshipMetadataList.get(0).getValue(), equalTo(String.valueOf(rightItem.getID())));
List<RelationshipMetadataValue> list = relationshipMetadataService.getRelationshipMetadata(item, true); //request the virtual metadata of the publication only
List<RelationshipMetadataValue> list = relationshipMetadataService.getRelationshipMetadata(leftItem, true);
assertThat(list.size(), equalTo(2)); assertThat(list.size(), equalTo(2));
assertThat(list.get(0).getValue(), equalTo("familyName, firstName")); assertThat(list.get(0).getValue(), equalTo("familyName, firstName"));
assertThat(list.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("dc")); assertThat(list.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("dc"));
@@ -133,10 +167,243 @@ public class RelationshipMetadataServiceTest extends AbstractUnitTest {
assertThat(list.get(0).getMetadataField().getQualifier(), equalTo("author")); assertThat(list.get(0).getMetadataField().getQualifier(), equalTo("author"));
assertThat(list.get(0).getAuthority(), equalTo("virtual::" + relationship.getID())); assertThat(list.get(0).getAuthority(), equalTo("virtual::" + relationship.getID()));
assertThat(list.get(1).getValue(), equalTo(String.valueOf(authorItem.getID()))); assertThat(list.get(1).getValue(), equalTo(String.valueOf(rightItem.getID())));
assertThat(list.get(1).getMetadataField().getMetadataSchema().getName(), equalTo("relation")); assertThat(list.get(1).getMetadataField().getMetadataSchema().getName(),
equalTo(MetadataSchemaEnum.RELATION.getName()));
assertThat(list.get(1).getMetadataField().getElement(), equalTo("isAuthorOfPublication")); assertThat(list.get(1).getMetadataField().getElement(), equalTo("isAuthorOfPublication"));
assertThat(list.get(1).getAuthority(), equalTo("virtual::" + relationship.getID())); assertThat(list.get(1).getAuthority(), equalTo("virtual::" + relationship.getID()));
}
@Test
public void testDeleteAuthorRelationshipCopyToLeftItem() throws Exception {
initPublicationAuthor();
context.turnOffAuthorisationSystem();
//delete the relationship, copying the virtual metadata to actual metadata on the leftItem
//leftItem is the publication
relationshipService.delete(context, relationship, true, false);
context.restoreAuthSystemState();
//verify the dc.contributor.author actual metadata
List<MetadataValue> authorList = itemService.getMetadata(leftItem, "dc", "contributor", "author", Item.ANY);
assertThat(authorList.size(), equalTo(1));
assertThat(authorList.get(0).getValue(), equalTo("familyName, firstName"));
assertThat(authorList.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("dc"));
assertThat(authorList.get(0).getMetadataField().getElement(), equalTo("contributor"));
assertThat(authorList.get(0).getMetadataField().getQualifier(), equalTo("author"));
assertNull(authorList.get(0).getAuthority());
//verify there's no relation.isAuthorOfPublication actual metadata
List<MetadataValue> relationshipMetadataList = itemService
.getMetadata(leftItem, MetadataSchemaEnum.RELATION.getName(), "isAuthorOfPublication", null, Item.ANY);
assertThat(relationshipMetadataList.size(), equalTo(0));
//request the virtual metadata of the publication only
List<RelationshipMetadataValue> list = relationshipMetadataService.getRelationshipMetadata(leftItem, true);
assertThat(list.size(), equalTo(0));
}
@Test
public void testAuthorDeleteRelationshipCopyToRightItem() throws Exception {
initPublicationAuthor();
context.turnOffAuthorisationSystem();
//delete the relationship, copying the virtual metadata to actual metadata on the rightItem
//rightItem is the author
relationshipService.delete(context, relationship, false, true);
context.restoreAuthSystemState();
//verify there's no dc.contributor.author actual metadata on the publication
List<MetadataValue> authorList = itemService.getMetadata(leftItem, "dc", "contributor", "author", Item.ANY);
assertThat(authorList.size(), equalTo(0));
//verify there's no relation.isAuthorOfPublication actual metadata on the publication
List<MetadataValue> relationshipMetadataList = itemService
.getMetadata(leftItem, MetadataSchemaEnum.RELATION.getName(), "isAuthorOfPublication", null, Item.ANY);
assertThat(relationshipMetadataList.size(), equalTo(0));
}
@Test
public void testDeleteAuthorRelationshipCopyToBothItems() throws Exception {
initPublicationAuthor();
context.turnOffAuthorisationSystem();
//delete the relationship, copying the virtual metadata to actual metadata on the both items
relationshipService.delete(context, relationship, true, true);
context.restoreAuthSystemState();
//verify the dc.contributor.author actual metadata
List<MetadataValue> authorList = itemService.getMetadata(leftItem, "dc", "contributor", "author", Item.ANY);
assertThat(authorList.size(), equalTo(1));
assertThat(authorList.get(0).getValue(), equalTo("familyName, firstName"));
assertThat(authorList.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("dc"));
assertThat(authorList.get(0).getMetadataField().getElement(), equalTo("contributor"));
assertThat(authorList.get(0).getMetadataField().getQualifier(), equalTo("author"));
assertNull(authorList.get(0).getAuthority());
//verify there's no relation.isAuthorOfPublication actual metadata
List<MetadataValue> relationshipMetadataList = itemService
.getMetadata(leftItem, MetadataSchemaEnum.RELATION.getName(), "isAuthorOfPublication", null, Item.ANY);
assertThat(relationshipMetadataList.size(), equalTo(0));
}
@Test
public void testGetJournalRelationshipMetadata() throws SQLException, AuthorizeException {
initJournalVolumeIssue();
//leftItem is the journal issue item
//verify the publicationvolume.volumeNumber virtual metadata
List<MetadataValue> volumeList =
itemService.getMetadata(leftItem, "publicationvolume", "volumeNumber", null, Item.ANY);
assertThat(volumeList.size(), equalTo(1));
assertThat(volumeList.get(0).getValue(), equalTo("30"));
//rightItem is the journal volume item
//verify the publicationissue.issueNumber virtual metadata
List<MetadataValue> issueList =
itemService.getMetadata(rightItem, "publicationissue", "issueNumber", null, Item.ANY);
assertThat(issueList.size(), equalTo(1));
assertThat(issueList.get(0).getValue(), equalTo("2"));
//request the virtual metadata of the journal issue
List<RelationshipMetadataValue> issueRelList =
relationshipMetadataService.getRelationshipMetadata(leftItem, true);
assertThat(issueRelList.size(), equalTo(2));
assertThat(issueRelList.get(0).getValue(), equalTo("30"));
assertThat(issueRelList.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("publicationvolume"));
assertThat(issueRelList.get(0).getMetadataField().getElement(), equalTo("volumeNumber"));
assertThat(issueRelList.get(0).getMetadataField().getQualifier(), equalTo(null));
assertThat(issueRelList.get(0).getAuthority(), equalTo("virtual::" + relationship.getID()));
assertThat(issueRelList.get(1).getValue(), equalTo(String.valueOf(rightItem.getID())));
assertThat(issueRelList.get(1).getMetadataField().getMetadataSchema().getName(),
equalTo(MetadataSchemaEnum.RELATION.getName()));
assertThat(issueRelList.get(1).getMetadataField().getElement(), equalTo("isJournalVolumeOfIssue"));
assertThat(issueRelList.get(1).getAuthority(), equalTo("virtual::" + relationship.getID()));
//request the virtual metadata of the journal volume
List<RelationshipMetadataValue> volumeRelList =
relationshipMetadataService.getRelationshipMetadata(rightItem, true);
assertThat(volumeRelList.size(), equalTo(2));
assertThat(volumeRelList.get(0).getValue(), equalTo("2"));
assertThat(volumeRelList.get(0).getMetadataField().getMetadataSchema().getName(), equalTo("publicationissue"));
assertThat(volumeRelList.get(0).getMetadataField().getElement(), equalTo("issueNumber"));
assertThat(volumeRelList.get(0).getMetadataField().getQualifier(), equalTo(null));
assertThat(volumeRelList.get(0).getAuthority(), equalTo("virtual::" + relationship.getID()));
assertThat(volumeRelList.get(1).getValue(), equalTo(String.valueOf(leftItem.getID())));
assertThat(volumeRelList.get(1).getMetadataField().getMetadataSchema().getName(),
equalTo(MetadataSchemaEnum.RELATION.getName()));
assertThat(volumeRelList.get(1).getMetadataField().getElement(), equalTo("isIssueOfJournalVolume"));
assertThat(volumeRelList.get(1).getAuthority(), equalTo("virtual::" + relationship.getID()));
}
@Test
public void testDeleteJournalRelationshipCopyToLeftItem() throws SQLException, AuthorizeException {
initJournalVolumeIssue();
context.turnOffAuthorisationSystem();
//leftItem is the journal issue item
relationshipService.delete(context, relationship, true, false);
context.restoreAuthSystemState();
//verify the left item's publicationvolume.volumeNumber actual metadata
List<MetadataValue> volumeList =
itemService.getMetadata(leftItem, "publicationvolume", "volumeNumber", null, Item.ANY);
assertThat(volumeList.size(), equalTo(1));
assertThat(volumeList.get(0).getValue(), equalTo("30"));
//verify the right item doesn't contain the actual metadata
List<MetadataValue> issueList =
itemService.getMetadata(rightItem, "publicationissue", "issueNumber", null, Item.ANY);
assertThat(issueList.size(), equalTo(0));
}
@Test
public void testJournalDeleteRelationshipCopyToRightItem() throws SQLException, AuthorizeException {
initJournalVolumeIssue();
context.turnOffAuthorisationSystem();
//rightItem is the journal volume item
relationshipService.delete(context, relationship, false, true);
context.restoreAuthSystemState();
//verify the left item doesn't contain the publicationvolume.volumeNumber actual metadata
List<MetadataValue> volumeList =
itemService.getMetadata(leftItem, "publicationvolume", "volumeNumber", null, Item.ANY);
assertThat(volumeList.size(), equalTo(0));
//verify the right item's publicationissue.issueNumber actual metadata
List<MetadataValue> issueList =
itemService.getMetadata(rightItem, "publicationissue", "issueNumber", null, Item.ANY);
assertThat(issueList.size(), equalTo(1));
assertThat(issueList.get(0).getValue(), equalTo("2"));
}
@Test
public void testDeleteJournalRelationshipCopyToBothItems() throws SQLException, AuthorizeException {
initJournalVolumeIssue();
context.turnOffAuthorisationSystem();
//leftItem is the journal issue item
//rightItem is the journal volume item
relationshipService.delete(context, relationship, true, true);
context.restoreAuthSystemState();
//verify the left item's publicationvolume.volumeNumber actual metadata
List<MetadataValue> volumeList =
itemService.getMetadata(leftItem, "publicationvolume", "volumeNumber", null, Item.ANY);
assertThat(volumeList.size(), equalTo(1));
assertThat(volumeList.get(0).getValue(), equalTo("30"));
//verify the right item's publicationissue.issueNumber actual metadata
List<MetadataValue> issueList =
itemService.getMetadata(rightItem, "publicationissue", "issueNumber", null, Item.ANY);
assertThat(issueList.size(), equalTo(1));
assertThat(issueList.get(0).getValue(), equalTo("2"));
}
@Test
public void testGetNextRightPlace() throws Exception {
assertThat(relationshipService.findNextRightPlaceByRightItem(context, rightItem), equalTo(0));
initPublicationAuthor();
assertThat(relationshipService.findNextRightPlaceByRightItem(context, rightItem), equalTo(1));
context.turnOffAuthorisationSystem();
Community community = communityService.create(null, context);
Collection col = collectionService.create(context, community);
WorkspaceItem is = workspaceItemService.create(context, col, false);
Item secondItem = installItemService.installItem(context, is);
itemService.addMetadata(context, secondItem, "relationship", "type", null, null, "Publication");
Relationship secondRelationship = relationshipService.create(context, secondItem, rightItem,
isAuthorOfPublicationRelationshipType, 0, 0);
context.restoreAuthSystemState();
assertThat(relationshipService.findNextRightPlaceByRightItem(context, rightItem), equalTo(2));
}
@Test
public void testGetNextLeftPlace() throws Exception {
assertThat(relationshipService.findNextLeftPlaceByLeftItem(context, leftItem), equalTo(0));
initPublicationAuthor();
assertThat(relationshipService.findNextLeftPlaceByLeftItem(context, leftItem), equalTo(1));
context.turnOffAuthorisationSystem();
Community community = communityService.create(null, context);
Collection col = collectionService.create(context, community);
WorkspaceItem is = workspaceItemService.create(context, col, false);
Item secondAuthor = installItemService.installItem(context, is);
itemService.addMetadata(context, secondAuthor, "relationship", "type", null, null, "Author");
itemService.addMetadata(context, secondAuthor, "person", "familyName", null, null, "familyName");
itemService.addMetadata(context, secondAuthor, "person", "givenName", null, null, "firstName");
Relationship secondRelationship = relationshipService.create(context, leftItem, secondAuthor,
isAuthorOfPublicationRelationshipType, 0, 0);
context.restoreAuthSystemState();
assertThat(relationshipService.findNextLeftPlaceByLeftItem(context, leftItem), equalTo(2));
} }
} }

View File

@@ -0,0 +1,428 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.sql.SQLException;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.dspace.AbstractUnitTest;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.WorkspaceItemService;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class RelationshipServiceImplPlaceTest extends AbstractUnitTest {
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(RelationshipServiceImplPlaceTest.class);
protected RelationshipService relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
protected RelationshipTypeService relationshipTypeService = ContentServiceFactory.getInstance()
.getRelationshipTypeService();
protected EntityTypeService entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
protected MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
Community community;
Collection col;
Item item;
Item authorItem;
RelationshipType isAuthorOfPublication;
EntityType publicationEntityType;
EntityType authorEntityType;
String authorQualifier = "author";
String contributorElement = "contributor";
String dcSchema = "dc";
/**
* This method will be run before every test as per @Before. It will
* initialize resources required for the tests.
*/
@Before
@Override
public void init() {
super.init();
try {
context.turnOffAuthorisationSystem();
community = communityService.create(null, context);
col = collectionService.create(context, community);
WorkspaceItem is = workspaceItemService.create(context, col, false);
WorkspaceItem authorIs = workspaceItemService.create(context, col, false);
item = installItemService.installItem(context, is);
itemService.addMetadata(context, item, "relationship", "type", null, null, "Publication");
authorItem = installItemService.installItem(context, authorIs);
itemService.addMetadata(context, authorItem, "relationship", "type", null, null, "Person");
itemService.addMetadata(context, authorItem, "person", "familyName", null, null, "familyName");
itemService.addMetadata(context, authorItem, "person", "givenName", null, null, "firstName");
publicationEntityType = entityTypeService.create(context, "Publication");
authorEntityType = entityTypeService.create(context, "Person");
isAuthorOfPublication = relationshipTypeService
.create(context, publicationEntityType, authorEntityType,
"isAuthorOfPublication", "isPublicationOfAuthor",
null, null, null, null);
context.restoreAuthSystemState();
} catch (AuthorizeException ex) {
log.error("Authorization Error in init", ex);
fail("Authorization Error in init: " + ex.getMessage());
} catch (SQLException ex) {
log.error("SQL Error in init", ex);
fail("SQL Error in init: " + ex.getMessage());
}
}
/**
* This method will be run after every test as per @After. It will
* clean resources initialized by the @Before methods.
*/
@After
@Override
public void destroy() {
context.abort();
super.destroy();
}
/**
* This test will test the use case of having an item to which we add some metadata. After that, we'll add a single
* relationship to this Item. We'll test whether the places are correct, in this case it'll be the two metadata
* values that we created first, has to have place 0 and 1. The Relationship that we just created needs to have
* leftPlace 2 and the metadata value resulting from that Relationship needs to also have place 2.
* Once these assertions succeed, we basically repeat said process with new metadata values and a new relationship.
* We then test if the old assertions still hold true like they should and that the new ones behave as expected
* as well.
* @throws Exception If something goes wrong
*/
@Test
public void addMetadataAndRelationshipTest() throws Exception {
context.turnOffAuthorisationSystem();
// Here we add the first set of metadata to the item
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, one");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, two");
// Here we create the first Relationship to the item
Relationship relationship = relationshipService
.create(context, item, authorItem, isAuthorOfPublication, -1, -1);
context.restoreAuthSystemState();
// The code below performs the mentioned assertions to ensure the place is correct
List<MetadataValue> list = itemService
.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertThat(list.size(), equalTo(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 1, list.get(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 2, list.get(2));
assertThat(relationship.getLeftPlace(), equalTo(2));
context.turnOffAuthorisationSystem();
// This is where we add the second set of metadata values
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, three");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, four");
// Here we create an Item so that we can create another relationship with this item
WorkspaceItem authorIs = workspaceItemService.create(context, col, false);
Item secondAuthorItem = installItemService.installItem(context, authorIs);
itemService.addMetadata(context, secondAuthorItem, "relationship", "type", null, null, "Person");
itemService.addMetadata(context, secondAuthorItem, "person", "familyName", null, null, "familyNameTwo");
itemService.addMetadata(context, secondAuthorItem, "person", "givenName", null, null, "firstNameTwo");
Relationship relationshipTwo = relationshipService
.create(context, item, secondAuthorItem, isAuthorOfPublication, -1, -1);
context.restoreAuthSystemState();
// Here we retrieve the list of metadata again to perform the assertions on the places below as mentioned
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 1, list.get(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 2, list.get(2));
assertThat(relationship.getLeftPlace(), equalTo(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 3, list.get(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, four", null, 4, list.get(4));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyNameTwo, firstNameTwo",
"virtual::" + relationshipTwo.getID(), 5, list.get(5));
assertThat(relationshipTwo.getLeftPlace(), equalTo(5));
}
/**
* This test is virtually the same as above, only this time we'll add Relationships with leftPlaces already set
* equal to what they HAVE to be. So in the first test addMetadataAndRelationshipTest, we didn't specify a place
* and left it up to the Service to determine it, here we provide a correct place already.
* We perform the exact same logic except that we give a proper place already to the Relationships and we
* perform the same checks
* @throws Exception If something goes wrong
*/
@Test
public void AddMetadataAndRelationshipWithSpecificPlaceTest() throws Exception {
context.turnOffAuthorisationSystem();
// Here we add the first set of metadata to the item
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, one");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, two");
// Here we create the first Relationship to the item with the specific leftPlace: 2
Relationship relationship = relationshipService.create(context, item, authorItem, isAuthorOfPublication, 2, -1);
context.restoreAuthSystemState();
// The code below performs the mentioned assertions to ensure the place is correct
List<MetadataValue> list = itemService
.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertThat(list.size(), equalTo(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 1, list.get(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 2, list.get(2));
assertThat(relationship.getLeftPlace(), equalTo(2));
context.turnOffAuthorisationSystem();
// This is where we add the second set of metadata values
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, three");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, four");
// Here we create an Item so that we can create another relationship with this item. We'll give this
// Relationship a specific place as well
WorkspaceItem authorIs = workspaceItemService.create(context, col, false);
Item secondAuthorItem = installItemService.installItem(context, authorIs);
itemService.addMetadata(context, secondAuthorItem, "relationship", "type", null, null, "Person");
itemService.addMetadata(context, secondAuthorItem, "person", "familyName", null, null, "familyNameTwo");
itemService.addMetadata(context, secondAuthorItem, "person", "givenName", null, null, "firstNameTwo");
Relationship relationshipTwo = relationshipService
.create(context, item, secondAuthorItem, isAuthorOfPublication, 5, -1);
context.restoreAuthSystemState();
// Here we retrieve the list of metadata again to perform the assertions on the places below as mentioned
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 1, list.get(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 2, list.get(2));
assertThat(relationship.getLeftPlace(), equalTo(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 3, list.get(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, four", null, 4, list.get(4));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyNameTwo, firstNameTwo",
"virtual::" + relationshipTwo.getID(), 5, list.get(5));
assertThat(relationshipTwo.getLeftPlace(), equalTo(5));
}
/**
* In this test, our goal will be to add a bunch of metadata values to then remove one of them. We'll check the list
* of metadata values for the item and check that the places have not been altered for the metadata values IF an
* item.update hadn't been called yet. We'll then create a Relationship (by which an item.update will be called)
* and then we check that the places are set correctly.
* We then repeat this process once more and check that everything works as intended
* @throws Exception
*/
@Test
public void AddAndRemoveMetadataAndRelationshipsTest() throws Exception {
context.turnOffAuthorisationSystem();
// Here we add the first set of metadata to the item
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, one");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, two");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, three");
// Get a specific metadatavlaue to remove
MetadataValue metadataValueToRemove = itemService.getMetadata(item, "dc", "contributor", "author", Item.ANY)
.get(1);
// Remove the actual metadata value
item.removeMetadata(metadataValueToRemove);
metadataValueService.delete(context, metadataValueToRemove);
context.restoreAuthSystemState();
// Retrieve the list of mdv again
List<MetadataValue> list = itemService
.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
// Verify we only have 2 mdv left
assertThat(list.size(), equalTo(2));
// Check that these places are still intact after the deletion as the place doesn't get updated until an
// item.update has been called
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(1));
context.turnOffAuthorisationSystem();
// Create a relationship with this item with a spcific place
Relationship relationship = relationshipService.create(context, item, authorItem, isAuthorOfPublication, 1, -1);
context.restoreAuthSystemState();
// Retrieve the list again and verify that the creation of the Relationship added an additional mdv
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertThat(list.size(), equalTo(3));
// Assert that the mdv are well placed
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 1, list.get(1));
assertThat(relationship.getLeftPlace(), equalTo(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(2));
context.turnOffAuthorisationSystem();
// Add two extra mdv
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, four");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, five");
//This is author "test, four" that we're removing
metadataValueToRemove = itemService.getMetadata(item, "dc", "contributor", "author", Item.ANY).get(3);
item.removeMetadata(metadataValueToRemove);
metadataValueService.delete(context, metadataValueToRemove);
context.restoreAuthSystemState();
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
// Check that these places are still intact after the deletion as the place doesn't get updated until an
// item.update has been called
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 1, list.get(1));
assertThat(relationship.getLeftPlace(), equalTo(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, five", null, 4, list.get(3));
context.turnOffAuthorisationSystem();
// Create an additional item for another relationship
WorkspaceItem authorIs = workspaceItemService.create(context, col, false);
Item secondAuthorItem = installItemService.installItem(context, authorIs);
itemService.addMetadata(context, secondAuthorItem, "relationship", "type", null, null, "Person");
itemService.addMetadata(context, secondAuthorItem, "person", "familyName", null, null, "familyNameTwo");
itemService.addMetadata(context, secondAuthorItem, "person", "givenName", null, null, "firstNameTwo");
Relationship relationshipTwo = relationshipService
.create(context, item, secondAuthorItem, isAuthorOfPublication, 3, -1);
context.restoreAuthSystemState();
// Check that the other mdv are still okay and that the creation of the relationship added
// another correct mdv to the item
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 1, list.get(1));
assertThat(relationship.getLeftPlace(), equalTo(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyNameTwo, firstNameTwo",
"virtual::" + relationshipTwo.getID(), 3, list.get(3));
assertThat(relationshipTwo.getLeftPlace(), equalTo(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, five", null, 4, list.get(4));
}
@Test
public void AddAndUpdateMetadataAndRelationshipsTest() throws Exception {
context.turnOffAuthorisationSystem();
// Add metadata and relationships to the item
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, one");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, two");
itemService.addMetadata(context, item, dcSchema, contributorElement, authorQualifier, null, "test, three");
Relationship relationship = relationshipService
.create(context, item, authorItem, isAuthorOfPublication, -1, -1);
context.restoreAuthSystemState();
// Get the list of mdv and assert that they're correct
List<MetadataValue> list = itemService
.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertThat(list.size(), equalTo(4));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 1, list.get(1));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 3, list.get(3));
assertThat(relationship.getLeftPlace(), equalTo(3));
context.turnOffAuthorisationSystem();
MetadataValue metadataValueToUpdate = itemService.getMetadata(item, "dc", "contributor", "author", Item.ANY)
.get(1);
// Switching the places of this relationship and metadata value to verify in the test later on that this
// updating works
metadataValueToUpdate.setPlace(3);
metadataValueService.update(context, metadataValueToUpdate);
relationship.setLeftPlace(1);
relationshipService.update(context, relationship);
context.restoreAuthSystemState();
// Retrieve the list again and verify that the updating did indeed work
list = itemService.getMetadata(item, dcSchema, contributorElement, authorQualifier, Item.ANY);
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, one", null, 0, list.get(0));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, two", null, 3, list.get(3));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "test, three", null, 2, list.get(2));
assertMetadataValue(authorQualifier, contributorElement, dcSchema, "familyName, firstName",
"virtual::" + relationship.getID(), 1, list.get(1));
assertThat(relationship.getLeftPlace(), equalTo(1));
}
private void assertMetadataValue(String authorQualifier, String contributorElement, String dcSchema, String value,
String authority, int place, MetadataValue metadataValue) {
assertThat(metadataValue.getValue(), equalTo(value));
assertThat(metadataValue.getMetadataField().getMetadataSchema().getName(), equalTo(dcSchema));
assertThat(metadataValue.getMetadataField().getElement(), equalTo(contributorElement));
assertThat(metadataValue.getMetadataField().getQualifier(), equalTo(authorQualifier));
assertThat(metadataValue.getAuthority(), equalTo(authority));
assertThat(metadataValue.getPlace(), equalTo(place));
}
}

View File

@@ -114,11 +114,11 @@ public class RelationshipServiceImplTest {
Item item = mock(Item.class); Item item = mock(Item.class);
// Mock DAO to return mocked left place as 0 // Mock DAO to return mocked left place as 0
when(relationshipDAO.findLeftPlaceByLeftItem(context, item)).thenReturn(0); when(relationshipDAO.findNextLeftPlaceByLeftItem(context, item)).thenReturn(0);
// The left place reported from out mocked item should match the DAO's report of the left place // The left place reported from out mocked item should match the DAO's report of the left place
assertEquals("TestFindLeftPlaceByLeftItem 0", relationshipDAO.findLeftPlaceByLeftItem(context, item), assertEquals("TestFindLeftPlaceByLeftItem 0", relationshipDAO.findNextLeftPlaceByLeftItem(context, item),
relationshipService.findLeftPlaceByLeftItem(context, item)); relationshipService.findNextLeftPlaceByLeftItem(context, item));
} }
@Test @Test
@@ -127,11 +127,11 @@ public class RelationshipServiceImplTest {
Item item = mock(Item.class); Item item = mock(Item.class);
// Mock lower level DAO to return mocked right place as 0 // Mock lower level DAO to return mocked right place as 0
when(relationshipDAO.findRightPlaceByRightItem(context, item)).thenReturn(0); when(relationshipDAO.findNextRightPlaceByRightItem(context, item)).thenReturn(0);
// The right place reported from out mocked item should match the DAO's report of the right place // The right place reported from out mocked item should match the DAO's report of the right place
assertEquals("TestFindRightPlaceByRightItem 0", relationshipDAO.findRightPlaceByRightItem(context, item), assertEquals("TestFindRightPlaceByRightItem 0", relationshipDAO.findNextRightPlaceByRightItem(context, item),
relationshipService.findRightPlaceByRightItem(context, item)); relationshipService.findNextRightPlaceByRightItem(context, item));
} }
@Test @Test

View File

@@ -138,24 +138,24 @@ public class RelationshipDAOImplTest extends AbstractIntegrationTest {
} }
/** /**
* Test findLeftPlaceByLeftItem should return 0 given our test left Item itemOne. * Test findNextLeftPlaceByLeftItem should return 0 given our test left Item itemOne.
* *
* @throws Exception * @throws Exception
*/ */
@Test @Test
public void testFindLeftPlaceByLeftItem() throws Exception { public void testFindNextLeftPlaceByLeftItem() throws Exception {
assertEquals("TestLeftPlaceByLeftItem 0", 0, relationshipService.findLeftPlaceByLeftItem(context, assertEquals("TestNextLeftPlaceByLeftItem 0", 1, relationshipService.findNextLeftPlaceByLeftItem(context,
itemOne)); itemOne));
} }
/** /**
* Test findRightPlaceByRightItem should return 0 given our test right Item itemTwo. * Test findNextRightPlaceByRightItem should return 0 given our test right Item itemTwo.
* *
* @throws Exception * @throws Exception
*/ */
@Test @Test
public void testFindRightPlaceByRightItem() throws Exception { public void testFindNextRightPlaceByRightItem() throws Exception {
assertEquals("TestRightPlaceByRightItem 0", 0, relationshipService.findRightPlaceByRightItem(context, assertEquals("TestNextRightPlaceByRightItem 0", 1, relationshipService.findNextRightPlaceByRightItem(context,
itemTwo)); itemTwo));
} }

View File

@@ -0,0 +1,93 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.external.provider.impl;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.ExternalDataProvider;
public class MockDataProvider implements ExternalDataProvider {
private Map<String, ExternalDataObject> mockLookupMap;
private String sourceIdentifier;
/**
* Generic getter for the sourceIdentifier
* @return the sourceIdentifier value of this MockDataProvider
*/
public String getSourceIdentifier() {
return sourceIdentifier;
}
public Optional<ExternalDataObject> getExternalDataObject(String id) {
ExternalDataObject externalDataObject = mockLookupMap.get(id);
if (externalDataObject == null) {
return Optional.empty();
} else {
return Optional.of(externalDataObject);
}
}
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
List<ExternalDataObject> listToReturn = new LinkedList<>();
for (Map.Entry<String, ExternalDataObject> entry : mockLookupMap.entrySet()) {
if (StringUtils.containsIgnoreCase(entry.getKey(), query)) {
listToReturn.add(entry.getValue());
}
}
return listToReturn;
}
@Override
public boolean supports(String source) {
return StringUtils.equalsIgnoreCase(sourceIdentifier, source);
}
@Override
public int getNumberOfResults(String query) {
return searchExternalDataObjects(query, 0, 100).size();
}
/**
* Generic setter for the sourceIdentifier
* @param sourceIdentifier The sourceIdentifier to be set on this MockDataProvider
*/
public void setSourceIdentifier(String sourceIdentifier) {
this.sourceIdentifier = sourceIdentifier;
}
public void init() throws IOException {
mockLookupMap = new HashMap<>();
List<String> externalDataObjectsToMake = new LinkedList<>();
externalDataObjectsToMake.add("one");
externalDataObjectsToMake.add("two");
externalDataObjectsToMake.add("three");
externalDataObjectsToMake.add("onetwo");
for (String id : externalDataObjectsToMake) {
ExternalDataObject externalDataObject = new ExternalDataObject("mock");
externalDataObject.setId(id);
externalDataObject.setValue(id);
externalDataObject.setDisplayValue(id);
List<MetadataValueDTO> list = new LinkedList<>();
list.add(new MetadataValueDTO("dc", "contributor", "author", null, "Donald, Smith"));
externalDataObject.setMetadata(list);
mockLookupMap.put(id, externalDataObject);
}
}
}

View File

@@ -0,0 +1,136 @@
/**
* 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.scripts;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.LinkedList;
import java.util.List;
import org.dspace.AbstractUnitTest;
import org.junit.Test;
public class DSpaceCommandLineParameterTest extends AbstractUnitTest {
@Test
public void constructorTest() {
String key = "-c";
String value = "test";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
assertThat("constructorTest 0", dSpaceCommandLineParameter.getName(), equalTo(key));
assertThat("constructorTest 1", dSpaceCommandLineParameter.getValue(), equalTo(value));
}
@Test
public void constructorTestNullValue() {
String key = "-c";
String value = null;
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
assertThat("constructorTest 0", dSpaceCommandLineParameter.getName(), equalTo(key));
assertThat("constructorTest 1", dSpaceCommandLineParameter.getValue(), equalTo(value));
}
@Test
public void singleParameterConstructorTest() {
String parameter = "-c test";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(parameter);
assertThat("singleParameterConstructorTest 0", dSpaceCommandLineParameter.getName(), equalTo("-c"));
assertThat("singleParameterConstructorTest 1", dSpaceCommandLineParameter.getValue(), equalTo("test"));
}
@Test
public void singleParameterConstructorTestNoValue() {
String parameter = "-c";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(parameter);
assertThat("singleParameterConstructorTest 0", dSpaceCommandLineParameter.getName(), equalTo("-c"));
assertThat("singleParameterConstructorTest 1", dSpaceCommandLineParameter.getValue(), equalTo(null));
}
@Test
public void toStringTest() {
String key = "-c";
String value = "test";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
assertThat("toStringTest 0", dSpaceCommandLineParameter.getName(), equalTo(key));
assertThat("toStringTest 1", dSpaceCommandLineParameter.getValue(), equalTo(value));
assertThat("toStringTest 2", dSpaceCommandLineParameter.toString(), equalTo("-c test"));
}
@Test
public void toStringTestNullValue() {
String key = "-c";
String value = null;
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
assertThat("toStringTest 0", dSpaceCommandLineParameter.getName(), equalTo(key));
assertThat("toStringTest 1", dSpaceCommandLineParameter.getValue(), equalTo(value));
assertThat("toStringTest 2", dSpaceCommandLineParameter.toString(), equalTo("-c"));
}
@Test
public void equalsTest() {
String key = "-c";
String value = "test";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
DSpaceCommandLineParameter dSpaceCommandLineParameter1 = new DSpaceCommandLineParameter(key, value);
assertThat("toStringTest 0", dSpaceCommandLineParameter.getName(), equalTo(key));
assertThat("toStringTest 1", dSpaceCommandLineParameter.getValue(), equalTo(value));
assertThat("toStringTest 0", dSpaceCommandLineParameter1.getName(), equalTo(key));
assertThat("toStringTest 1", dSpaceCommandLineParameter1.getValue(), equalTo(value));
assertTrue(dSpaceCommandLineParameter.equals(dSpaceCommandLineParameter1));
}
@Test
public void concatenateTest() {
String key = "-c";
String value = "test";
DSpaceCommandLineParameter dSpaceCommandLineParameter = new DSpaceCommandLineParameter(key, value);
DSpaceCommandLineParameter dSpaceCommandLineParameter1 = new DSpaceCommandLineParameter(key, value);
String key2 = "-r";
String value2 = "testing";
DSpaceCommandLineParameter dSpaceCommandLineParameter2 = new DSpaceCommandLineParameter(key2, value2);
String key3 = "-t";
String value3 = null;
DSpaceCommandLineParameter dSpaceCommandLineParameter3 = new DSpaceCommandLineParameter(key3, value3);
List<DSpaceCommandLineParameter> dSpaceCommandLineParameterList = new LinkedList<>();
dSpaceCommandLineParameterList.add(dSpaceCommandLineParameter);
dSpaceCommandLineParameterList.add(dSpaceCommandLineParameter1);
dSpaceCommandLineParameterList.add(dSpaceCommandLineParameter2);
dSpaceCommandLineParameterList.add(dSpaceCommandLineParameter3);
String concatenedString = DSpaceCommandLineParameter.concatenate(dSpaceCommandLineParameterList);
assertThat("concatenateTest", concatenedString, equalTo(
dSpaceCommandLineParameter.toString() + DSpaceCommandLineParameter.SEPARATOR + dSpaceCommandLineParameter1
.toString() + DSpaceCommandLineParameter.SEPARATOR + dSpaceCommandLineParameter2
.toString() + DSpaceCommandLineParameter.SEPARATOR + dSpaceCommandLineParameter3.toString()));
}
}

View File

@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.scripts.impl;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.scripts.DSpaceRunnable;
public class MockDSpaceRunnableScript extends DSpaceRunnable {
private MockDSpaceRunnableScript() {
Options options = constructOptions();
this.options = options;
}
@Override
public void internalRun() throws Exception {
}
@Override
public void setup() throws ParseException {
if (!commandLine.hasOption("i")) {
throw new ParseException("-i is a mandatory parameter");
}
}
private Options constructOptions() {
Options options = new Options();
options.addOption("r", "remove", true, "description r");
options.getOption("r").setType(String.class);
options.addOption("i", "index", true, "description i");
options.getOption("i").setType(boolean.class);
options.getOption("i").setRequired(true);
return options;
}
}

View File

@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.converter.EPersonConverter; import org.dspace.app.rest.converter.EPersonConverter;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.AuthenticationStatusRest; import org.dspace.app.rest.model.AuthenticationStatusRest;
@@ -18,6 +19,7 @@ import org.dspace.app.rest.model.AuthnRest;
import org.dspace.app.rest.model.EPersonRest; import org.dspace.app.rest.model.EPersonRest;
import org.dspace.app.rest.model.hateoas.AuthenticationStatusResource; import org.dspace.app.rest.model.hateoas.AuthenticationStatusResource;
import org.dspace.app.rest.model.hateoas.AuthnResource; import org.dspace.app.rest.model.hateoas.AuthnResource;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -49,6 +51,9 @@ public class AuthenticationRestController implements InitializingBean {
@Autowired @Autowired
DiscoverableEndpointsService discoverableEndpointsService; DiscoverableEndpointsService discoverableEndpointsService;
@Autowired
private ConverterService converter;
@Autowired @Autowired
private EPersonConverter ePersonConverter; private EPersonConverter ePersonConverter;
@@ -65,24 +70,24 @@ public class AuthenticationRestController implements InitializingBean {
} }
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public AuthnResource authn() throws SQLException { public AuthnResource authn() {
AuthnResource authnResource = new AuthnResource(new AuthnRest(), utils); AuthnRest authnRest = new AuthnRest();
halLinkService.addLinks(authnResource); authnRest.setProjection(utils.obtainProjection());
return authnResource; return converter.toResource(authnRest);
} }
@RequestMapping(value = "/status", method = RequestMethod.GET) @RequestMapping(value = "/status", method = RequestMethod.GET)
public AuthenticationStatusResource status(HttpServletRequest request) throws SQLException { public AuthenticationStatusResource status(HttpServletRequest request) throws SQLException {
Context context = ContextUtil.obtainContext(request); Context context = ContextUtil.obtainContext(request);
EPersonRest ePersonRest = null; EPersonRest ePersonRest = null;
Projection projection = utils.obtainProjection();
if (context.getCurrentUser() != null) { if (context.getCurrentUser() != null) {
ePersonRest = ePersonConverter.fromModelWithGroups(context, context.getCurrentUser()); ePersonRest = ePersonConverter.fromModelWithGroups(context, context.getCurrentUser(), projection);
} }
AuthenticationStatusResource authenticationStatusResource = new AuthenticationStatusResource( AuthenticationStatusRest authenticationStatusRest = new AuthenticationStatusRest(ePersonRest);
new AuthenticationStatusRest(ePersonRest), utils); authenticationStatusRest.setProjection(projection);
AuthenticationStatusResource authenticationStatusResource = converter.toResource(authenticationStatusRest);
halLinkService.addLinks(authenticationStatusResource);
return authenticationStatusResource; return authenticationStatusResource;
} }

View File

@@ -0,0 +1,153 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import static org.dspace.core.Constants.BUNDLE;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.hateoas.BundleResource;
import org.dspace.app.rest.repository.BitstreamRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.DSpaceObject;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Controller to access bitstreams and the bundles they're in
* Endpoint: /api/core/bitstreams/{uuid}
* This controller can:
* - request bundle a bitstream is in (GET /api/core/bitstreams/{uuid}/bundle)
* - move bitstreams between bundles (POST /api/core/bitstreams/{uuid}/bundle (text/uri-list) -d link-to-new-bundle)
*
*/
@RestController
@RequestMapping("/api/" + BitstreamRest.CATEGORY + "/" + BitstreamRest.PLURAL_NAME
+ REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/" + BundleRest.NAME)
public class BitstreamBundleController {
@Autowired
private BitstreamService bitstreamService;
@Autowired
ConverterService converter;
@Autowired
HalLinkService halLinkService;
@Autowired
Utils utils;
@Autowired
BitstreamRestRepository bitstreamRestRepository;
/**
* This method gets the bundle of the bitstream that corresponds to to the provided bitstream uuid. When multiple
* bundles are present, only the first will be returned.
*
* @param uuid The UUID of the bitstream for which the bundle will be retrieved
* @param response The response object
* @param request The request object
* @return The wrapped resource containing the first bundle of the bitstream
* @throws IOException
* @throws SQLException
* @throws AuthorizeException
*/
@PreAuthorize("hasPermission(#uuid, 'BITSTREAM', 'READ')")
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
public ResponseEntity<ResourceSupport> getBundle(@PathVariable UUID uuid, HttpServletResponse response,
HttpServletRequest request)
throws IOException, SQLException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
Bitstream bitstream = bitstreamService.find(context, uuid);
if (bitstream == null) {
throw new ResourceNotFoundException(
BitstreamRest.CATEGORY + "." + BitstreamRest.NAME + " with id: " + uuid + " not found");
}
List<Bundle> bundles = bitstream.getBundles();
if (bundles.isEmpty()) {
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
}
BundleResource bundleResource = converter.toResource(
converter.toRest(bundles.get(0), utils.obtainProjection()));
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, bundleResource);
}
/**
* This method moves the bitstream to the bundle corresponding the the link provided in the body of the put request
*
* @param uuid The UUID of the bitstream for which the bundle will be retrieved
* @param response The response object
* @param request The request object
* @return The wrapped resource containing the new bundle of the bitstream
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@RequestMapping(method = RequestMethod.PUT, consumes = {"text/uri-list"})
@PreAuthorize("hasPermission(#uuid, 'BITSTREAM','WRITE')")
@PostAuthorize("returnObject != null")
public BundleRest move(@PathVariable UUID uuid, HttpServletResponse response,
HttpServletRequest request)
throws SQLException, IOException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
List<DSpaceObject> dsoList = utils.constructDSpaceObjectList(context, utils.getStringListFromRequest(request));
if (dsoList.size() != 1 || dsoList.get(0).getType() != BUNDLE) {
throw new UnprocessableEntityException("No bundle has been specified " +
"or the data cannot be resolved to a bundle.");
}
Bitstream bitstream = bitstreamService.find(context, uuid);
if (bitstream == null) {
throw new ResourceNotFoundException("Bitstream with id: " + uuid + " not found");
}
BundleRest bundleRest = bitstreamRestRepository.performBitstreamMove(context, bitstream,
(Bundle) dsoList.get(0));
context.commit();
return bundleRest;
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.ContextUtil.obtainContext; import static org.dspace.app.rest.utils.ContextUtil.obtainContext;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import static org.springframework.web.bind.annotation.RequestMethod.PUT; import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import java.io.IOException; import java.io.IOException;
@@ -22,10 +23,11 @@ import javax.ws.rs.core.Response;
import org.apache.catalina.connector.ClientAbortException; import org.apache.catalina.connector.ClientAbortException;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.BitstreamConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.DSpaceBadRequestException; import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource; import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.MultipartFileSender; import org.dspace.app.rest.utils.MultipartFileSender;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
@@ -65,7 +67,7 @@ import org.springframework.web.bind.annotation.RestController;
*/ */
@RestController @RestController
@RequestMapping("/api/" + BitstreamRest.CATEGORY + "/" + BitstreamRest.PLURAL_NAME @RequestMapping("/api/" + BitstreamRest.CATEGORY + "/" + BitstreamRest.PLURAL_NAME
+ "/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}") + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
public class BitstreamRestController { public class BitstreamRestController {
private static final Logger log = org.apache.logging.log4j.LogManager private static final Logger log = org.apache.logging.log4j.LogManager
@@ -90,7 +92,7 @@ public class BitstreamRestController {
private ConfigurationService configurationService; private ConfigurationService configurationService;
@Autowired @Autowired
BitstreamConverter converter; ConverterService converter;
@Autowired @Autowired
Utils utils; Utils utils;
@@ -238,7 +240,7 @@ public class BitstreamRestController {
context.commit(); context.commit();
return (BitstreamResource) utils.getResourceRepository(BitstreamRest.CATEGORY, BitstreamRest.NAME) BitstreamRest bitstreamRest = converter.toRest(context.reloadEntity(bitstream), Projection.DEFAULT);
.wrapResource(converter.fromModel(context.reloadEntity(bitstream))); return converter.toResource(bitstreamRest);
} }
} }

View File

@@ -0,0 +1,117 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.repository.BundleRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.content.Bundle;
import org.dspace.content.service.BundleService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* Controller to upload bitstreams to a certain bundle, indicated by a uuid in the request
* Usage: POST /api/core/bundles/{uuid}/bitstreams (with file and properties of file in request)
* Example:
* <pre>
* {@code
* curl https://<dspace.server.url>/api/core/bundles/d3599177-0408-403b-9f8d-d300edd79edb/bitstreams
* -XPOST -H 'Content-Type: multipart/form-data' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* -F "file=@Downloads/test.html" \
* -F 'properties={ "name": "test.html", "metadata": { "dc.description": [ { "value": "example file", "language": null,
* "authority": null, "confidence": -1, "place": 0 } ]}, "bundleName": "ORIGINAL" };type=application/json'
* }
* </pre>
*/
@RestController
@RequestMapping("/api/" + BundleRest.CATEGORY + "/" + BundleRest.PLURAL_NAME + "/"
+ REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/" + BitstreamRest.PLURAL_NAME)
public class BundleUploadBitstreamController {
private static final Logger log = LogManager.getLogger();
@Autowired
protected Utils utils;
@Autowired
private BundleService bundleService;
@Autowired
private BundleRestRepository bundleRestRepository;
@Autowired
private ConverterService converter;
/**
* Method to upload a Bitstream to a Bundle with the given UUID in the URL. This will create a Bitstream with the
* file provided in the request and attach this to the Item that matches the UUID in the URL.
* This will only work for uploading one file, any extra files will silently be ignored
*
* @return The created BitstreamResource
*/
@RequestMapping(method = RequestMethod.POST, headers = "content-type=multipart/form-data")
@PreAuthorize("hasPermission(#uuid, 'BUNDLE', 'ADD') && hasPermission(#uuid, 'BUNDLE', 'WRITE')")
public ResponseEntity<ResourceSupport> uploadBitstream(HttpServletRequest request, @PathVariable UUID uuid,
@RequestParam("file") MultipartFile uploadfile,
@RequestParam(value = "properties", required = false) String properties) {
Context context = ContextUtil.obtainContext(request);
Bundle bundle = null;
try {
bundle = bundleService.find(context, uuid);
} catch (SQLException e) {
log.error("Something went wrong trying to find the Bundle with uuid: " + uuid, e);
}
if (bundle == null) {
throw new ResourceNotFoundException("The given uuid did not resolve to a Bundle on the server: " + uuid);
}
InputStream fileInputStream = null;
try {
fileInputStream = uploadfile.getInputStream();
} catch (IOException e) {
log.error("Something went wrong when trying to read the inputstream from the given file in the request",
e);
throw new UnprocessableEntityException("The InputStream from the file couldn't be read", e);
}
BitstreamRest bitstreamRest = bundleRestRepository.uploadBitstream(
context, bundle, uploadfile.getOriginalFilename(), fileInputStream, properties);
BitstreamResource bitstreamResource = converter.toResource(bitstreamRest);
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, bitstreamResource);
}
}

View File

@@ -12,6 +12,7 @@ import java.util.UUID;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.converter.HarvestedCollectionConverter; import org.dspace.app.rest.converter.HarvestedCollectionConverter;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.HarvestedCollectionRest; import org.dspace.app.rest.model.HarvestedCollectionRest;
@@ -48,6 +49,9 @@ public class CollectionHarvestSettingsController {
@Autowired @Autowired
CollectionService collectionService; CollectionService collectionService;
@Autowired
ConverterService converter;
@Autowired @Autowired
HarvestedCollectionService harvestedCollectionService; HarvestedCollectionService harvestedCollectionService;
@@ -80,9 +84,7 @@ public class CollectionHarvestSettingsController {
} }
HarvestedCollectionRest harvestedCollectionRest = harvestedCollectionRestRepository.findOne(collection); HarvestedCollectionRest harvestedCollectionRest = harvestedCollectionRestRepository.findOne(collection);
HarvestedCollectionResource resource = new HarvestedCollectionResource(harvestedCollectionRest); HarvestedCollectionResource resource = converter.toResource(harvestedCollectionRest);
halLinkService.addLinks(resource);
return resource; return resource;
} }
@@ -114,8 +116,7 @@ public class CollectionHarvestSettingsController {
// Return a harvestedCollectionResource only if a new harvestedCollection was created // Return a harvestedCollectionResource only if a new harvestedCollection was created
if (harvestedCollectionRest != null) { if (harvestedCollectionRest != null) {
harvestedCollectionResource = new HarvestedCollectionResource(harvestedCollectionRest); harvestedCollectionResource = converter.toResource(harvestedCollectionRest);
halLinkService.addLinks(harvestedCollectionResource);
} }
context.commit(); context.commit();

View File

@@ -0,0 +1,160 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.BadRequestException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.hateoas.ItemResource;
import org.dspace.app.rest.repository.CollectionRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* This RestController takes care of the creation and retrieval of Collection's Item templates
* This class will receive the UUID of a Collection and it'll perform actions on its nested objects
*/
@RestController
@RequestMapping("/api/" + CollectionRest.CATEGORY + "/" + CollectionRest.PLURAL_NAME
+ REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/itemtemplate")
public class CollectionItemtemplateController {
@Autowired
private Utils utils;
@Autowired
private CollectionRestRepository collectionRestRepository;
@Autowired
private CollectionService collectionService;
/**
* This method will create an Item and add it as a template to a Collection.
*
* Example:
* <pre>
* {@code
* curl http://<dspace.server.url>/api/core/collections/51715dd3-5590-49f2-b227-6a663c849921/itemtemplate
* -XPOST -H 'Content-Type: Content-Type:application/json' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* --data '{
* "metadata": {
* "dc.type": [
* {
* "value": "Journal Article",
* "language": "en",
* "authority": null,
* "confidence": -1
* }
* ]
* },
* "inArchive": false,
* "discoverable": false,
* "withdrawn": false,
* "type": "item"
* }'
* }
* </pre>
* @param request The request as described above
* @param uuid The UUID of the Collection for which the template item should be made
* @param itemBody The new item
* @return The created template
* @throws SQLException
* @throws AuthorizeException
*/
@PreAuthorize("hasPermission(#uuid, 'COLLECTION', 'WRITE')")
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<ResourceSupport> createTemplateItem(HttpServletRequest request,
@PathVariable UUID uuid,
@RequestBody(required = false) JsonNode itemBody)
throws SQLException, AuthorizeException {
if (itemBody == null) {
throw new BadRequestException("The new item should be included as json in the body of this request");
}
Context context = ContextUtil.obtainContext(request);
Collection collection = getCollection(context, uuid);
ItemRest inputItemRest;
try {
ObjectMapper mapper = new ObjectMapper();
inputItemRest = mapper.readValue(itemBody.toString(), ItemRest.class);
} catch (IOException e1) {
throw new UnprocessableEntityException("Error parsing request body", e1);
}
ItemRest templateItem = collectionRestRepository.createTemplateItem(context, collection, inputItemRest);
context.commit();
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null,
new ItemResource(templateItem, utils));
}
/**
* This method gets the template Item based on the owning Collection
*
* <pre>
* {@code
* curl http://<dspace.server.url>/api/core/collections/51715dd3-5590-49f2-b227-6a663c849921/itemtemplate
* -XGET \
* -H 'Authorization: Bearer eyJhbGciOiJI...'
* }
* </pre>
* @param request
* @param uuid The UUID of the Collection from which you want the template item
* @return The template item from the Collection in the request
* @throws SQLException
*/
@PreAuthorize("hasPermission(#uuid, 'COLLECTION', 'READ')")
@RequestMapping(method = RequestMethod.GET)
public ItemResource getTemplateItem(HttpServletRequest request, @PathVariable UUID uuid)
throws SQLException {
Context context = ContextUtil.obtainContext(request);
Collection collection = getCollection(context, uuid);
ItemRest templateItem = collectionRestRepository.getTemplateItem(collection);
return new ItemResource(templateItem, utils);
}
private Collection getCollection(Context context, UUID uuid) throws SQLException {
Collection collection = collectionService.find(context, uuid);
if (collection == null) {
throw new ResourceNotFoundException(
"The given uuid did not resolve to a collection on the server: " + uuid);
}
return collection;
}
}

View File

@@ -14,6 +14,7 @@ import java.util.Objects;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.FacetConfigurationRest; import org.dspace.app.rest.model.FacetConfigurationRest;
import org.dspace.app.rest.model.FacetResultsRest; import org.dspace.app.rest.model.FacetResultsRest;
@@ -61,6 +62,9 @@ public class DiscoveryRestController implements InitializingBean {
@Autowired @Autowired
private HalLinkService halLinkService; private HalLinkService halLinkService;
@Autowired
private ConverterService converter;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
discoverableEndpointsService discoverableEndpointsService
@@ -74,8 +78,7 @@ public class DiscoveryRestController implements InitializingBean {
throws Exception { throws Exception {
SearchSupportRest searchSupportRest = discoveryRestRepository.getSearchSupport(); SearchSupportRest searchSupportRest = discoveryRestRepository.getSearchSupport();
SearchSupportResource searchSupportResource = new SearchSupportResource(searchSupportRest); SearchSupportResource searchSupportResource = converter.toResource(searchSupportRest);
halLinkService.addLinks(searchSupportResource);
return searchSupportResource; return searchSupportResource;
} }
@@ -91,9 +94,7 @@ public class DiscoveryRestController implements InitializingBean {
SearchConfigurationRest searchConfigurationRest = discoveryRestRepository SearchConfigurationRest searchConfigurationRest = discoveryRestRepository
.getSearchConfiguration(dsoScope, configuration); .getSearchConfiguration(dsoScope, configuration);
SearchConfigurationResource searchConfigurationResource = new SearchConfigurationResource( SearchConfigurationResource searchConfigurationResource = converter.toResource(searchConfigurationRest);
searchConfigurationRest);
halLinkService.addLinks(searchConfigurationResource);
return searchConfigurationResource; return searchConfigurationResource;
} }
@@ -142,9 +143,8 @@ public class DiscoveryRestController implements InitializingBean {
} }
//Get the Search results in JSON format //Get the Search results in JSON format
SearchResultsRest searchResultsRest = null; SearchResultsRest searchResultsRest = discoveryRestRepository
searchResultsRest = discoveryRestRepository .getSearchObjects(query, dsoType, dsoScope, configuration, searchFilters, page, utils.obtainProjection());
.getSearchObjects(query, dsoType, dsoScope, configuration, searchFilters, page);
//Convert the Search JSON results to paginated HAL resources //Convert the Search JSON results to paginated HAL resources
SearchResultsResource searchResultsResource = new SearchResultsResource(searchResultsRest, utils, page); SearchResultsResource searchResultsResource = new SearchResultsResource(searchResultsRest, utils, page);
@@ -164,7 +164,7 @@ public class DiscoveryRestController implements InitializingBean {
FacetConfigurationRest facetConfigurationRest = discoveryRestRepository FacetConfigurationRest facetConfigurationRest = discoveryRestRepository
.getFacetsConfiguration(dsoScope, configuration); .getFacetsConfiguration(dsoScope, configuration);
FacetConfigurationResource facetConfigurationResource = new FacetConfigurationResource(facetConfigurationRest); FacetConfigurationResource facetConfigurationResource = converter.toResource(facetConfigurationRest);
halLinkService.addLinks(facetConfigurationResource, pageable); halLinkService.addLinks(facetConfigurationResource, pageable);
return facetConfigurationResource; return facetConfigurationResource;
@@ -192,7 +192,7 @@ public class DiscoveryRestController implements InitializingBean {
FacetResultsRest facetResultsRest = discoveryRestRepository FacetResultsRest facetResultsRest = discoveryRestRepository
.getFacetObjects(facetName, prefix, query, dsoType, dsoScope, configuration, searchFilters, page); .getFacetObjects(facetName, prefix, query, dsoType, dsoScope, configuration, searchFilters, page);
FacetResultsResource facetResultsResource = new FacetResultsResource(facetResultsRest); FacetResultsResource facetResultsResource = converter.toResource(facetResultsRest);
halLinkService.addLinks(facetResultsResource, page); halLinkService.addLinks(facetResultsResource, page);
return facetResultsResource; return facetResultsResource;

View File

@@ -0,0 +1,96 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.ExternalSourceEntryRest;
import org.dspace.app.rest.model.hateoas.ExternalSourceEntryResource;
import org.dspace.app.rest.repository.ExternalSourceRestRepository;
import org.dspace.app.rest.utils.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.PagedResources;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* This RestController takes care of the retrieval of External data from various endpoints and providers depending
* on the calls it receives
*/
@RestController
@RequestMapping("/api/integration/externalsources/{externalSourceName}")
public class ExternalSourcesRestController {
@Autowired
private ExternalSourceRestRepository externalSourceRestRepository;
@Autowired
protected Utils utils;
@Autowired
HalLinkService linkService;
/**
* This method will retrieve all the ExternalSourceEntries for the ExternalSource for the given externalSourceName
* param
*
* curl -X GET http://<dspace.restUrl>/api/integration/externalsources/orcidV2/entries
*
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
* @param query The query used in the lookup
* @param parent The parent used in the lookup
* @param pageable The pagination object
* @param assembler The assembler object
* @return A paginated list of ExternalSourceEntryResource objects that comply with the params
*/
@RequestMapping(method = RequestMethod.GET, value = "/entries")
public PagedResources<ExternalSourceEntryResource> getExternalSourceEntries(
@PathVariable("externalSourceName") String externalSourceName,
@RequestParam(name = "query") String query,
@RequestParam(name = "parent", required = false) String parent,
Pageable pageable, PagedResourcesAssembler assembler) {
Page<ExternalSourceEntryRest> externalSourceEntryRestPage = externalSourceRestRepository
.getExternalSourceEntries(externalSourceName, query, parent, pageable);
Page<ExternalSourceEntryResource> externalSourceEntryResources = externalSourceEntryRestPage
.map(externalSourceEntryRest -> new ExternalSourceEntryResource(externalSourceEntryRest));
externalSourceEntryResources.forEach(linkService::addLinks);
PagedResources<ExternalSourceEntryResource> result = assembler.toResource(externalSourceEntryResources);
return result;
}
/**
* This method will retrieve one ExternalSourceEntryResource based on the ExternalSource for the given
* externalSourceName and with the given entryId
*
* curl -X GET http://<dspace.restUrl>/api/integration/externalsources/orcidV2/entries/0000-0000-0000-0000
*
* @param externalSourceName The externalSourceName that defines which ExternalDataProvider is used
* @param entryId The entryId used for the lookup
* @return An ExternalSourceEntryResource that complies with the above params
*/
@RequestMapping(method = RequestMethod.GET, value = "/entryValues/{entryId}")
public ExternalSourceEntryResource getExternalSourceEntryValue(@PathVariable("externalSourceName") String
externalSourceName,
@PathVariable("entryId") String entryId) {
ExternalSourceEntryRest externalSourceEntryRest = externalSourceRestRepository
.getExternalSourceEntryValue(externalSourceName, entryId);
ExternalSourceEntryResource externalSourceEntryResource = new ExternalSourceEntryResource(
externalSourceEntryRest);
linkService.addLinks(externalSourceEntryResource);
return externalSourceEntryResource;
}
}

View File

@@ -12,12 +12,12 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.HarvesterMetadataRest; import org.dspace.app.rest.model.HarvesterMetadataRest;
import org.dspace.app.rest.model.hateoas.HarvesterMetadataResource; import org.dspace.app.rest.model.hateoas.HarvesterMetadataResource;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.OAIHarvester;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
@@ -38,6 +38,9 @@ public class HarvesterMetadataController {
@Autowired @Autowired
private HalLinkService halLinkService; private HalLinkService halLinkService;
@Autowired
private ConverterService converter;
/** /**
* GET endpoint that returns all available metadata formats * GET endpoint that returns all available metadata formats
* @param request The request object * @param request The request object
@@ -50,11 +53,10 @@ public class HarvesterMetadataController {
List<Map<String,String>> configs = OAIHarvester.getAvailableMetadataFormats(); List<Map<String,String>> configs = OAIHarvester.getAvailableMetadataFormats();
HarvesterMetadataRest data = new HarvesterMetadataRest(); HarvesterMetadataRest data = new HarvesterMetadataRest();
data.setProjection(utils.obtainProjection());
data.setConfigs(configs); data.setConfigs(configs);
HarvesterMetadataResource resource = new HarvesterMetadataResource(data, utils); HarvesterMetadataResource resource = converter.toResource(data);
halLinkService.addLinks(resource);
return resource; return resource;
} }

View File

@@ -13,15 +13,15 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.atteo.evo.inflector.English; import org.atteo.evo.inflector.English;
import org.dspace.app.rest.converter.GenericDSpaceObjectConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.model.DSpaceObjectRest; import org.dspace.app.rest.model.DSpaceObjectRest;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.identifier.IdentifierNotFoundException; import org.dspace.identifier.IdentifierNotFoundException;
@@ -53,7 +53,10 @@ public class IdentifierRestController implements InitializingBean {
Logger.getLogger(IdentifierRestController.class); Logger.getLogger(IdentifierRestController.class);
@Autowired @Autowired
private GenericDSpaceObjectConverter converter; private ConverterService converter;
@Autowired
private Utils utils;
@Autowired @Autowired
private DiscoverableEndpointsService discoverableEndpointsService; private DiscoverableEndpointsService discoverableEndpointsService;
@@ -84,7 +87,7 @@ public class IdentifierRestController implements InitializingBean {
try { try {
dso = identifierService.resolve(context, id); dso = identifierService.resolve(context, id);
if (dso != null) { if (dso != null) {
DSpaceObjectRest dsor = converter.convert(dso); DSpaceObjectRest dsor = converter.toRest(dso, utils.obtainProjection());
URI link = linkTo(dsor.getController(), dsor.getCategory(), URI link = linkTo(dsor.getController(), dsor.getCategory(),
English.plural(dsor.getType())) English.plural(dsor.getType()))
.slash(dsor.getId()).toUri(); .slash(dsor.getId()).toUri();

View File

@@ -0,0 +1,114 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.hateoas.BundleResource;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.repository.ItemRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* Controller to add bundles to a certain item, indicated by a uuid in the request
* Usage: POST /api/core/items/<:uuid>/bundles (with name and metadata of bundle in request json)
* Example:
* <pre>
* {@code
* curl -X POST https://<dspace.server.url>/api/core/items/1911e8a4-6939-490c-b58b-a5d70f8d91fb/bundles
* -H 'Authorization: Bearer eyJhbGciOiJI...'
* -H 'Content-Type: application/json
* -d {
* "name": "ORIGINAL",
* "metadata": {...}
* }
* }
* </pre>
*/
@RestController
@RequestMapping("/api/" + ItemRest.CATEGORY + "/" + ItemRest.PLURAL_NAME + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID
+ "/" + BundleRest.PLURAL_NAME)
public class ItemAddBundleController {
@Autowired
ConverterService converter;
@Autowired
ItemService itemService;
@Autowired
ItemRestRepository itemRestRepository;
@Autowired
MetadataConverter metadataConverter;
@Autowired
Utils utils;
/**
* Method to add a Bundle to an Item with the given UUID in the URL. This will create a Bundle with the
* name provided in the request and attach this to the Item that matches the UUID in the URL.
*
* @return The created BundleResource
*/
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'ADD')")
public ResponseEntity<ResourceSupport> addBundleToItem(@PathVariable UUID uuid,
HttpServletRequest request,
HttpServletResponse response)
throws SQLException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
Item item = itemService.find(context, uuid);
if (item == null) {
throw new ResourceNotFoundException("Could not find item with id " + uuid);
}
BundleRest bundleRest;
try {
bundleRest = new ObjectMapper().readValue(request.getInputStream(), BundleRest.class);
} catch (IOException excIO) {
throw new UnprocessableEntityException("Could not parse request body");
}
Bundle bundle = itemRestRepository.addBundleToItem(context, item, bundleRest);
BundleResource bundleResource = converter.toResource(converter.toRest(bundle, Projection.DEFAULT));
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, bundleResource);
}
}

View File

@@ -7,6 +7,7 @@
*/ */
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import static org.dspace.core.Constants.COLLECTION; import static org.dspace.core.Constants.COLLECTION;
import java.io.IOException; import java.io.IOException;
@@ -16,10 +17,11 @@ import java.util.UUID;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.CollectionConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.DSpaceBadRequestException; import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.CollectionRest; import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
@@ -41,13 +43,11 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
/** /**
* This controller will handle all the incoming calls on the api/code/items/{itemUuid}/owningCollection endpoint * This controller will handle all the incoming calls on the api/code/items/{uuid}/owningCollection endpoint
* where the itemUuid corresponds to the item of which you want to edit the owning collection. * where the uuid corresponds to the item of which you want to edit the owning collection.
*/ */
@RestController @RestController
@RequestMapping("/api/core/items/" + @RequestMapping("/api/core/items" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/owningCollection")
"{itemUuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12" +
"}}/owningCollection")
public class ItemOwningCollectionUpdateRestController { public class ItemOwningCollectionUpdateRestController {
@Autowired @Autowired
@@ -60,7 +60,7 @@ public class ItemOwningCollectionUpdateRestController {
AuthorizeService authorizeService; AuthorizeService authorizeService;
@Autowired @Autowired
CollectionConverter converter; ConverterService converter;
@Autowired @Autowired
Utils utils; Utils utils;
@@ -69,7 +69,7 @@ public class ItemOwningCollectionUpdateRestController {
* This method will update the owning collection of the item that correspond to the provided item uuid, effectively * This method will update the owning collection of the item that correspond to the provided item uuid, effectively
* moving the item to the new collection. * moving the item to the new collection.
* *
* @param itemUuid The UUID of the item that will be moved * @param uuid The UUID of the item that will be moved
* @param response The response object * @param response The response object
* @param request The request object * @param request The request object
* @return The wrapped resource containing the new owning collection or null when the item was not moved * @return The wrapped resource containing the new owning collection or null when the item was not moved
@@ -78,9 +78,9 @@ public class ItemOwningCollectionUpdateRestController {
* @throws AuthorizeException If the user is not authorized to perform the move action * @throws AuthorizeException If the user is not authorized to perform the move action
*/ */
@RequestMapping(method = RequestMethod.PUT, consumes = {"text/uri-list"}) @RequestMapping(method = RequestMethod.PUT, consumes = {"text/uri-list"})
@PreAuthorize("hasPermission(#itemUuid, 'ITEM','WRITE')") @PreAuthorize("hasPermission(#uuid, 'ITEM','WRITE')")
@PostAuthorize("returnObject != null") @PostAuthorize("returnObject != null")
public CollectionRest move(@PathVariable UUID itemUuid, HttpServletResponse response, public CollectionRest move(@PathVariable UUID uuid, HttpServletResponse response,
HttpServletRequest request) HttpServletRequest request)
throws SQLException, IOException, AuthorizeException { throws SQLException, IOException, AuthorizeException {
Context context = ContextUtil.obtainContext(request); Context context = ContextUtil.obtainContext(request);
@@ -92,12 +92,12 @@ public class ItemOwningCollectionUpdateRestController {
"or the data cannot be resolved to a collection."); "or the data cannot be resolved to a collection.");
} }
Collection targetCollection = performItemMove(context, itemUuid, (Collection) dsoList.get(0)); Collection targetCollection = performItemMove(context, uuid, (Collection) dsoList.get(0));
if (targetCollection == null) { if (targetCollection == null) {
return null; return null;
} }
return converter.fromModel(targetCollection); return converter.toRest(targetCollection, Projection.DEFAULT);
} }

View File

@@ -1,163 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.BitstreamConverter;
import org.dspace.app.rest.converter.MetadataConverter;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.hateoas.BitstreamResource;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.Item;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/api/core/items/{uuid}")
public class ItemUploadController {
private static final Logger log = LogManager.getLogger();
@Autowired
protected Utils utils;
@Autowired
private ItemService itemService;
@Autowired
private BitstreamService bitstreamService;
@Autowired
private BitstreamConverter bitstreamConverter;
@Autowired
private MetadataConverter metadataConverter;
@Autowired
private BitstreamFormatService bitstreamFormatService;
/**
* Method to upload a Bitstream to an Item with the given UUID in the URL. This will create a Bitstream with the
* file provided in the request and attach this to the Item that matches the UUID in the URL.
* This will only work for uploading one file, any extra files will silently be ignored
* @return The created BitstreamResource
*/
@RequestMapping(method = RequestMethod.POST, value = "/bitstreams", headers = "content-type=multipart/form-data")
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'WRITE') && hasPermission(#uuid, 'ITEM', 'ADD')")
public BitstreamResource uploadBitstream(HttpServletRequest request, @PathVariable UUID uuid,
@RequestParam("file") MultipartFile uploadfile,
@RequestParam(value = "properties", required = false) String properties) {
Context context = ContextUtil.obtainContext(request);
Item item = null;
Bitstream bitstream = null;
try {
item = itemService.find(context, uuid);
} catch (SQLException e) {
log.error("Something went wrong trying to find the Item with uuid: " + uuid, e);
}
if (item == null) {
throw new ResourceNotFoundException("The given uuid did not resolve to an Item on the server: " + uuid);
}
InputStream fileInputStream = null;
try {
fileInputStream = uploadfile.getInputStream();
} catch (IOException e) {
log.error("Something went wrong when trying to read the inputstream from the given file in the request",
e);
throw new UnprocessableEntityException("The InputStream from the file couldn't be read", e);
}
try {
bitstream = processBitstreamCreation(context, item, fileInputStream, properties,
uploadfile.getOriginalFilename());
itemService.update(context, item);
context.commit();
} catch (AuthorizeException | IOException | SQLException e) {
String message = "Something went wrong with trying to create the single bitstream for file with filename: "
+ uploadfile.getOriginalFilename()
+ " for item with uuid: " + uuid + " and possible properties: " + properties;
log.error(message, e);
throw new RuntimeException(message, e);
}
return new BitstreamResource(bitstreamConverter.fromModel(bitstream), utils);
}
/**
* Creates the bitstream based on the given parameters
* @param context The context
* @param item The item where the bitstream should be store
* @param fileInputStream The input stream used to create the bitstream
* @param properties The properties to be assigned to the bitstream
* @param originalFilename The filename as it was uploaded
* @return The bitstream which has been created
*/
private Bitstream processBitstreamCreation(Context context, Item item, InputStream fileInputStream,
String properties, String originalFilename)
throws AuthorizeException, IOException, SQLException {
Bitstream bitstream = null;
if (StringUtils.isNotBlank(properties)) {
ObjectMapper mapper = new ObjectMapper();
BitstreamRest bitstreamRest = null;
try {
bitstreamRest = mapper.readValue(properties, BitstreamRest.class);
} catch (Exception e) {
throw new UnprocessableEntityException("The properties parameter was incorrect: " + properties);
}
String bundleName = bitstreamRest.getBundleName();
if (StringUtils.isBlank(bundleName)) {
throw new UnprocessableEntityException("Properties without a bundleName is not allowed");
}
bitstream = itemService.createSingleBitstream(context, fileInputStream, item, bundleName);
if (bitstreamRest.getMetadata() != null) {
metadataConverter.setMetadata(context, bitstream, bitstreamRest.getMetadata());
}
String name = bitstreamRest.getName();
if (StringUtils.isNotBlank(name)) {
bitstream.setName(context, name);
} else {
bitstream.setName(context, originalFilename);
}
} else {
bitstream = itemService.createSingleBitstream(context, fileInputStream, item);
bitstream.setName(context, originalFilename);
}
BitstreamFormat bitstreamFormat = bitstreamFormatService.guessFormat(context, bitstream);
bitstreamService.setFormat(context, bitstream, bitstreamFormat);
bitstreamService.update(context, bitstream);
return bitstream;
}
}

View File

@@ -0,0 +1,174 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.io.IOException;
import java.sql.SQLException;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.databind.JsonNode;
import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.hateoas.ItemResource;
import org.dspace.app.rest.repository.ItemRestRepository;
import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* This RestController takes care of the modification and retrieval of Collection's Item templates
* Contrary to CollectionItemtemplateController, this class will receive the UUID of an Item template
*/
@RestController
@RequestMapping("/api/core/itemtemplates" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
public class ItemtemplateRestController {
@Autowired
private Utils utils;
@Autowired
private ItemService itemService;
@Autowired
private ItemRestRepository itemRestRepository;
/**
* This method gets a template Item based on its uuid
*
* Example:
* <pre>
* {@code
* curl http://<dspace.server.url>/api/core/itemtemplates/cb760455-837a-4159-bd12-dcdfafcadc78
* -XGET \
* -H 'Authorization: Bearer eyJhbGciOiJI...'
* }
* </pre>
* @param request
* @param uuid A UUID of a template item
* @return The template item corresponding to the UUID above
*/
@PreAuthorize("hasPermission(#uuid, 'COLLECTION', 'READ')")
@RequestMapping(method = RequestMethod.GET)
public ItemResource getTemplateItem(HttpServletRequest request, @PathVariable UUID uuid) {
Context context = ContextUtil.obtainContext(request);
ItemRest templateItem = itemRestRepository.findOne(context, uuid);
if (templateItem == null) {
throw new ResourceNotFoundException("Item with id: " + uuid + " not found");
}
if (templateItem.getTemplateItemOf() == null) {
throw new ResourceNotFoundException("The item with id " + uuid + " is not a template item");
}
return new ItemResource(templateItem, utils);
}
/**
* This method modifies installed template items
*
* Example:
* <pre>
* {@code
* curl http://<dspace.server.url>/api/core/itemtemplates/cb760455-837a-4159-bd12-dcdfafcadc78
* -XPATCH -H 'Content-Type: Content-Type:application/json' \
* -H 'Authorization: Bearer eyJhbGciOiJI...' \
* --data '[
* {
* "op": "add",
* "path": "/metadata/dc.description",
* "value": [ { "value": "Some other first description" } ]
* }
* ]'
* }
* </pre>
* @param request
* @param uuid The UUID of the template item to be modified
* @param jsonNode The data as shown above
* @return The modified item
* @throws SQLException
* @throws AuthorizeException
*/
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'WRITE')")
@RequestMapping(method = RequestMethod.PATCH)
public ResponseEntity<ResourceSupport> replaceTemplateItem(HttpServletRequest request, @PathVariable UUID uuid,
@RequestBody(required = true) JsonNode jsonNode)
throws SQLException, AuthorizeException {
Context context = ContextUtil.obtainContext(request);
Item item = getTemplateItem(context, uuid);
ItemRest templateItem = itemRestRepository.patchTemplateItem(item, jsonNode);
context.commit();
return ControllerUtils.toResponseEntity(HttpStatus.OK, null,
new ItemResource(templateItem, utils));
}
/**
* This method deletes a template item from a collection.
*
* Example:
* <pre>
* {@code
* curl http://<dspace.server.url>/api/core/itemtemplates/cb760455-837a-4159-bd12-dcdfafcadc78
* -XDELETE \
* -H 'Authorization: Bearer eyJhbGciOiJI...'
* }
* </pre>
* @param request
* @param uuid
* @return Status code 204 is returned if the deletion was successful
* @throws SQLException
* @throws AuthorizeException
* @throws IOException
*/
@PreAuthorize("hasPermission(#uuid, 'ITEM', 'DELETE')")
@RequestMapping(method = RequestMethod.DELETE)
public ResponseEntity<ResourceSupport> deleteTemplateItem(HttpServletRequest request, @PathVariable UUID uuid)
throws SQLException, AuthorizeException, IOException {
Context context = ContextUtil.obtainContext(request);
Item item = getTemplateItem(context, uuid);
itemRestRepository.removeTemplateItem(context, item);
context.commit();
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
}
private Item getTemplateItem(Context context, UUID uuid) throws SQLException {
Item item = itemService.find(context, uuid);
if (item == null) {
throw new ResourceNotFoundException(
"The given uuid did not resolve to an item on the server: " + uuid);
}
if (item.getTemplateItemOf() == null) {
throw new UnprocessableEntityException("The item with id " + uuid + " is not a template item");
}
return item;
}
}

View File

@@ -7,6 +7,7 @@
*/ */
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import static org.dspace.core.Constants.COLLECTION; import static org.dspace.core.Constants.COLLECTION;
import java.io.IOException; import java.io.IOException;
@@ -18,7 +19,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.rest.converter.CollectionConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.MethodNotAllowedException; import org.dspace.app.rest.exception.MethodNotAllowedException;
import org.dspace.app.rest.exception.UnprocessableEntityException; import org.dspace.app.rest.exception.UnprocessableEntityException;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
@@ -46,9 +47,7 @@ import org.springframework.web.bind.annotation.RestController;
* This class will typically receive a UUID that resolves to an Item and it'll perform logic on its collections * This class will typically receive a UUID that resolves to an Item and it'll perform logic on its collections
*/ */
@RestController @RestController
@RequestMapping("/api/core/items/" + @RequestMapping("/api/core/items" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/mappedCollections")
"{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}" +
"/mappedCollections")
public class MappedCollectionRestController { public class MappedCollectionRestController {
private static final Logger log = Logger.getLogger(MappedCollectionRestController.class); private static final Logger log = Logger.getLogger(MappedCollectionRestController.class);
@@ -57,7 +56,7 @@ public class MappedCollectionRestController {
private ItemService itemService; private ItemService itemService;
@Autowired @Autowired
private CollectionConverter collectionConverter; private ConverterService converter;
@Autowired @Autowired
private CollectionService collectionService; private CollectionService collectionService;
@@ -100,18 +99,16 @@ public class MappedCollectionRestController {
List<CollectionRest> mappingCollectionRest = new LinkedList<>(); List<CollectionRest> mappingCollectionRest = new LinkedList<>();
for (Collection collection : collections) { for (Collection collection : collections) {
if (collection.getID() != owningCollectionUuid) { if (collection.getID() != owningCollectionUuid) {
mappingCollectionRest.add(collectionConverter.fromModel(collection)); mappingCollectionRest.add(converter.toRest(collection, utils.obtainProjection()));
} }
} }
MappedCollectionRestWrapper mappingCollectionRestWrapper = new MappedCollectionRestWrapper(); MappedCollectionRestWrapper mappingCollectionRestWrapper = new MappedCollectionRestWrapper();
mappingCollectionRestWrapper.setProjection(utils.obtainProjection());
mappingCollectionRestWrapper.setMappedCollectionRestList(mappingCollectionRest); mappingCollectionRestWrapper.setMappedCollectionRestList(mappingCollectionRest);
mappingCollectionRestWrapper.setItem(item); mappingCollectionRestWrapper.setItem(item);
MappedCollectionResourceWrapper mappingCollectionResourceWrapper = new MappedCollectionResourceWrapper( MappedCollectionResourceWrapper mappingCollectionResourceWrapper =
mappingCollectionRestWrapper, utils, pageable); converter.toResource(mappingCollectionRestWrapper);
halLinkService.addLinks(mappingCollectionResourceWrapper);
return mappingCollectionResourceWrapper; return mappingCollectionResourceWrapper;

View File

@@ -7,6 +7,8 @@
*/ */
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -15,7 +17,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.rest.converter.ItemConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.ItemRest; import org.dspace.app.rest.model.ItemRest;
import org.dspace.app.rest.model.MappedItemRestWrapper; import org.dspace.app.rest.model.MappedItemRestWrapper;
@@ -40,8 +42,7 @@ import org.springframework.web.bind.annotation.RestController;
* have the given collection as their owning collection * have the given collection as their owning collection
*/ */
@RestController @RestController
@RequestMapping("/api/core/collections/" + @RequestMapping("/api/core/collections" + REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/mappedItems")
"{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}/mappedItems")
public class MappedItemRestController { public class MappedItemRestController {
private static final Logger log = Logger.getLogger(MappedItemRestController.class); private static final Logger log = Logger.getLogger(MappedItemRestController.class);
@@ -53,7 +54,7 @@ public class MappedItemRestController {
private ItemService itemService; private ItemService itemService;
@Autowired @Autowired
private ItemConverter itemConverter; private ConverterService converter;
@Autowired @Autowired
Utils utils; Utils utils;
@@ -95,11 +96,12 @@ public class MappedItemRestController {
while (itemIterator.hasNext()) { while (itemIterator.hasNext()) {
Item item = itemIterator.next(); Item item = itemIterator.next();
if (item.getOwningCollection().getID() != uuid) { if (item.getOwningCollection().getID() != uuid) {
mappedItemRestList.add(itemConverter.fromModel(item)); mappedItemRestList.add(converter.toRest(item, utils.obtainProjection()));
} }
} }
MappedItemRestWrapper mappedItemRestWrapper = new MappedItemRestWrapper(); MappedItemRestWrapper mappedItemRestWrapper = new MappedItemRestWrapper();
mappedItemRestWrapper.setProjection(utils.obtainProjection());
mappedItemRestWrapper.setMappedItemRestList(mappedItemRestList); mappedItemRestWrapper.setMappedItemRestList(mappedItemRestList);
mappedItemRestWrapper.setCollectionUuid(uuid); mappedItemRestWrapper.setCollectionUuid(uuid);
MappedItemResourceWrapper mappedItemResourceWrapper = MappedItemResourceWrapper mappedItemResourceWrapper =

View File

@@ -7,6 +7,8 @@
*/ */
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT;
import java.sql.SQLException; import java.sql.SQLException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@@ -29,11 +31,6 @@ import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/api/core/relationships") @RequestMapping("/api/core/relationships")
public class RelationshipRestController { public class RelationshipRestController {
/**
* Regular expression in the request mapping to accept number as identifier
*/
private static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT = "/{id:\\d+}";
@Autowired @Autowired
private RelationshipRestRepository relationshipRestRepository; private RelationshipRestRepository relationshipRestRepository;

View File

@@ -13,11 +13,12 @@ import java.util.List;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.dspace.app.rest.converter.RelationshipTypeConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.RelationshipTypeRest; import org.dspace.app.rest.model.RelationshipTypeRest;
import org.dspace.app.rest.model.RelationshipTypeRestWrapper; import org.dspace.app.rest.model.RelationshipTypeRestWrapper;
import org.dspace.app.rest.model.hateoas.RelationshipTypeResourceWrapper; import org.dspace.app.rest.model.hateoas.RelationshipTypeResourceWrapper;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils; import org.dspace.app.rest.utils.Utils;
import org.dspace.content.EntityType; import org.dspace.content.EntityType;
@@ -48,7 +49,7 @@ public class RelationshipTypeRestController {
private EntityTypeService entityTypeService; private EntityTypeService entityTypeService;
@Autowired @Autowired
private RelationshipTypeConverter relationshipTypeConverter; private ConverterService converter;
@Autowired @Autowired
private Utils utils; private Utils utils;
@@ -67,7 +68,8 @@ public class RelationshipTypeRestController {
* @throws SQLException If something goes wrong * @throws SQLException If something goes wrong
*/ */
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public RelationshipTypeResourceWrapper retrieve(@PathVariable Integer id, HttpServletResponse response, public RelationshipTypeResourceWrapper retrieve(@PathVariable Integer id,
HttpServletResponse response,
HttpServletRequest request) throws SQLException { HttpServletRequest request) throws SQLException {
Context context = ContextUtil.obtainContext(request); Context context = ContextUtil.obtainContext(request);
EntityType entityType = entityTypeService.find(context, id); EntityType entityType = entityTypeService.find(context, id);
@@ -75,19 +77,19 @@ public class RelationshipTypeRestController {
List<RelationshipTypeRest> relationshipTypeRests = new LinkedList<>(); List<RelationshipTypeRest> relationshipTypeRests = new LinkedList<>();
Projection projection = utils.obtainProjection();
for (RelationshipType relationshipType : list) { for (RelationshipType relationshipType : list) {
relationshipTypeRests.add(relationshipTypeConverter.fromModel(relationshipType)); relationshipTypeRests.add(converter.toRest(relationshipType, projection));
} }
RelationshipTypeRestWrapper relationshipTypeRestWrapper = new RelationshipTypeRestWrapper(); RelationshipTypeRestWrapper relationshipTypeRestWrapper = new RelationshipTypeRestWrapper();
relationshipTypeRestWrapper.setProjection(projection);
relationshipTypeRestWrapper.setEntityTypeId(id); relationshipTypeRestWrapper.setEntityTypeId(id);
relationshipTypeRestWrapper.setEntityTypeLabel(entityType.getLabel()); relationshipTypeRestWrapper.setEntityTypeLabel(entityType.getLabel());
relationshipTypeRestWrapper.setRelationshipTypeRestList(relationshipTypeRests); relationshipTypeRestWrapper.setRelationshipTypeRestList(relationshipTypeRests);
RelationshipTypeResourceWrapper relationshipTypeResourceWrapper = new RelationshipTypeResourceWrapper( RelationshipTypeResourceWrapper relationshipTypeResourceWrapper =
relationshipTypeRestWrapper, utils); converter.toResource(relationshipTypeRestWrapper);
halLinkService.addLinks(relationshipTypeResourceWrapper);
return relationshipTypeResourceWrapper; return relationshipTypeResourceWrapper;
} }
} }

View File

@@ -7,6 +7,9 @@
*/ */
package org.dspace.app.rest; package org.dspace.app.rest;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG;
import static org.dspace.app.rest.utils.RegexUtils.REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
@@ -19,17 +22,16 @@ import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
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;
import org.atteo.evo.inflector.English; import org.atteo.evo.inflector.English;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.converter.JsonPatchConverter; import org.dspace.app.rest.converter.JsonPatchConverter;
import org.dspace.app.rest.exception.DSpaceBadRequestException; import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.exception.PaginationException; import org.dspace.app.rest.exception.PaginationException;
@@ -64,7 +66,6 @@ import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.data.web.PagedResourcesAssembler;
import org.springframework.hateoas.Link; import org.springframework.hateoas.Link;
import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.PagedResources;
import org.springframework.hateoas.Resource;
import org.springframework.hateoas.ResourceSupport; import org.springframework.hateoas.ResourceSupport;
import org.springframework.hateoas.Resources; import org.springframework.hateoas.Resources;
import org.springframework.hateoas.UriTemplate; import org.springframework.hateoas.UriTemplate;
@@ -95,24 +96,6 @@ import org.springframework.web.multipart.MultipartFile;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public class RestResourceController implements InitializingBean { public class RestResourceController implements InitializingBean {
/**
* Regular expression in the request mapping to accept UUID as identifier
*/
private static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID =
"/{uuid:[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}}";
/**
* Regular expression in the request mapping to accept a string as identifier but not the other kind of
* identifier (digits or uuid)
*/
private static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG = "/{id:^(?!^\\d+$)" +
"(?!^[0-9a-fxA-FX]{8}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{4}-[0-9a-fxA-FX]{12}$)[\\w+\\-]+$+}";
/**
* Regular expression in the request mapping to accept number as identifier
*/
private static final String REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT = "/{id:\\d+}";
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RestResourceController.class); private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RestResourceController.class);
@Autowired @Autowired
@@ -130,6 +113,9 @@ public class RestResourceController implements InitializingBean {
@Autowired @Autowired
HalLinkService linkService; HalLinkService linkService;
@Autowired
ConverterService converter;
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
List<Link> links = new ArrayList<Link>(); List<Link> links = new ArrayList<Link>();
@@ -152,22 +138,20 @@ public class RestResourceController implements InitializingBean {
* *
* Note that the regular expression in the request mapping accept a number as identifier; * Note that the regular expression in the request mapping accept a number as identifier;
* *
* Please see {@link RestResourceController#findOne(String, String, String, String)} for findOne with string as * Please see {@link RestResourceController#findOne(String, String, String)} for findOne with string as
* identifier * identifier
* and see {@link RestResourceController#findOne(String, String, UUID, String)} for uuid as identifier * and see {@link RestResourceController#findOne(String, String, UUID)} for uuid as identifier
* *
* @param apiCategory * @param apiCategory
* @param model * @param model
* @param id * @param id
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT) @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model, public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
@PathVariable Integer id, @PathVariable Integer id) {
@RequestParam(required = false) String projection) { return findOneInternal(apiCategory, model, id);
return findOneInternal(apiCategory, model, id, projection);
} }
/** /**
@@ -186,22 +170,20 @@ public class RestResourceController implements InitializingBean {
* </pre> * </pre>
* *
* *
* Please see {@link RestResourceController#findOne(String, String, Integer, String)} for findOne with number as * Please see {@link RestResourceController#findOne(String, String, Integer)} for findOne with number as
* identifier * identifier
* and see {@link RestResourceController#findOne(String, String, UUID, String)} for uuid as identifier * and see {@link RestResourceController#findOne(String, String, UUID)} for uuid as identifier
* *
* @param apiCategory * @param apiCategory
* @param model * @param model
* @param id * @param id
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG) @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model, public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
@PathVariable String id, @PathVariable String id) {
@RequestParam(required = false) String projection) { return findOneInternal(apiCategory, model, id);
return findOneInternal(apiCategory, model, id, projection);
} }
/** /**
@@ -209,22 +191,20 @@ public class RestResourceController implements InitializingBean {
* *
* Note that the regular expression in the request mapping accept a UUID as identifier; * Note that the regular expression in the request mapping accept a UUID as identifier;
* *
* Please see {@link RestResourceController#findOne(String, String, Integer, String)} for findOne with number as * Please see {@link RestResourceController#findOne(String, String, Integer)} for findOne with number as
* identifier * identifier
* and see {@link RestResourceController#findOne(String, String, String, String)} for string as identifier * and see {@link RestResourceController#findOne(String, String, String)} for string as identifier
* *
* @param apiCategory * @param apiCategory
* @param model * @param model
* @param uuid * @param uuid
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID) @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID)
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model, public DSpaceResource<RestAddressableModel> findOne(@PathVariable String apiCategory, @PathVariable String model,
@PathVariable UUID uuid, @PathVariable UUID uuid) {
@RequestParam(required = false) String projection) { return findOneInternal(apiCategory, model, uuid);
return findOneInternal(apiCategory, model, uuid, projection);
} }
/** /**
@@ -233,13 +213,10 @@ public class RestResourceController implements InitializingBean {
* @param apiCategory * @param apiCategory
* @param model * @param model
* @param id * @param id
* @param projection
* @return * @return
*/ */
private <ID extends Serializable> DSpaceResource<RestAddressableModel> findOneInternal(String apiCategory, private <ID extends Serializable> DSpaceResource<RestAddressableModel> findOneInternal(String apiCategory,
String model, ID id, String model, ID id) {
String projection) {
checkModelPluralForm(apiCategory, model);
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model); DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
RestAddressableModel modelObject = null; RestAddressableModel modelObject = null;
try { try {
@@ -250,9 +227,7 @@ public class RestResourceController implements InitializingBean {
if (modelObject == null) { if (modelObject == null) {
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found");
} }
DSpaceResource result = repository.wrapResource(modelObject); return converter.toResource(modelObject);
linkService.addLinks(result);
return result;
} }
/** /**
@@ -267,7 +242,6 @@ public class RestResourceController implements InitializingBean {
* @param rel * @param rel
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT + "/{rel}") @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT + "/{rel}")
@@ -275,9 +249,8 @@ public class RestResourceController implements InitializingBean {
@PathVariable String apiCategory, @PathVariable String apiCategory,
@PathVariable String model, @PathVariable Integer id, @PathVariable String rel, @PathVariable String model, @PathVariable Integer id, @PathVariable String rel,
Pageable page, Pageable page,
PagedResourcesAssembler assembler, PagedResourcesAssembler assembler) {
@RequestParam(required = false) String projection) { return findRelInternal(request, response, apiCategory, model, id, rel, page, assembler);
return findRelInternal(request, response, apiCategory, model, id, rel, page, assembler, projection);
} }
/** /**
@@ -293,7 +266,6 @@ public class RestResourceController implements InitializingBean {
* @param rel * @param rel
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG + @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG +
@@ -302,9 +274,8 @@ public class RestResourceController implements InitializingBean {
@PathVariable String apiCategory, @PathVariable String apiCategory,
@PathVariable String model, @PathVariable String id, @PathVariable String rel, @PathVariable String model, @PathVariable String id, @PathVariable String rel,
Pageable page, Pageable page,
PagedResourcesAssembler assembler, PagedResourcesAssembler assembler) {
@RequestParam(required = false) String projection) { return findRelInternal(request, response, apiCategory, model, id, rel, page, assembler);
return findRelInternal(request, response, apiCategory, model, id, rel, page, assembler, projection);
} }
/** /**
@@ -319,7 +290,6 @@ public class RestResourceController implements InitializingBean {
* @param rel * @param rel
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/{rel}") @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID + "/{rel}")
@@ -327,9 +297,8 @@ public class RestResourceController implements InitializingBean {
@PathVariable String apiCategory, @PathVariable String apiCategory,
@PathVariable String model, @PathVariable UUID uuid, @PathVariable String rel, @PathVariable String model, @PathVariable UUID uuid, @PathVariable String rel,
Pageable page, Pageable page,
PagedResourcesAssembler assembler, PagedResourcesAssembler assembler) {
@RequestParam(required = false) String projection) { return findRelInternal(request, response, apiCategory, model, uuid, rel, page, assembler);
return findRelInternal(request, response, apiCategory, model, uuid, rel, page, assembler, projection);
} }
/** /**
@@ -362,7 +331,6 @@ public class RestResourceController implements InitializingBean {
* @param relid * @param relid
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG + @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_STRING_VERSION_STRONG +
@@ -371,9 +339,8 @@ public class RestResourceController implements InitializingBean {
@PathVariable String apiCategory, @PathVariable String apiCategory,
@PathVariable String model, @PathVariable String id, @PathVariable String rel, @PathVariable String model, @PathVariable String id, @PathVariable String rel,
@PathVariable String relid, @PathVariable String relid,
Pageable page, PagedResourcesAssembler assembler, Pageable page, PagedResourcesAssembler assembler) throws Throwable {
@RequestParam(required = false) String projection) throws Throwable { return findRelEntryInternal(request, response, apiCategory, model, id, rel, relid, page, assembler);
return findRelEntryInternal(request, response, apiCategory, model, id, rel, relid, page, assembler, projection);
} }
@@ -458,8 +425,7 @@ public class RestResourceController implements InitializingBean {
if (modelObject == null) { if (modelObject == null) {
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED); return ControllerUtils.toEmptyResponse(HttpStatus.CREATED);
} }
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
//TODO manage HTTPHeader //TODO manage HTTPHeader
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} }
@@ -491,8 +457,7 @@ public class RestResourceController implements InitializingBean {
if (modelObject == null) { if (modelObject == null) {
return ControllerUtils.toEmptyResponse(HttpStatus.CREATED); return ControllerUtils.toEmptyResponse(HttpStatus.CREATED);
} }
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
//TODO manage HTTPHeader //TODO manage HTTPHeader
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} }
@@ -530,8 +495,7 @@ public class RestResourceController implements InitializingBean {
} }
if (modelObject != null) { if (modelObject != null) {
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} else { } else {
return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT); return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
@@ -622,8 +586,7 @@ public class RestResourceController implements InitializingBean {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR); return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR);
} }
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} }
@@ -660,8 +623,7 @@ public class RestResourceController implements InitializingBean {
List<DSpaceResource> resources = new ArrayList<>(); List<DSpaceResource> resources = new ArrayList<>();
for (T modelObject : content) { for (T modelObject : content) {
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
resources.add(result); resources.add(result);
} }
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, Resources.wrap(resources)); return ControllerUtils.toResponseEntity(HttpStatus.OK, null, Resources.wrap(resources));
@@ -740,8 +702,7 @@ public class RestResourceController implements InitializingBean {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
throw e; throw e;
} }
DSpaceResource result = repository.wrapResource(modelObject); DSpaceResource result = converter.toResource(modelObject);
linkService.addLinks(result);
//TODO manage HTTPHeader //TODO manage HTTPHeader
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, result); return ControllerUtils.toResponseEntity(HttpStatus.OK, null, result);
@@ -758,7 +719,6 @@ public class RestResourceController implements InitializingBean {
* @param relid * @param relid
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
private <ID extends Serializable> ResourceSupport findRelEntryInternal(HttpServletRequest request, private <ID extends Serializable> ResourceSupport findRelEntryInternal(HttpServletRequest request,
@@ -766,26 +726,24 @@ public class RestResourceController implements InitializingBean {
String apiCategory, String model, String apiCategory, String model,
String id, String rel, String relid, String id, String rel, String relid,
Pageable page, Pageable page,
PagedResourcesAssembler assembler, PagedResourcesAssembler assembler)
String projection) throws Throwable { throws Throwable {
checkModelPluralForm(apiCategory, model); checkModelPluralForm(apiCategory, model);
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model); DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
Class<RestAddressableModel> domainClass = repository.getDomainClass(); Class<RestAddressableModel> domainClass = repository.getDomainClass();
LinkRest linkRest = utils.getLinkRest(rel, domainClass); LinkRest linkRest = utils.getClassLevelLinkRest(rel, domainClass);
if (linkRest != null) { if (linkRest != null) {
LinkRestRepository linkRepository = utils.getLinkResourceRepository(apiCategory, model, linkRest.name()); LinkRestRepository linkRepository = utils.getLinkResourceRepository(apiCategory, model, linkRest.name());
Method linkMethod = repositoryUtils.getLinkMethod("getResource", linkRepository); Method linkMethod = utils.requireMethod(linkRepository.getClass(), "getResource");
try { try {
Object object = linkMethod.invoke(linkRepository, request, id, relid, page, projection); Object object = linkMethod.invoke(linkRepository, request, id, relid, page, utils.obtainProjection());
Link link = linkTo(this.getClass(), apiCategory, model).slash(id).slash(rel).slash(relid).withSelfRel(); Link link = linkTo(this.getClass(), apiCategory, model).slash(id).slash(rel).slash(relid).withSelfRel();
List result = new ArrayList(); List result = new ArrayList();
result.add(object); result.add(object);
PageImpl<RestAddressableModel> pageResult = new PageImpl(result, page, 1); PageImpl<RestAddressableModel> pageResult = new PageImpl(result, page, 1);
Page<HALResource> halResources = pageResult.map(linkRepository::wrapResource); Page<HALResource> halResources = pageResult.map(restObject -> converter.toResource(restObject));
halResources.forEach(linkService::addLinks);
return assembler.toResource(halResources, link); return assembler.toResource(halResources, link);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
// This catch has been made to resolve the issue that caused AuthorizeDenied exceptions for the methods // This catch has been made to resolve the issue that caused AuthorizeDenied exceptions for the methods
@@ -812,37 +770,29 @@ public class RestResourceController implements InitializingBean {
* @param apiCategory * @param apiCategory
* @param model * @param model
* @param uuid * @param uuid
* @param rel
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
private <ID extends Serializable> ResourceSupport findRelInternal(HttpServletRequest request, private <ID extends Serializable> ResourceSupport findRelInternal(HttpServletRequest request,
HttpServletResponse response, String apiCategory, HttpServletResponse response, String apiCategory,
String model, ID uuid, String subpath, String model, ID uuid, String subpath,
Pageable page, PagedResourcesAssembler assembler, Pageable page,
String projection) { PagedResourcesAssembler assembler) {
checkModelPluralForm(apiCategory, model); checkModelPluralForm(apiCategory, model);
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model); DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
Class<RestAddressableModel> domainClass = repository.getDomainClass(); Class<RestAddressableModel> domainClass = repository.getDomainClass();
LinkRest linkRest = utils.getLinkRest(subpath, domainClass); LinkRest linkRest = utils.getClassLevelLinkRest(subpath, domainClass);
PagedResources<? extends HALResource> result; PagedResources<? extends HALResource> result;
if (linkRest != null) { if (linkRest != null) {
LinkRestRepository linkRepository = utils.getLinkResourceRepository(apiCategory, model, linkRest.name()); LinkRestRepository linkRepository = utils.getLinkResourceRepository(apiCategory, model, linkRest.name());
Method linkMethod = repositoryUtils.getLinkMethod(linkRest.method(), linkRepository); Method linkMethod = utils.requireMethod(linkRepository.getClass(), linkRest.method());
if (linkMethod == null) {
// TODO custom exception
throw new RuntimeException(
"Method for relation " + subpath + " not found: " + linkRest.name() + ":" + linkRest.method());
} else {
try { try {
if (Page.class.isAssignableFrom(linkMethod.getReturnType())) { if (Page.class.isAssignableFrom(linkMethod.getReturnType())) {
Page<? extends RestModel> pageResult = (Page<? extends RestAddressableModel>) linkMethod Page<? extends RestModel> pageResult = (Page<? extends RestAddressableModel>) linkMethod
.invoke(linkRepository, request, uuid, page, projection); .invoke(linkRepository, request, uuid, page, utils.obtainProjection(true));
Link link = null; Link link = null;
String querystring = request.getQueryString(); String querystring = request.getQueryString();
@@ -853,16 +803,14 @@ public class RestResourceController implements InitializingBean {
link = linkTo(this.getClass(), apiCategory, model).slash(uuid).slash(subpath).withSelfRel(); link = linkTo(this.getClass(), apiCategory, model).slash(uuid).slash(subpath).withSelfRel();
} }
Page<HALResource> halResources = pageResult.map(linkRepository::wrapResource); Page<HALResource> halResources = pageResult.map(object -> converter.toResource(object));
halResources.forEach(linkService::addLinks);
return assembler.toResource(halResources, link); return assembler.toResource(halResources, link);
} else { } else {
RestModel object = (RestModel) linkMethod.invoke(linkRepository, request, uuid, page, RestModel object = (RestModel) linkMethod.invoke(linkRepository, request, uuid, page,
projection); utils.obtainProjection());
Link link = linkTo(this.getClass(), apiCategory, model).slash(uuid).slash(subpath) Link link = linkTo(this.getClass(), apiCategory, model).slash(uuid).slash(subpath)
.withSelfRel(); .withSelfRel();
HALResource tmpresult = linkRepository.wrapResource(object); HALResource tmpresult = converter.toResource(object);
tmpresult.add(link); tmpresult.add(link);
return tmpresult; return tmpresult;
} }
@@ -870,15 +818,13 @@ public class RestResourceController implements InitializingBean {
throw new RuntimeException(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e);
} }
} }
}
RestAddressableModel modelObject = repository.findOne(uuid); RestAddressableModel modelObject = repository.findOne(uuid);
if (modelObject == null) { if (modelObject == null) {
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found"); throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
} }
DSpaceResource resource = repository.wrapResource(modelObject, subpath); DSpaceResource resource = converter.toResource(modelObject);
linkService.addLinks(resource);
String rel = null; String rel = null;
@@ -919,16 +865,7 @@ public class RestResourceController implements InitializingBean {
.getResourceRepository(fullList.get(0).getCategory(), fullList.get(0).getType()); .getResourceRepository(fullList.get(0).getCategory(), fullList.get(0).getType());
PageImpl<RestAddressableModel> pageResult = new PageImpl(fullList.subList(start, end), page, PageImpl<RestAddressableModel> pageResult = new PageImpl(fullList.subList(start, end), page,
fullList.size()); fullList.size());
result = assembler.toResource(pageResult.map(resourceRepository::wrapResource)); return assembler.toResource(pageResult.map(converter::toResource));
for (Resource subObj : result) {
if (subObj.getContent() instanceof HALResource) {
linkService.addLinks((HALResource) subObj.getContent());
}
}
return result;
} else { } else {
if (resource.getEmbeddedResources().get(rel) == null) { if (resource.getEmbeddedResources().get(rel) == null) {
response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.setStatus(HttpServletResponse.SC_NO_CONTENT);
@@ -945,7 +882,6 @@ public class RestResourceController implements InitializingBean {
* @param model * @param model
* @param page * @param page
* @param assembler * @param assembler
* @param projection
* @return * @return
*/ */
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
@@ -954,18 +890,15 @@ public class RestResourceController implements InitializingBean {
@PathVariable String model, @PathVariable String model,
Pageable page, Pageable page,
PagedResourcesAssembler assembler, PagedResourcesAssembler assembler,
@RequestParam(required = false)
String projection,
HttpServletResponse response) { HttpServletResponse response) {
DSpaceRestRepository<T, ?> repository = utils.getResourceRepository(apiCategory, model); DSpaceRestRepository<T, ?> repository = utils.getResourceRepository(apiCategory, model);
Link link = linkTo(methodOn(this.getClass(), apiCategory, model).findAll(apiCategory, model, Link link = linkTo(methodOn(this.getClass(), apiCategory, model).findAll(apiCategory, model,
page, assembler, projection, response)) page, assembler, response))
.withSelfRel(); .withSelfRel();
Page<DSpaceResource<T>> resources; Page<DSpaceResource<T>> resources;
try { try {
resources = repository.findAll(page).map(repository::wrapResource); resources = repository.findAll(page).map(converter::toResource);
resources.forEach(linkService::addLinks);
} catch (PaginationException pe) { } catch (PaginationException pe) {
resources = new PageImpl<DSpaceResource<T>>(new ArrayList<DSpaceResource<T>>(), page, pe.getTotal()); resources = new PageImpl<DSpaceResource<T>>(new ArrayList<DSpaceResource<T>>(), page, pe.getTotal());
} catch (RepositoryMethodNotImplementedException mne) { } catch (RepositoryMethodNotImplementedException mne) {
@@ -1044,18 +977,15 @@ public class RestResourceController implements InitializingBean {
if (searchResult == null) { if (searchResult == null) {
resources = new PageImpl(new ArrayList(), pageable, 0); resources = new PageImpl(new ArrayList(), pageable, 0);
} else { } else {
resources = ((Page<T>) searchResult).map(repository::wrapResource); resources = ((Page<T>) searchResult).map(converter::toResource);
} }
resources.forEach(linkService::addLinks);
result = assembler.toResource(resources, link); result = assembler.toResource(resources, link);
} else { } else {
if (searchResult == null) { if (searchResult == null) {
response.setStatus(HttpServletResponse.SC_NO_CONTENT); response.setStatus(HttpServletResponse.SC_NO_CONTENT);
return null; return null;
} }
DSpaceResource<T> dsResource = repository.wrapResource((T) searchResult); return converter.toResource((T) searchResult);
linkService.addLinks(dsResource);
result = dsResource;
} }
return result; return result;
} }
@@ -1204,9 +1134,7 @@ public class RestResourceController implements InitializingBean {
if (modelObject == null) { if (modelObject == null) {
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found");
} }
DSpaceResource result = repository.wrapResource(modelObject); return converter.toResource(modelObject);
linkService.addLinks(result);
return result;
} }
/** /**
@@ -1229,9 +1157,6 @@ public class RestResourceController implements InitializingBean {
if (modelObject == null) { if (modelObject == null) {
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found"); throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + id + " not found");
} }
DSpaceResource result = repository.wrapResource(modelObject); return converter.toResource(modelObject);
linkService.addLinks(result);
return result;
} }
} }

View File

@@ -9,8 +9,8 @@ package org.dspace.app.rest;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.RootRest;
import org.dspace.app.rest.model.hateoas.RootResource; import org.dspace.app.rest.model.hateoas.RootResource;
import org.dspace.app.rest.repository.RootRestRepository; import org.dspace.app.rest.repository.RootRestRepository;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -39,13 +39,11 @@ public class RootRestResourceController {
@Autowired @Autowired
RootRestRepository rootRestRepository; RootRestRepository rootRestRepository;
@Autowired
ConverterService converter;
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public RootResource listDefinedEndpoint(HttpServletRequest request) { public RootResource listDefinedEndpoint(HttpServletRequest request) {
return converter.toResource(rootRestRepository.getRoot());
RootRest rootRest = rootRestRepository.getRoot();
RootResource rootResource = new RootResource(rootRest);
halLinkService.addLinks(rootResource);
return rootResource;
} }
} }

View File

@@ -0,0 +1,62 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.rest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.app.rest.repository.ScriptRestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.hateoas.ResourceSupport;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* This controller adds additional subresource methods to allow connecting scripts with processes
*/
@RestController
@RequestMapping("/api/" + ScriptRest.CATEGORY + "/" + ScriptRest.PLURAL_NAME + "/{name}/processes")
public class ScriptProcessesController {
private static final Logger log = LogManager.getLogger();
@Autowired
private ConverterService converter;
@Autowired
private ScriptRestRepository scriptRestRepository;
/**
* This method can be called by sending a POST request to the system/scripts/{name}/processes endpoint
* This will start a process for the script that matches the given name
* @param scriptName The name of the script that we want to start a process for
* @return The ProcessResource object for the created process
* @throws Exception If something goes wrong
*/
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasAuthority('ADMIN')")
public ResponseEntity<ResourceSupport> startProcess(@PathVariable(name = "name") String scriptName)
throws Exception {
if (log.isTraceEnabled()) {
log.trace("Starting Process for Script with name: " + scriptName);
}
ProcessRest processRest = scriptRestRepository.startProcess(scriptName);
ProcessResource processResource = converter.toResource(processRest);
return ControllerUtils.toResponseEntity(HttpStatus.ACCEPTED, null, processResource);
}
}

View File

@@ -10,6 +10,7 @@ package org.dspace.app.rest;
import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException; import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.link.HalLinkService; import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.RestAddressableModel; import org.dspace.app.rest.model.RestAddressableModel;
@@ -47,6 +48,9 @@ public class StatisticsRestController implements InitializingBean {
@Autowired @Autowired
private HalLinkService halLinkService; private HalLinkService halLinkService;
@Autowired
private ConverterService converter;
@Autowired @Autowired
private StatisticsRestRepository statisticsRestRepository; private StatisticsRestRepository statisticsRestRepository;
@@ -65,12 +69,10 @@ public class StatisticsRestController implements InitializingBean {
@RequestMapping(method = RequestMethod.GET) @RequestMapping(method = RequestMethod.GET)
public StatisticsSupportResource getStatisticsSupport() throws Exception { public StatisticsSupportResource getStatisticsSupport() throws Exception {
StatisticsSupportRest statisticsSupportRest = statisticsRestRepository.getStatisticsSupport(); StatisticsSupportRest statisticsSupportRest = statisticsRestRepository.getStatisticsSupport();
StatisticsSupportResource statisticsSupportResource = new StatisticsSupportResource(statisticsSupportRest); return converter.toResource(statisticsSupportRest);
halLinkService.addLinks(statisticsSupportResource);
return statisticsSupportResource;
} }
@RequestMapping(method = RequestMethod.GET, value = "/viewevents/{uuid}") @RequestMapping(method = RequestMethod.GET, value = "/viewevents/{uuid}")
public PagedResources<ViewEventResource> getViewEvent(@PathVariable(name = "uuid") UUID uuid) throws Exception { public PagedResources<ViewEventResource> getViewEvent(@PathVariable(name = "uuid") UUID uuid) throws Exception {
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
@@ -93,13 +95,13 @@ public class StatisticsRestController implements InitializingBean {
@RequestMapping(method = RequestMethod.POST, value = "/viewevents") @RequestMapping(method = RequestMethod.POST, value = "/viewevents")
public ResponseEntity<ResourceSupport> postViewEvent() throws Exception { public ResponseEntity<ResourceSupport> postViewEvent() throws Exception {
ViewEventResource result = new ViewEventResource(viewEventRestRepository.createViewEvent(), utils); ViewEventResource result = converter.toResource(viewEventRestRepository.createViewEvent());
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} }
@RequestMapping(method = RequestMethod.POST, value = "/searchevents") @RequestMapping(method = RequestMethod.POST, value = "/searchevents")
public ResponseEntity<ResourceSupport> postSearchEvent() throws Exception { public ResponseEntity<ResourceSupport> postSearchEvent() throws Exception {
SearchEventResource result = new SearchEventResource(searchEventRestRepository.createSearchEvent(), utils); SearchEventResource result = converter.toResource(searchEventRestRepository.createSearchEvent());
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
} }

View File

@@ -14,14 +14,14 @@ import java.net.URI;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.rest.converter.GenericDSpaceObjectConverter; import org.dspace.app.rest.converter.ConverterService;
import org.dspace.app.rest.model.DSpaceObjectRest; import org.dspace.app.rest.model.DSpaceObjectRest;
import org.dspace.app.rest.utils.ContextUtil; import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.app.rest.utils.Utils;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.DSpaceObjectService; import org.dspace.content.service.DSpaceObjectService;
@@ -57,6 +57,9 @@ public class UUIDLookupRestController implements InitializingBean {
@Autowired @Autowired
private ContentServiceFactory contentServiceFactory; private ContentServiceFactory contentServiceFactory;
@Autowired
private Utils utils;
private static final Logger log = private static final Logger log =
Logger.getLogger(UUIDLookupRestController.class); Logger.getLogger(UUIDLookupRestController.class);
@@ -64,7 +67,7 @@ public class UUIDLookupRestController implements InitializingBean {
private DiscoverableEndpointsService discoverableEndpointsService; private DiscoverableEndpointsService discoverableEndpointsService;
@Autowired @Autowired
private GenericDSpaceObjectConverter converter; private ConverterService converter;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
@@ -92,7 +95,7 @@ public class UUIDLookupRestController implements InitializingBean {
.getDSpaceObjectServices()) { .getDSpaceObjectServices()) {
DSpaceObject dso = dSpaceObjectService.find(context, uuid); DSpaceObject dso = dSpaceObjectService.find(context, uuid);
if (dso != null) { if (dso != null) {
DSpaceObjectRest dsor = converter.convert(dso); DSpaceObjectRest dsor = converter.toRest(dso, utils.obtainProjection());
URI link = linkTo(dsor.getController(), dsor.getCategory(), dsor.getTypePlural()) URI link = linkTo(dsor.getController(), dsor.getCategory(), dsor.getTypePlural())
.slash(dsor.getId()).toUri(); .slash(dsor.getId()).toUri();
response.setStatus(HttpServletResponse.SC_FOUND); response.setStatus(HttpServletResponse.SC_FOUND);

View File

@@ -17,6 +17,7 @@ import org.dspace.app.rest.model.AInprogressSubmissionRest;
import org.dspace.app.rest.model.ErrorRest; import org.dspace.app.rest.model.ErrorRest;
import org.dspace.app.rest.model.SubmissionDefinitionRest; import org.dspace.app.rest.model.SubmissionDefinitionRest;
import org.dspace.app.rest.model.SubmissionSectionRest; import org.dspace.app.rest.model.SubmissionSectionRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.submit.AbstractRestProcessingStep; import org.dspace.app.rest.submit.AbstractRestProcessingStep;
import org.dspace.app.rest.submit.SubmissionService; import org.dspace.app.rest.submit.SubmissionService;
import org.dspace.app.util.SubmissionConfigReader; import org.dspace.app.util.SubmissionConfigReader;
@@ -47,22 +48,13 @@ public abstract class AInprogressItemConverter<T extends InProgressSubmission<ID
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(AInprogressItemConverter.class); private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(AInprogressItemConverter.class);
@Autowired @Autowired
private EPersonConverter epersonConverter; private ConverterService converter;
@Autowired
private ItemConverter itemConverter;
@Autowired
private CollectionConverter collectionConverter;
protected SubmissionConfigReader submissionConfigReader;
@Autowired
private SubmissionDefinitionConverter submissionDefinitionConverter;
@Autowired @Autowired
private SubmissionSectionConverter submissionSectionConverter; private SubmissionSectionConverter submissionSectionConverter;
protected SubmissionConfigReader submissionConfigReader;
@Autowired @Autowired
SubmissionService submissionService; SubmissionService submissionService;
@@ -70,7 +62,7 @@ public abstract class AInprogressItemConverter<T extends InProgressSubmission<ID
submissionConfigReader = new SubmissionConfigReader(); submissionConfigReader = new SubmissionConfigReader();
} }
protected void fillFromModel(T obj, R witem) { protected void fillFromModel(T obj, R witem, Projection projection) {
Collection collection = obj.getCollection(); Collection collection = obj.getCollection();
Item item = obj.getItem(); Item item = obj.getItem();
EPerson submitter = null; EPerson submitter = null;
@@ -81,17 +73,17 @@ public abstract class AInprogressItemConverter<T extends InProgressSubmission<ID
} }
witem.setId(obj.getID()); witem.setId(obj.getID());
witem.setCollection(collection != null ? collectionConverter.convert(collection) : null); witem.setCollection(collection != null ? converter.toRest(collection, projection) : null);
witem.setItem(itemConverter.convert(item)); witem.setItem(converter.toRest(item, projection));
witem.setSubmitter(epersonConverter.convert(submitter)); witem.setSubmitter(converter.toRest(submitter, projection));
// 1. retrieve the submission definition // 1. retrieve the submission definition
// 2. iterate over the submission section to allow to plugin additional // 2. iterate over the submission section to allow to plugin additional
// info // info
if (collection != null) { if (collection != null) {
SubmissionDefinitionRest def = submissionDefinitionConverter SubmissionDefinitionRest def = converter.toRest(
.convert(submissionConfigReader.getSubmissionConfigByCollection(collection.getHandle())); submissionConfigReader.getSubmissionConfigByCollection(collection.getHandle()), projection);
witem.setSubmissionDefinition(def); witem.setSubmissionDefinition(def);
for (SubmissionSectionRest sections : def.getPanels()) { for (SubmissionSectionRest sections : def.getPanels()) {
SubmissionStepConfig stepConfig = submissionSectionConverter.toModel(sections); SubmissionStepConfig stepConfig = submissionSectionConverter.toModel(sections);

View File

@@ -7,8 +7,8 @@
*/ */
package org.dspace.app.rest.converter; package org.dspace.app.rest.converter;
import org.apache.commons.lang3.NotImplementedException;
import org.dspace.app.rest.model.AuthorityEntryRest; import org.dspace.app.rest.model.AuthorityEntryRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.AuthorityUtils; import org.dspace.app.rest.utils.AuthorityUtils;
import org.dspace.content.authority.Choice; import org.dspace.content.authority.Choice;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
* This is the converter from/to the Choice in the DSpace API data * This is the converter from/to the Choice in the DSpace API data
* model and the REST data model. * model and the REST data model.
* *
* TODO please do not use this convert but use the wrapper {@link AuthorityUtils#convertEntry(Choice, String)}} * TODO please do not use this convert but use the wrapper {@link AuthorityUtils#convertEntry(Choice, String, String)}
* *
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/ */
@@ -25,8 +25,9 @@ import org.springframework.stereotype.Component;
public class AuthorityEntryRestConverter implements DSpaceConverter<Choice, AuthorityEntryRest> { public class AuthorityEntryRestConverter implements DSpaceConverter<Choice, AuthorityEntryRest> {
@Override @Override
public AuthorityEntryRest fromModel(Choice choice) { public AuthorityEntryRest convert(Choice choice, Projection projection) {
AuthorityEntryRest entry = new AuthorityEntryRest(); AuthorityEntryRest entry = new AuthorityEntryRest();
entry.setProjection(projection);
entry.setValue(choice.value); entry.setValue(choice.value);
entry.setDisplay(choice.label); entry.setDisplay(choice.label);
entry.setId(choice.authority); entry.setId(choice.authority);
@@ -35,7 +36,7 @@ public class AuthorityEntryRestConverter implements DSpaceConverter<Choice, Auth
} }
@Override @Override
public Choice toModel(AuthorityEntryRest obj) { public Class<Choice> getModelClass() {
throw new NotImplementedException("Method not implemented"); return Choice.class;
} }
} }

View File

@@ -7,8 +7,8 @@
*/ */
package org.dspace.app.rest.converter; package org.dspace.app.rest.converter;
import org.apache.commons.lang3.NotImplementedException;
import org.dspace.app.rest.model.AuthorityRest; import org.dspace.app.rest.model.AuthorityRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.AuthorityUtils; import org.dspace.app.rest.utils.AuthorityUtils;
import org.dspace.content.authority.ChoiceAuthority; import org.dspace.content.authority.ChoiceAuthority;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -18,7 +18,7 @@ import org.springframework.stereotype.Component;
* model and the REST data model * model and the REST data model
* *
* TODO please do not use this convert but use the wrapper * TODO please do not use this convert but use the wrapper
* {@link AuthorityUtils#convertAuthority(ChoiceAuthority, String)} * {@link AuthorityUtils#convertAuthority(ChoiceAuthority, String, String)}
* *
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/ */
@@ -26,8 +26,9 @@ import org.springframework.stereotype.Component;
public class AuthorityRestConverter implements DSpaceConverter<ChoiceAuthority, AuthorityRest> { public class AuthorityRestConverter implements DSpaceConverter<ChoiceAuthority, AuthorityRest> {
@Override @Override
public AuthorityRest fromModel(ChoiceAuthority step) { public AuthorityRest convert(ChoiceAuthority step, Projection projection) {
AuthorityRest authorityRest = new AuthorityRest(); AuthorityRest authorityRest = new AuthorityRest();
authorityRest.setProjection(projection);
authorityRest.setHierarchical(step.isHierarchical()); authorityRest.setHierarchical(step.isHierarchical());
authorityRest.setScrollable(step.isScrollable()); authorityRest.setScrollable(step.isScrollable());
authorityRest.setIdentifier(step.hasIdentifier()); authorityRest.setIdentifier(step.hasIdentifier());
@@ -35,7 +36,7 @@ public class AuthorityRestConverter implements DSpaceConverter<ChoiceAuthority,
} }
@Override @Override
public ChoiceAuthority toModel(AuthorityRest obj) { public Class<ChoiceAuthority> getModelClass() {
throw new NotImplementedException("Method not implemented"); return ChoiceAuthority.class;
} }
} }

View File

@@ -10,9 +10,9 @@ package org.dspace.app.rest.converter;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.dspace.app.rest.model.BitstreamFormatRest;
import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.CheckSumRest; import org.dspace.app.rest.model.CheckSumRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.Bundle; import org.dspace.content.Bundle;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -25,19 +25,14 @@ import org.springframework.stereotype.Component;
* @author Andrea Bollini (andrea.bollini at 4science.it) * @author Andrea Bollini (andrea.bollini at 4science.it)
*/ */
@Component @Component
public class BitstreamConverter public class BitstreamConverter extends DSpaceObjectConverter<Bitstream, BitstreamRest> {
extends DSpaceObjectConverter<org.dspace.content.Bitstream, org.dspace.app.rest.model.BitstreamRest> {
@Autowired(required = true) @Autowired
BitstreamFormatConverter bfConverter; ConverterService converter;
@Override @Override
public org.dspace.content.Bitstream toModel(org.dspace.app.rest.model.BitstreamRest obj) { public BitstreamRest convert(org.dspace.content.Bitstream obj, Projection projection) {
return super.toModel(obj); BitstreamRest b = super.convert(obj, projection);
}
@Override
public BitstreamRest fromModel(org.dspace.content.Bitstream obj) {
BitstreamRest b = super.fromModel(obj);
b.setSequenceId(obj.getSequenceID()); b.setSequenceId(obj.getSequenceID());
List<Bundle> bundles = null; List<Bundle> bundles = null;
try { try {
@@ -53,14 +48,11 @@ public class BitstreamConverter
checksum.setCheckSumAlgorithm(obj.getChecksumAlgorithm()); checksum.setCheckSumAlgorithm(obj.getChecksumAlgorithm());
checksum.setValue(obj.getChecksum()); checksum.setValue(obj.getChecksum());
b.setCheckSum(checksum); b.setCheckSum(checksum);
BitstreamFormatRest format = null;
try { try {
format = bfConverter.fromModel(obj.getFormat(null)); b.setFormat(converter.toRest(obj.getFormat(null), projection));
} catch (Exception e) { } catch (SQLException e) {
// TODO Auto-generated catch block throw new RuntimeException(e);
e.printStackTrace();
} }
b.setFormat(format);
b.setSizeBytes(obj.getSizeBytes()); b.setSizeBytes(obj.getSizeBytes());
return b; return b;
} }
@@ -71,7 +63,7 @@ public class BitstreamConverter
} }
@Override @Override
protected Class<Bitstream> getModelClass() { public Class<Bitstream> getModelClass() {
return Bitstream.class; return Bitstream.class;
} }
} }

View File

@@ -8,6 +8,7 @@
package org.dspace.app.rest.converter; package org.dspace.app.rest.converter;
import org.dspace.app.rest.model.BitstreamFormatRest; import org.dspace.app.rest.model.BitstreamFormatRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.content.BitstreamFormat; import org.dspace.content.BitstreamFormat;
import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamFormatService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -26,8 +27,9 @@ public class BitstreamFormatConverter implements DSpaceConverter<BitstreamFormat
BitstreamFormatService bitstreamFormatService; BitstreamFormatService bitstreamFormatService;
@Override @Override
public BitstreamFormatRest fromModel(BitstreamFormat obj) { public BitstreamFormatRest convert(BitstreamFormat obj, Projection projection) {
BitstreamFormatRest bf = new BitstreamFormatRest(); BitstreamFormatRest bf = new BitstreamFormatRest();
bf.setProjection(projection);
bf.setId(obj.getID()); bf.setId(obj.getID());
bf.setShortDescription(obj.getShortDescription()); bf.setShortDescription(obj.getShortDescription());
bf.setDescription(obj.getDescription()); bf.setDescription(obj.getDescription());
@@ -43,8 +45,7 @@ public class BitstreamFormatConverter implements DSpaceConverter<BitstreamFormat
} }
@Override @Override
public BitstreamFormat toModel(BitstreamFormatRest obj) { public Class<BitstreamFormat> getModelClass() {
// TODO Auto-generated method stub return BitstreamFormat.class;
return null;
} }
} }

Some files were not shown because too many files have changed in this diff Show More