mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge branch 'master' into Authentication_X-Forwarded-For
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# This image will be published as dspace/dspace
|
||||
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
|
||||
#
|
||||
# This version is JDK8 compatible
|
||||
# - tomcat:8-jre8
|
||||
# - ANT 1.10.5
|
||||
# - maven:latest
|
||||
# - note:
|
||||
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8
|
||||
|
||||
# Step 1 - Run Maven Build
|
||||
FROM maven as build
|
||||
@@ -12,7 +19,7 @@ COPY dspace/src/main/docker/local.cfg /app/local.cfg
|
||||
RUN mvn package
|
||||
|
||||
# Step 2 - Run Ant Deploy
|
||||
FROM tomcat:8 as ant_build
|
||||
FROM tomcat:8-jre8 as ant_build
|
||||
ARG TARGET_DIR=dspace-installer
|
||||
COPY --from=build /app /dspace-src
|
||||
WORKDIR /dspace-src/dspace/target/${TARGET_DIR}
|
||||
@@ -29,7 +36,7 @@ RUN ant update_configs update_code update_webapps update_solr_indexes
|
||||
|
||||
# Step 3 - Run tomcat
|
||||
# Create a new tomcat image that does not retain the the build directory contents
|
||||
FROM tomcat:8
|
||||
FROM tomcat:8-jre8
|
||||
COPY --from=ant_build /dspace /dspace
|
||||
EXPOSE 8080 8009
|
||||
|
64
Dockerfile.jdk8-test
Normal file
64
Dockerfile.jdk8-test
Normal file
@@ -0,0 +1,64 @@
|
||||
# This image will be published as dspace/dspace
|
||||
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
|
||||
#
|
||||
# This version is JDK8 compatible
|
||||
# - tomcat:8-jre8
|
||||
# - ANT 1.10.5
|
||||
# - maven:latest
|
||||
# - note: expose /solr to any host; provide /rest over http
|
||||
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8-test
|
||||
|
||||
# Step 1 - Run Maven Build
|
||||
FROM maven as build
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
|
||||
ADD . /app/
|
||||
COPY dspace/src/main/docker/local.cfg /app/local.cfg
|
||||
|
||||
# Provide web.xml overrides to make webapps easier to test
|
||||
COPY dspace/src/main/docker/test/solr_web.xml /app/dspace-solr/src/main/webapp/WEB-INF/web.xml
|
||||
COPY dspace/src/main/docker/test/rest_web.xml /app/dspace-rest/src/main/webapp/WEB-INF/web.xml
|
||||
|
||||
RUN mvn package
|
||||
|
||||
# Step 2 - Run Ant Deploy
|
||||
FROM tomcat:8-jre8 as ant_build
|
||||
ARG TARGET_DIR=dspace-installer
|
||||
COPY --from=build /app /dspace-src
|
||||
WORKDIR /dspace-src/dspace/target/${TARGET_DIR}
|
||||
|
||||
# Create the initial install deployment using ANT
|
||||
ENV ANT_VERSION 1.10.5
|
||||
ENV ANT_HOME /tmp/ant-$ANT_VERSION
|
||||
ENV PATH $ANT_HOME/bin:$PATH
|
||||
|
||||
RUN mkdir $ANT_HOME && \
|
||||
wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
|
||||
|
||||
RUN ant update_configs update_code update_webapps update_solr_indexes
|
||||
|
||||
# Step 3 - Run tomcat
|
||||
# Create a new tomcat image that does not retain the the build directory contents
|
||||
FROM tomcat:8-jre8
|
||||
COPY --from=ant_build /dspace /dspace
|
||||
EXPOSE 8080 8009
|
||||
|
||||
# Ant will be embedded in the final container to allow additional deployments
|
||||
ENV ANT_VERSION 1.10.5
|
||||
ENV ANT_HOME /tmp/ant-$ANT_VERSION
|
||||
ENV PATH $ANT_HOME/bin:$PATH
|
||||
|
||||
RUN mkdir $ANT_HOME && \
|
||||
wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
|
||||
|
||||
ENV DSPACE_INSTALL=/dspace
|
||||
ENV JAVA_OPTS=-Xmx2000m
|
||||
|
||||
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
|
||||
ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \
|
||||
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
|
||||
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
|
||||
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
|
||||
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
|
||||
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
|
@@ -40,6 +40,9 @@ Please be aware that, as a Java web application, DSpace requires a database (Pos
|
||||
and a servlet container (usually Tomcat) in order to function.
|
||||
More information about these and all other prerequisites can be found in the Installation instructions above.
|
||||
|
||||
## Dockerfile Usage
|
||||
See the [DSpace Docker Tutorial](https://dspace-labs.github.io/DSpace-Docker-Images/).
|
||||
|
||||
## Contributing
|
||||
|
||||
DSpace is a community built and supported project. We do not have a centralized development or support team,
|
||||
|
@@ -364,10 +364,6 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
@@ -399,7 +395,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -63,6 +63,12 @@ public class DCInput {
|
||||
*/
|
||||
private String label = null;
|
||||
|
||||
/**
|
||||
* a style instruction to apply to the input. The exact way to use the style value is UI depending that receive the
|
||||
* value from the REST API as is
|
||||
*/
|
||||
private String style = null;
|
||||
|
||||
/**
|
||||
* the input type
|
||||
*/
|
||||
@@ -199,7 +205,7 @@ public class DCInput {
|
||||
typeBind.add(type.trim());
|
||||
}
|
||||
}
|
||||
|
||||
style = fieldMap.get("style");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +268,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DC element for this form row.
|
||||
* Get the DC element for this form field.
|
||||
*
|
||||
* @return the DC element
|
||||
*/
|
||||
@@ -271,7 +277,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DC namespace prefix for this form row.
|
||||
* Get the DC namespace prefix for this form field.
|
||||
*
|
||||
* @return the DC namespace prefix
|
||||
*/
|
||||
@@ -290,7 +296,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there a required string for this form row?
|
||||
* Is there a required string for this form field?
|
||||
*
|
||||
* @return true if a required string is set
|
||||
*/
|
||||
@@ -299,7 +305,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DC qualifier for this form row.
|
||||
* Get the DC qualifier for this form field.
|
||||
*
|
||||
* @return the DC qualifier
|
||||
*/
|
||||
@@ -308,7 +314,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the language for this form row.
|
||||
* Get the language for this form field.
|
||||
*
|
||||
* @return the language state
|
||||
*/
|
||||
@@ -317,7 +323,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the hint for this form row, formatted for an HTML table
|
||||
* Get the hint for this form field
|
||||
*
|
||||
* @return the hints
|
||||
*/
|
||||
@@ -326,7 +332,7 @@ public class DCInput {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label for this form row.
|
||||
* Get the label for this form field.
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
@@ -334,6 +340,15 @@ public class DCInput {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the style for this form field
|
||||
*
|
||||
* @return the style
|
||||
*/
|
||||
public String getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the pairs type
|
||||
*
|
||||
|
@@ -25,25 +25,26 @@ public class DCInputSet {
|
||||
/**
|
||||
* the inputs ordered by row position
|
||||
*/
|
||||
private DCInput[] inputs = null;
|
||||
private DCInput[][] inputs = null;
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @param formName form name
|
||||
* @param headings
|
||||
* @param mandatoryFlags
|
||||
* @param fields fields
|
||||
* @param rows the rows
|
||||
* @param listMap map
|
||||
*/
|
||||
public DCInputSet(String formName,
|
||||
List<Map<String, String>> fields, Map<String, List<String>> listMap) {
|
||||
public DCInputSet(String formName, List<List<Map<String, String>>> rows, Map<String, List<String>> listMap) {
|
||||
this.formName = formName;
|
||||
this.inputs = new DCInput[fields.size()];
|
||||
this.inputs = new DCInput[rows.size()][];
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
Map<String, String> field = fields.get(i);
|
||||
inputs[i] = new DCInput(field, listMap);
|
||||
|
||||
List<Map<String, String>> fields = rows.get(i);
|
||||
inputs[i] = new DCInput[fields.size()];
|
||||
for (int j = 0; j < inputs[i].length; j++) {
|
||||
Map<String, String> field = rows.get(i).get(j);
|
||||
inputs[i][j] = new DCInput(field, listMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@ public class DCInputSet {
|
||||
* @return an array containing the fields
|
||||
*/
|
||||
|
||||
public DCInput[] getFields() {
|
||||
public DCInput[][] getFields() {
|
||||
return inputs;
|
||||
}
|
||||
|
||||
@@ -104,10 +105,12 @@ public class DCInputSet {
|
||||
*/
|
||||
public boolean isFieldPresent(String fieldName) {
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
DCInput field = inputs[i];
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
return true;
|
||||
for (int j = 0; j < inputs[i].length; j++) {
|
||||
DCInput field = inputs[i][j];
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -127,11 +130,13 @@ public class DCInputSet {
|
||||
documentType = "";
|
||||
}
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
DCInput field = inputs[i];
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
if (field.isAllowedFor(documentType)) {
|
||||
return true;
|
||||
for (int j = 0; j < inputs[i].length; j++) {
|
||||
DCInput field = inputs[i][j];
|
||||
String fullName = field.getFieldName();
|
||||
if (fullName.equals(fieldName)) {
|
||||
if (field.isAllowedFor(documentType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -74,7 +74,7 @@ public class DCInputsReader {
|
||||
* Reference to the forms definitions map, computed from the forms
|
||||
* definition file
|
||||
*/
|
||||
private Map<String, List<Map<String, String>>> formDefns = null;
|
||||
private Map<String, List<List<Map<String, String>>>> formDefns = null;
|
||||
|
||||
/**
|
||||
* Reference to the value-pairs map, computed from the forms definition file
|
||||
@@ -115,7 +115,7 @@ public class DCInputsReader {
|
||||
|
||||
private void buildInputs(String fileName)
|
||||
throws DCInputsReaderException {
|
||||
formDefns = new HashMap<String, List<Map<String, String>>>();
|
||||
formDefns = new HashMap<String, List<List<Map<String, String>>>>();
|
||||
valuePairs = new HashMap<String, List<String>>();
|
||||
|
||||
String uri = "file:" + new File(fileName).getAbsolutePath();
|
||||
@@ -212,7 +212,7 @@ public class DCInputsReader {
|
||||
return lastInputSet;
|
||||
}
|
||||
// cache miss - construct new DCInputSet
|
||||
List<Map<String, String>> pages = formDefns.get(formName);
|
||||
List<List<Map<String, String>>> pages = formDefns.get(formName);
|
||||
if (pages == null) {
|
||||
throw new DCInputsReaderException("Missing the " + formName + " form");
|
||||
}
|
||||
@@ -292,8 +292,8 @@ public class DCInputsReader {
|
||||
|
||||
/**
|
||||
* Process the form-definitions section of the XML file. Each element is
|
||||
* formed thusly: <form name="formname">...pages...</form> Each pages
|
||||
* subsection is formed: <page number="#"> ...fields... </page> Each field
|
||||
* formed thusly: <form name="formname">...row...</form> Each rows
|
||||
* subsection is formed: <row> ...fields... </row> Each field
|
||||
* is formed from: dc-element, dc-qualifier, label, hint, input-type name,
|
||||
* required text, and repeatable flag.
|
||||
*/
|
||||
@@ -311,26 +311,24 @@ public class DCInputsReader {
|
||||
if (formName == null) {
|
||||
throw new SAXException("form element has no name attribute");
|
||||
}
|
||||
List<Map<String, String>> fields = new ArrayList<Map<String, String>>(); // the form contains fields
|
||||
formDefns.put(formName, fields);
|
||||
List<List<Map<String, String>>> rows = new ArrayList<List<Map<String, String>>>(); // the form
|
||||
// contains rows of fields
|
||||
formDefns.put(formName, rows);
|
||||
NodeList pl = nd.getChildNodes();
|
||||
int lenpg = pl.getLength();
|
||||
for (int j = 0; j < lenpg; j++) {
|
||||
Node npg = pl.item(j);
|
||||
|
||||
if (npg.getNodeName().equals("field")) {
|
||||
// process each field definition
|
||||
Map<String, String> field = new HashMap<String, String>();
|
||||
processField(formName, npg, field);
|
||||
fields.add(field);
|
||||
// we omit the duplicate validation, allowing multiple
|
||||
// fields definition for
|
||||
// the same metadata and different visibility/type-bind
|
||||
if (npg.getNodeName().equals("row")) {
|
||||
List<Map<String, String>> fields = new ArrayList<Map<String, String>>(); // the fields in the
|
||||
// row
|
||||
// process each row definition
|
||||
processRow(formName, j, npg, fields);
|
||||
rows.add(fields);
|
||||
}
|
||||
}
|
||||
// sanity check number of fields
|
||||
if (fields.size() < 1) {
|
||||
throw new DCInputsReaderException("Form " + formName + " has no fields");
|
||||
if (rows.size() < 1) {
|
||||
throw new DCInputsReaderException("Form " + formName + " has no rows");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,6 +337,48 @@ public class DCInputsReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process parts of a row
|
||||
*/
|
||||
private void processRow(String formName, int rowIdx, Node n, List<Map<String, String>> fields)
|
||||
throws SAXException, DCInputsReaderException {
|
||||
|
||||
NodeList pl = n.getChildNodes();
|
||||
int lenpg = pl.getLength();
|
||||
for (int j = 0; j < lenpg; j++) {
|
||||
Node npg = pl.item(j);
|
||||
|
||||
if (npg.getNodeName().equals("field")) {
|
||||
// process each field definition
|
||||
Map<String, String> field = new HashMap<String, String>();
|
||||
processField(formName, npg, field);
|
||||
fields.add(field);
|
||||
String key = field.get(PAIR_TYPE_NAME);
|
||||
if (StringUtils
|
||||
.isNotBlank(key)) {
|
||||
String schema = field.get("dc-schema");
|
||||
String element = field.get("dc-element");
|
||||
String qualifier = field
|
||||
.get("dc-qualifier");
|
||||
String metadataField = schema + "."
|
||||
+ element;
|
||||
if (StringUtils.isNotBlank(qualifier)) {
|
||||
metadataField += "." + qualifier;
|
||||
}
|
||||
}
|
||||
|
||||
// we omit the duplicate validation, allowing multiple
|
||||
// fields definition for
|
||||
// the same metadata and different visibility/type-bind
|
||||
}
|
||||
}
|
||||
// sanity check number of fields
|
||||
if (fields.size() < 1) {
|
||||
throw new DCInputsReaderException("Form " + formName + "row " + rowIdx + " has no fields");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process parts of a field
|
||||
* At the end, make sure that input-types 'qualdrop_value' and
|
||||
@@ -537,26 +577,29 @@ public class DCInputsReader {
|
||||
Iterator<String> ki = formDefns.keySet().iterator();
|
||||
while (ki.hasNext()) {
|
||||
String idName = ki.next();
|
||||
List<Map<String, String>> fields = formDefns.get(idName);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
Map<String, String> fld = fields.get(i);
|
||||
// verify reference in certain input types
|
||||
String type = fld.get("input-type");
|
||||
if (type.equals("dropdown")
|
||||
|| type.equals("qualdrop_value")
|
||||
|| type.equals("list")) {
|
||||
String pairsName = fld.get(PAIR_TYPE_NAME);
|
||||
List<String> v = valuePairs.get(pairsName);
|
||||
if (v == null) {
|
||||
String errString = "Cannot find value pairs for " + pairsName;
|
||||
throw new DCInputsReaderException(errString);
|
||||
List<List<Map<String, String>>> rows = formDefns.get(idName);
|
||||
for (int j = 0; j < rows.size(); j++) {
|
||||
List<Map<String, String>> fields = rows.get(j);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
Map<String, String> fld = fields.get(i);
|
||||
// verify reference in certain input types
|
||||
String type = fld.get("input-type");
|
||||
if (type.equals("dropdown")
|
||||
|| type.equals("qualdrop_value")
|
||||
|| type.equals("list")) {
|
||||
String pairsName = fld.get(PAIR_TYPE_NAME);
|
||||
List<String> v = valuePairs.get(pairsName);
|
||||
if (v == null) {
|
||||
String errString = "Cannot find value pairs for " + pairsName;
|
||||
throw new DCInputsReaderException(errString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we omit the "required" and "visibility" validation, provided this must be checked in the
|
||||
// processing class
|
||||
// only when it makes sense (if the field isn't visible means that it is not applicable, therefore it
|
||||
// can't be required)
|
||||
// we omit the "required" and "visibility" validation, provided this must be checked in the
|
||||
// processing class
|
||||
// only when it makes sense (if the field isn't visible means that it is not applicable,
|
||||
// therefore it can't be required)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -639,4 +682,5 @@ public class DCInputsReader {
|
||||
}
|
||||
throw new DCInputsReaderException("No field configuration found!");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -418,11 +418,12 @@ public class Util {
|
||||
|
||||
List<DCInputSet> inputSets = inputsReader.getInputsByCollectionHandle(col_handle);
|
||||
|
||||
// Replace the values of Metadatum[] with the correct ones in case
|
||||
// of
|
||||
// controlled vocabularies
|
||||
String currentField = Utils.standardize(schema, element, qualifier, ".");
|
||||
|
||||
for (DCInputSet inputSet : inputSets) {
|
||||
// Replace the values of Metadatum[] with the correct ones in case
|
||||
// of
|
||||
// controlled vocabularies
|
||||
String currentField = Utils.standardize(schema, element, qualifier, ".");
|
||||
|
||||
if (inputSet != null) {
|
||||
|
||||
@@ -430,19 +431,20 @@ public class Util {
|
||||
|
||||
for (int p = 0; p < fieldsNums; p++) {
|
||||
|
||||
DCInput[] inputs = inputSet.getFields();
|
||||
DCInput[][] inputs = inputSet.getFields();
|
||||
|
||||
if (inputs != null) {
|
||||
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
String inputField = Utils.standardize(inputs[i].getSchema(), inputs[i].getElement(),
|
||||
inputs[i].getQualifier(), ".");
|
||||
if (currentField.equals(inputField)) {
|
||||
|
||||
myInputs = inputs[i];
|
||||
myInputsFound = true;
|
||||
break;
|
||||
|
||||
for (int j = 0; j < inputs[i].length; j++) {
|
||||
String inputField = Utils
|
||||
.standardize(inputs[i][j].getSchema(), inputs[i][j].getElement(),
|
||||
inputs[i][j].getQualifier(), ".");
|
||||
if (currentField.equals(inputField)) {
|
||||
myInputs = inputs[i][j];
|
||||
myInputsFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -480,13 +482,17 @@ public class Util {
|
||||
Set<String> fromFieldName = new HashSet<>();
|
||||
Set<String> toFieldName = new HashSet<>();
|
||||
for (DCInputSet ff : from) {
|
||||
for (DCInput fdc : ff.getFields()) {
|
||||
fromFieldName.add(fdc.getFieldName());
|
||||
for (DCInput[] fdcrow : ff.getFields()) {
|
||||
for (DCInput fdc : fdcrow) {
|
||||
fromFieldName.add(fdc.getFieldName());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (DCInputSet tt : to) {
|
||||
for (DCInput tdc : tt.getFields()) {
|
||||
toFieldName.add(tdc.getFieldName());
|
||||
for (DCInput[] tdcrow : tt.getFields()) {
|
||||
for (DCInput tdc : tdcrow) {
|
||||
toFieldName.add(tdc.getFieldName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -147,6 +147,12 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
|
||||
return workspaceItemDAO.findByEPerson(context, ep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep, Integer limit, Integer offset)
|
||||
throws SQLException {
|
||||
return workspaceItemDAO.findByEPerson(context, ep, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findByCollection(Context context, Collection collection) throws SQLException {
|
||||
return workspaceItemDAO.findByCollection(context, collection);
|
||||
@@ -231,6 +237,11 @@ public class WorkspaceItemServiceImpl implements WorkspaceItemService {
|
||||
return workspaceItemDAO.countRows(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countByEPerson(Context context, EPerson ep) throws SQLException {
|
||||
return workspaceItemDAO.countRows(context, ep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map.Entry<Integer, Long>> getStageReachedCounts(Context context) throws SQLException {
|
||||
return workspaceItemDAO.getStageReachedCounts(context);
|
||||
|
@@ -264,39 +264,42 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
|
||||
try {
|
||||
DCInputsReader dcInputsReader = new DCInputsReader();
|
||||
for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) {
|
||||
DCInput[] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput dcinput : dcinputs) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
ChoiceAuthority ca = controller.get(authorityName);
|
||||
if (ca == null) {
|
||||
InputFormSelfRegisterWrapperAuthority ifa = new InputFormSelfRegisterWrapperAuthority();
|
||||
if (controller.containsKey(fieldKey)) {
|
||||
ifa = (InputFormSelfRegisterWrapperAuthority) controller.get(fieldKey);
|
||||
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput[] dcrows : dcinputs) {
|
||||
for (DCInput dcinput : dcrows) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
ChoiceAuthority ca = controller.get(authorityName);
|
||||
if (ca == null) {
|
||||
InputFormSelfRegisterWrapperAuthority ifa = new
|
||||
InputFormSelfRegisterWrapperAuthority();
|
||||
if (controller.containsKey(fieldKey)) {
|
||||
ifa = (InputFormSelfRegisterWrapperAuthority) controller.get(fieldKey);
|
||||
}
|
||||
|
||||
ChoiceAuthority ma = (ChoiceAuthority) pluginService
|
||||
.getNamedPlugin(ChoiceAuthority.class, authorityName);
|
||||
if (ma == null) {
|
||||
log.warn("Skipping invalid configuration for " + fieldKey
|
||||
+ " because named plugin not found: " + authorityName);
|
||||
continue;
|
||||
}
|
||||
ifa.getDelegates().put(dcinputSet.getFormName(), ma);
|
||||
controller.put(fieldKey, ifa);
|
||||
}
|
||||
|
||||
ChoiceAuthority ma = (ChoiceAuthority) pluginService
|
||||
.getNamedPlugin(ChoiceAuthority.class, authorityName);
|
||||
if (ma == null) {
|
||||
log.warn("Skipping invalid configuration for " + fieldKey
|
||||
+ " because named plugin not found: " + authorityName);
|
||||
continue;
|
||||
if (!authorities.containsKey(authorityName)) {
|
||||
authorities.put(authorityName, fieldKey);
|
||||
}
|
||||
ifa.getDelegates().put(dcinputSet.getFormName(), ma);
|
||||
controller.put(fieldKey, ifa);
|
||||
}
|
||||
|
||||
if (!authorities.containsKey(authorityName)) {
|
||||
authorities.put(authorityName, fieldKey);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -235,21 +235,23 @@ public class MetadataAuthorityServiceImpl implements MetadataAuthorityService {
|
||||
try {
|
||||
DCInputsReader dcInputsReader = new DCInputsReader();
|
||||
for (DCInputSet dcinputSet : dcInputsReader.getAllInputs(Integer.MAX_VALUE, 0)) {
|
||||
DCInput[] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput dcinput : dcinputs) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
boolean req = ConfigurationManager
|
||||
.getBooleanProperty("authority.required." + fieldKey, false);
|
||||
controlled.put(fieldKey, true);
|
||||
isAuthorityRequired.put(fieldKey, req);
|
||||
DCInput[][] dcinputs = dcinputSet.getFields();
|
||||
for (DCInput[] dcrows : dcinputs) {
|
||||
for (DCInput dcinput : dcrows) {
|
||||
if (StringUtils.isNotBlank(dcinput.getPairsType())
|
||||
|| StringUtils.isNotBlank(dcinput.getVocabulary())) {
|
||||
String authorityName = dcinput.getPairsType();
|
||||
if (StringUtils.isBlank(authorityName)) {
|
||||
authorityName = dcinput.getVocabulary();
|
||||
}
|
||||
if (!StringUtils.equals(dcinput.getInputType(), "qualdrop_value")) {
|
||||
String fieldKey = makeFieldKey(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier());
|
||||
boolean req = ConfigurationManager
|
||||
.getBooleanProperty("authority.required." + fieldKey, false);
|
||||
controlled.put(fieldKey, true);
|
||||
isAuthorityRequired.put(fieldKey, req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -30,6 +30,9 @@ public interface WorkspaceItemDAO extends GenericDAO<WorkspaceItem> {
|
||||
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep) throws SQLException;
|
||||
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep, Integer limit, Integer offset)
|
||||
throws SQLException;
|
||||
|
||||
public List<WorkspaceItem> findByCollection(Context context, Collection c) throws SQLException;
|
||||
|
||||
public WorkspaceItem findByItem(Context context, Item i) throws SQLException;
|
||||
@@ -45,4 +48,7 @@ public interface WorkspaceItemDAO extends GenericDAO<WorkspaceItem> {
|
||||
int countRows(Context context) throws SQLException;
|
||||
|
||||
List<Map.Entry<Integer, Long>> getStageReachedCounts(Context context) throws SQLException;
|
||||
|
||||
public int countRows(Context context, EPerson ep) throws SQLException;
|
||||
|
||||
}
|
||||
|
@@ -51,6 +51,18 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
return list(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep, Integer limit, Integer offset)
|
||||
throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class);
|
||||
Root<WorkspaceItem> workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class);
|
||||
criteriaQuery.select(workspaceItemRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.item).get("submitter"), ep));
|
||||
criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
return list(context, criteriaQuery, false, WorkspaceItem.class, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findByCollection(Context context, Collection c) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
@@ -58,8 +70,8 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
Root<WorkspaceItem> workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class);
|
||||
criteriaQuery.select(workspaceItemRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.collection), c));
|
||||
criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,14 +86,13 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findAll(Context context) throws SQLException {
|
||||
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class);
|
||||
Root<WorkspaceItem> workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class);
|
||||
criteriaQuery.select(workspaceItemRoot);
|
||||
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.item)));
|
||||
orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
|
||||
|
||||
@@ -96,7 +107,7 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
criteriaQuery.select(workspaceItemRoot);
|
||||
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.item)));
|
||||
orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
|
||||
|
||||
@@ -105,8 +116,6 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findWithSupervisedGroup(Context context) throws SQLException {
|
||||
|
||||
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class);
|
||||
Root<WorkspaceItem> workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class);
|
||||
@@ -116,16 +125,11 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
List<javax.persistence.criteria.Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
criteriaQuery.orderBy(orderList);
|
||||
|
||||
|
||||
return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<WorkspaceItem> findBySupervisedGroupMember(Context context, EPerson ePerson) throws SQLException {
|
||||
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class);
|
||||
Root<WorkspaceItem> workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class);
|
||||
@@ -133,6 +137,7 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
Join<Group, EPerson> secondJoin = join.join("epeople");
|
||||
criteriaQuery.select(workspaceItemRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(secondJoin.get(EPerson_.id), ePerson.getID()));
|
||||
criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId)));
|
||||
return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1);
|
||||
}
|
||||
|
||||
@@ -141,6 +146,14 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO<WorkspaceItem> im
|
||||
return count(createQuery(context, "SELECT count(*) from WorkspaceItem"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countRows(Context context, EPerson ep) throws SQLException {
|
||||
Query query = createQuery(context,
|
||||
"SELECT count(*) from WorkspaceItem ws where ws.item.submitter = :submitter");
|
||||
query.setParameter("submitter", ep);
|
||||
return count(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map.Entry<Integer, Long>> getStageReachedCounts(Context context) throws SQLException {
|
||||
|
@@ -72,6 +72,21 @@ public interface WorkspaceItemService extends InProgressSubmissionService<Worksp
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Get a page of workspace items for a particular e-person. These are ordered by
|
||||
* workspace item ID, since this should likely keep them in the order in
|
||||
* which they were created.
|
||||
*
|
||||
* @param context the context object
|
||||
* @param ep the eperson
|
||||
* @param limit the max number of workspaceitems to return
|
||||
* @param offset the offset
|
||||
* @return the corresponding workspace items
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
public List<WorkspaceItem> findByEPerson(Context context, EPerson ep, Integer limit, Integer offset)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Get all workspace items for a particular collection.
|
||||
*
|
||||
@@ -146,4 +161,8 @@ public interface WorkspaceItemService extends InProgressSubmissionService<Worksp
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
List<Map.Entry<Integer, Long>> getStageReachedCounts(Context context) throws SQLException;
|
||||
|
||||
|
||||
public int countByEPerson(Context context, EPerson ep) throws SQLException;
|
||||
|
||||
}
|
||||
|
@@ -100,17 +100,19 @@ public class RequiredMetadata extends AbstractCurationTask {
|
||||
reqList = new ArrayList<String>();
|
||||
List<DCInputSet> inputSet = reader.getInputsByCollectionHandle(handle);
|
||||
for (DCInputSet inputs : inputSet) {
|
||||
for (DCInput input : inputs.getFields()) {
|
||||
if (input.isRequired()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(input.getSchema()).append(".");
|
||||
sb.append(input.getElement()).append(".");
|
||||
String qual = input.getQualifier();
|
||||
if (qual == null) {
|
||||
qual = "";
|
||||
for (DCInput[] row : inputs.getFields()) {
|
||||
for (DCInput input : row) {
|
||||
if (input.isRequired()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(input.getSchema()).append(".");
|
||||
sb.append(input.getElement()).append(".");
|
||||
String qual = input.getQualifier();
|
||||
if (qual == null) {
|
||||
qual = "";
|
||||
}
|
||||
sb.append(qual);
|
||||
reqList.add(sb.toString());
|
||||
}
|
||||
sb.append(qual);
|
||||
reqList.add(sb.toString());
|
||||
}
|
||||
}
|
||||
reqMap.put(inputs.getFormName(), reqList);
|
||||
|
@@ -152,7 +152,6 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
log.info("solr-statistics.spidersfile:" + configurationService.getProperty("solr-statistics.spidersfile"));
|
||||
log.info("solr-statistics.server:" + configurationService.getProperty("solr-statistics.server"));
|
||||
log.info("usage-statistics.dbfile:" + configurationService.getProperty("usage-statistics.dbfile"));
|
||||
|
||||
|
@@ -7,10 +7,12 @@
|
||||
*/
|
||||
package org.dspace.submit;
|
||||
|
||||
import org.dspace.app.itemimport.BTEBatchImportService;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.BitstreamFormatService;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.content.service.BundleService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
@@ -20,24 +22,27 @@ import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.services.model.Request;
|
||||
|
||||
/**
|
||||
* Abstract processing class for DSpace Submission Steps. This defines the base
|
||||
* methods which are required for any Step processing class.
|
||||
* Abstract processing class for DSpace Submission Steps. This defines the base methods which are required for any Step
|
||||
* processing class.
|
||||
*/
|
||||
public abstract class AbstractProcessingStep {
|
||||
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
||||
protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
|
||||
.getBitstreamFormatService();
|
||||
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
||||
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
||||
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
|
||||
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
|
||||
protected BTEBatchImportService bteBatchImportService = DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("org.dspace.app.itemimport" + ".BTEBatchImportService", BTEBatchImportService.class);
|
||||
|
||||
public abstract void doProcessing(Context context, Request req, InProgressSubmission wsi);
|
||||
public abstract void doPreProcessing(Context context, InProgressSubmission wsi);
|
||||
|
||||
public abstract void doPostProcessing(Context context, Request obj, InProgressSubmission wsi);
|
||||
public abstract void doPostProcessing(Context context, InProgressSubmission wsi);
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.submit.extraction;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import gr.ekt.bte.dataloader.FileDataLoader;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
|
||||
/**
|
||||
* Configuration bean to associate a BTE FileDataLoader with a specific list of format identified by the file
|
||||
* extensions. See config/spring/api/metadata-extractor.xml
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class MetadataExtractor {
|
||||
|
||||
private List<String> extensions;
|
||||
|
||||
private FileDataLoader dataLoader;
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
public List<String> getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public void setExtensions(List<String> mime) {
|
||||
this.extensions = mime;
|
||||
}
|
||||
|
||||
public FileDataLoader getDataLoader() {
|
||||
return dataLoader;
|
||||
}
|
||||
|
||||
public void setDataLoader(FileDataLoader dataLoader) {
|
||||
this.dataLoader = dataLoader;
|
||||
}
|
||||
|
||||
public ConfigurationService getConfigurationService() {
|
||||
return configurationService;
|
||||
}
|
||||
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.submit.listener;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import gr.ekt.bte.core.DataLoader;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
|
||||
/**
|
||||
* Configuration bean to map metadata to identifiers (i.e dc.identifier.doi -> doi, dc.identifier.isbn -> isbn) and
|
||||
* alias to BTE Data Loader. See config/spring/api/step-processing.xml
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class MetadataListener {
|
||||
|
||||
/**
|
||||
* Metadata to identifier map
|
||||
*/
|
||||
private Map<String, String> metadata;
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
/**
|
||||
* Alias to data loader map
|
||||
*/
|
||||
private Map<String, DataLoader> dataloadersMap;
|
||||
|
||||
public ConfigurationService getConfigurationService() {
|
||||
return configurationService;
|
||||
}
|
||||
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
public Map<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public void setMetadata(Map<String, String> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public Map<String, DataLoader> getDataloadersMap() {
|
||||
return dataloadersMap;
|
||||
}
|
||||
|
||||
public void setDataloadersMap(Map<String, DataLoader> dataloadersMap) {
|
||||
this.dataloadersMap = dataloadersMap;
|
||||
}
|
||||
|
||||
}
|
@@ -275,13 +275,15 @@ public class DSpaceWorkspaceItemOutputGenerator implements OutputGenerator {
|
||||
String qualifier) throws DCInputsReaderException {
|
||||
List<DCInputSet> dcinputsets = new DCInputsReader().getInputsBySubmissionName(formName);
|
||||
for (DCInputSet dcinputset : dcinputsets) {
|
||||
for (DCInput dcinput : dcinputset.getFields()) {
|
||||
if (dcinput.getSchema().equals(schema)
|
||||
&& dcinput.getElement().equals(element)
|
||||
&& ((dcinput.getQualifier() != null && dcinput
|
||||
.getQualifier().equals(qualifier))
|
||||
|| (dcinput.getQualifier() == null && qualifier == null))) {
|
||||
return dcinput;
|
||||
for (DCInput[] dcrow : dcinputset.getFields()) {
|
||||
for (DCInput dcinput : dcrow) {
|
||||
if (dcinput.getSchema().equals(schema)
|
||||
&& dcinput.getElement().equals(element)
|
||||
&& ((dcinput.getQualifier() != null && dcinput
|
||||
.getQualifier().equals(qualifier))
|
||||
|| (dcinput.getQualifier() == null && qualifier == null))) {
|
||||
return dcinput;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,22 @@
|
||||
*/
|
||||
package org.dspace.submit.model;
|
||||
|
||||
/**
|
||||
* A simple POJO to store information about the available languages for a field
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class LanguageFormField {
|
||||
|
||||
/**
|
||||
* The value to present to the user
|
||||
*/
|
||||
private String display;
|
||||
|
||||
/**
|
||||
* The internal iso code to store in the database
|
||||
*/
|
||||
private String code;
|
||||
|
||||
public LanguageFormField(String code, String display) {
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
|
||||
@@ -21,13 +20,13 @@ public class AccessStep extends AbstractProcessingStep {
|
||||
private static Logger log = Logger.getLogger(AccessStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.license.factory.LicenseServiceFactory;
|
||||
import org.dspace.license.service.CreativeCommonsService;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class CCLicenseStep extends AbstractProcessingStep {
|
||||
@@ -25,15 +24,15 @@ public class CCLicenseStep extends AbstractProcessingStep {
|
||||
.getCreativeCommonsService();
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class CompleteStep extends AbstractProcessingStep {
|
||||
@@ -20,13 +19,13 @@ public class CompleteStep extends AbstractProcessingStep {
|
||||
private static Logger log = Logger.getLogger(CompleteStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -8,30 +8,14 @@
|
||||
package org.dspace.submit.step;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
|
||||
public class DescribeStep extends AbstractProcessingStep {
|
||||
/**
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class DescribeStep extends MetadataStep {
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private static Logger log = Logger.getLogger(DescribeStep.class);
|
||||
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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.submit.step;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class ExtractionStep extends MetadataStep {
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private static Logger log = Logger
|
||||
.getLogger(ExtractionStep.class);
|
||||
|
||||
}
|
@@ -9,19 +9,18 @@ package org.dspace.submit.step;
|
||||
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class InitialQuestionsStep extends AbstractProcessingStep {
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class LicenseStep extends AbstractProcessingStep {
|
||||
@@ -21,13 +20,13 @@ public class LicenseStep extends AbstractProcessingStep {
|
||||
private static Logger log = Logger.getLogger(LicenseStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* 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.submit.step;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import gr.ekt.bte.core.DataLoader;
|
||||
import gr.ekt.bte.core.Record;
|
||||
import gr.ekt.bte.core.Value;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
import org.dspace.submit.listener.MetadataListener;
|
||||
import org.dspace.submit.lookup.SubmissionLookupDataLoader;
|
||||
|
||||
//FIXME move to the ExtractionStep
|
||||
/**
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class MetadataStep extends AbstractProcessingStep {
|
||||
/**
|
||||
* log4j logger
|
||||
*/
|
||||
private static Logger log = Logger.getLogger(MetadataStep.class);
|
||||
|
||||
protected List<MetadataListener> listeners = DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServicesByType(MetadataListener.class);
|
||||
|
||||
protected Map<String, List<MetadataValue>> metadataMap = new HashMap<String, List<MetadataValue>>();
|
||||
private Map<String, Set<String>> results = new HashMap<String, Set<String>>();
|
||||
private Map<String, String> mappingIdentifier = new HashMap<String, String>();
|
||||
|
||||
@Override
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
for (MetadataListener listener : listeners) {
|
||||
for (String metadata : listener.getMetadata().keySet()) {
|
||||
String[] tokenized = Utils.tokenize(metadata);
|
||||
List<MetadataValue> mm = itemService.getMetadata(wsi.getItem(), tokenized[0], tokenized[1],
|
||||
tokenized[2], Item.ANY);
|
||||
if (mm != null && !mm.isEmpty()) {
|
||||
metadataMap.put(metadata, mm);
|
||||
} else {
|
||||
metadataMap.put(metadata, new ArrayList<MetadataValue>());
|
||||
}
|
||||
mappingIdentifier.put(metadata, listener.getMetadata().get(metadata));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
external:
|
||||
for (String metadata : metadataMap.keySet()) {
|
||||
String[] tokenized = Utils.tokenize(metadata);
|
||||
List<MetadataValue> currents = itemService.getMetadata(wsi.getItem(), tokenized[0], tokenized[1],
|
||||
tokenized[2], Item.ANY);
|
||||
if (currents != null && !currents.isEmpty()) {
|
||||
List<MetadataValue> olds = metadataMap.get(metadata);
|
||||
if (olds.isEmpty()) {
|
||||
process(context, metadata, currents);
|
||||
continue external;
|
||||
}
|
||||
internal:
|
||||
for (MetadataValue current : currents) {
|
||||
|
||||
boolean found = false;
|
||||
for (MetadataValue old : olds) {
|
||||
if (old.getValue().equals(current.getValue())) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
process(context, metadata, current);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!results.isEmpty()) {
|
||||
for (MetadataListener listener : listeners) {
|
||||
for (DataLoader dataLoader : listener.getDataloadersMap().values()) {
|
||||
SubmissionLookupDataLoader submissionLookupDataLoader = (SubmissionLookupDataLoader) dataLoader;
|
||||
try {
|
||||
List<Record> recordSet = submissionLookupDataLoader.getByIdentifier(context, results);
|
||||
List<Record> resultSet = convertFields(recordSet, bteBatchImportService.getOutputMap());
|
||||
enrichItem(context, resultSet, wsi.getItem());
|
||||
} catch (HttpException | IOException | SQLException | AuthorizeException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void enrichItem(Context context, List<Record> rset, Item item) throws SQLException, AuthorizeException {
|
||||
for (Record record : rset) {
|
||||
for (String field : record.getFields()) {
|
||||
try {
|
||||
String[] tfield = Utils.tokenize(field);
|
||||
List<MetadataValue> mdvs = itemService
|
||||
.getMetadata(item, tfield[0], tfield[1], tfield[2], Item.ANY);
|
||||
if (mdvs == null || mdvs.isEmpty()) {
|
||||
for (Value value : record.getValues(field)) {
|
||||
|
||||
itemService.addMetadata(context, item, tfield[0], tfield[1], tfield[2], null,
|
||||
value.getAsString());
|
||||
}
|
||||
} else {
|
||||
external:
|
||||
for (Value value : record.getValues(field)) {
|
||||
boolean found = false;
|
||||
for (MetadataValue mdv : mdvs) {
|
||||
if (mdv.getValue().equals(value.getAsString())) {
|
||||
found = true;
|
||||
continue external;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
itemService.addMetadata(context, item, tfield[0], tfield[1], tfield[2], null,
|
||||
value.getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
itemService.update(context, item);
|
||||
|
||||
}
|
||||
|
||||
private void process(Context context, String metadata, List<MetadataValue> currents) {
|
||||
for (MetadataValue current : currents) {
|
||||
process(context, metadata, current);
|
||||
}
|
||||
}
|
||||
|
||||
private void process(Context context, String metadata, MetadataValue current) {
|
||||
String key = mappingIdentifier.get(metadata);
|
||||
Set<String> identifiers = null;
|
||||
if (!results.containsKey(key)) {
|
||||
identifiers = new HashSet<String>();
|
||||
} else {
|
||||
identifiers = results.get(key);
|
||||
}
|
||||
identifiers.add(current.getValue());
|
||||
results.put(key, identifiers);
|
||||
}
|
||||
|
||||
public List<Record> convertFields(List<Record> recordSet, Map<String, String> fieldMap) {
|
||||
List<Record> result = new ArrayList<Record>();
|
||||
for (Record publication : recordSet) {
|
||||
for (String fieldName : fieldMap.keySet()) {
|
||||
String md = null;
|
||||
if (fieldMap != null) {
|
||||
md = fieldMap.get(fieldName);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(md)) {
|
||||
continue;
|
||||
} else {
|
||||
md = md.trim();
|
||||
}
|
||||
|
||||
if (publication.isMutable()) {
|
||||
List<Value> values = publication.getValues(md);
|
||||
publication.makeMutable().removeField(md);
|
||||
publication.makeMutable().addField(fieldName, values);
|
||||
}
|
||||
}
|
||||
|
||||
result.add(publication);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -9,19 +9,18 @@ package org.dspace.submit.step;
|
||||
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class SampleStep extends AbstractProcessingStep {
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class SelectCollectionStep extends AbstractProcessingStep {
|
||||
@@ -18,13 +17,13 @@ public class SelectCollectionStep extends AbstractProcessingStep {
|
||||
private static final Logger log = Logger.getLogger(SelectCollectionStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class StartSubmissionLookupStep extends AbstractProcessingStep {
|
||||
@@ -21,14 +20,14 @@ public class StartSubmissionLookupStep extends AbstractProcessingStep {
|
||||
.getLogger(StartSubmissionLookupStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,6 @@ package org.dspace.submit.step;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class UploadStep extends AbstractProcessingStep {
|
||||
@@ -20,13 +19,13 @@ public class UploadStep extends AbstractProcessingStep {
|
||||
private static final Logger log = Logger.getLogger(UploadStep.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -9,19 +9,18 @@ package org.dspace.submit.step;
|
||||
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
|
||||
public class VerifyStep extends AbstractProcessingStep {
|
||||
|
||||
@Override
|
||||
public void doProcessing(Context context, Request req, InProgressSubmission wsi) {
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doPostProcessing(Context context, Request obj, InProgressSubmission wsi) {
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
@@ -4,402 +4,416 @@
|
||||
|
||||
<input-forms>
|
||||
|
||||
<!-- The form-definitions map lays out the detailed definition of all the -->
|
||||
<!-- submission forms. Each separate form set has a unique name as an -->
|
||||
<!-- attribute. This name matches one of the names in the form-map. One -->
|
||||
<!-- named form set has the name "traditional"; as this name suggests, -->
|
||||
<!-- it is the old style and is also the default, which gets used when -->
|
||||
<!-- the specified collection has no correspondingly-named form set. -->
|
||||
<!-- -->
|
||||
<!-- Each form set contains an ordered set of pages; each page defines -->
|
||||
<!-- one submission metadata entry screen. Each page has an ordered list -->
|
||||
<!-- of field definitions, Each field definition corresponds to one -->
|
||||
<!-- metadata entry (a so-called row), which has a DC element name, a -->
|
||||
<!-- displayed label, a text string prompt which is called a hint, and -->
|
||||
<!-- an input-type. Each field also may hold optional elements: DC -->
|
||||
<!-- qualifier name, a repeatable flag, and a text string whose presence -->
|
||||
<!-- serves as a 'this field is required' flag. -->
|
||||
<!-- The form-definitions map lays out the detailed definition of all the -->
|
||||
<!-- submission forms. Each separate form set has a unique name as an -->
|
||||
<!-- attribute. This name matches one of the names in the form-map. One -->
|
||||
<!-- named form set has the name "traditional"; as this name suggests, -->
|
||||
<!-- it is the old style and is also the default, which gets used when -->
|
||||
<!-- the specified collection has no correspondingly-named form set. -->
|
||||
<!-- -->
|
||||
<!-- Each form set contains an ordered set of pages; each page defines -->
|
||||
<!-- one submission metadata entry screen. Each page has an ordered list -->
|
||||
<!-- of field definitions, Each field definition corresponds to one -->
|
||||
<!-- metadata entry (a so-called row), which has a DC element name, a -->
|
||||
<!-- displayed label, a text string prompt which is called a hint, and -->
|
||||
<!-- an input-type. Each field also may hold optional elements: DC -->
|
||||
<!-- qualifier name, a repeatable flag, and a text string whose presence -->
|
||||
<!-- serves as a 'this field is required' flag. -->
|
||||
|
||||
<form-definitions>
|
||||
<form name="bitstream-metadata">
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Title</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the name of the file.</hint>
|
||||
<required>You must enter a main title for this item.</required>
|
||||
</field>
|
||||
<form-definitions>
|
||||
<form name="bitstream-metadata">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Title</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the name of the file.</hint>
|
||||
<required>You must enter a main title for this item.</required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Description</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter a description for the file</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="traditionalpageone">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Authors</label>
|
||||
<input-type>name</input-type>
|
||||
<hint>Enter the names of the authors of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Title</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the main title of the item.</hint>
|
||||
<required>You must enter a main title for this item.</required>
|
||||
<!-- <language value-pairs-name="common_iso_languages">true</language> -->
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier>alternative</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Other Titles</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>If the item has any alternative titles, please enter them here.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>date</dc-element>
|
||||
<dc-qualifier>issued</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Date of Issue</label>
|
||||
<style>col-sm-4</style>
|
||||
<input-type>date</input-type>
|
||||
<hint>Please give the date of previous publication or public distribution.
|
||||
You can leave out the day and/or month if they aren't
|
||||
applicable.</hint>
|
||||
<required>You must enter at least the year.</required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Description</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter a description for the file</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</form>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>publisher</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Publisher</label>
|
||||
<style>col-sm-8</style>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the name of the publisher of the previously issued instance of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>identifier</dc-element>
|
||||
<dc-qualifier>citation</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Citation</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the standard citation for the previously issued instance of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>relation</dc-element>
|
||||
<dc-qualifier>ispartofseries</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Series/Report No.</label>
|
||||
<input-type>series</input-type>
|
||||
<hint>Enter the series and number assigned to this item by your community.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>identifier</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<!-- An input-type of qualdrop_value MUST be marked as repeatable -->
|
||||
<repeatable>true</repeatable>
|
||||
<label>Identifiers</label>
|
||||
<input-type value-pairs-name="common_identifiers">qualdrop_value</input-type>
|
||||
<hint>If the item has any identification numbers or codes associated with
|
||||
it, please enter the types and the actual numbers or codes.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>type</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Type</label>
|
||||
<input-type value-pairs-name="common_types">dropdown</input-type>
|
||||
<hint>Select the type(s) of content of the item. To select more than one value in the list, you may have to hold down the "CTRL" or "Shift" key.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>language</dc-element>
|
||||
<dc-qualifier>iso</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Language</label>
|
||||
<input-type value-pairs-name="common_iso_languages">dropdown</input-type>
|
||||
<hint>Select the language of the main content of the item. If the language does not appear in the list, please select 'Other'. If the content does not really have a language (for example, if it is a dataset or an image) please select 'N/A'.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="traditionalpagetwo">
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>subject</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<!-- An input-type of twobox MUST be marked as repeatable -->
|
||||
<repeatable>true</repeatable>
|
||||
<label>Subject Keywords</label>
|
||||
<input-type>twobox</input-type>
|
||||
<hint>Enter appropriate subject keywords or phrases. </hint>
|
||||
<required></required>
|
||||
<vocabulary>srsc</vocabulary>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier>abstract</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Abstract</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter the abstract of the item. </hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier>sponsorship</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Sponsors</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter the names of any sponsors and/or funding codes in the box. </hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
<row>
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Description</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter any other description or comments in this box. </hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</row>
|
||||
</form>
|
||||
|
||||
<form name="traditionalpageone">
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>contributor</dc-element>
|
||||
<dc-qualifier>author</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Authors</label>
|
||||
<input-type>name</input-type>
|
||||
<hint>Enter the names of the authors of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Title</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the main title of the item.</hint>
|
||||
<required>You must enter a main title for this item.</required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>title</dc-element>
|
||||
<dc-qualifier>alternative</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Other Titles</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>If the item has any alternative titles, please enter them here.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>date</dc-element>
|
||||
<dc-qualifier>issued</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Date of Issue</label>
|
||||
<input-type>date</input-type>
|
||||
<hint>Please give the date of previous publication or public distribution.
|
||||
You can leave out the day and/or month if they aren't
|
||||
applicable.
|
||||
</hint>
|
||||
<required>You must enter at least the year.</required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>publisher</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Publisher</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the name of the publisher of the previously issued instance of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>identifier</dc-element>
|
||||
<dc-qualifier>citation</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Citation</label>
|
||||
<input-type>onebox</input-type>
|
||||
<hint>Enter the standard citation for the previously issued instance of this item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>relation</dc-element>
|
||||
<dc-qualifier>ispartofseries</dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Series/Report No.</label>
|
||||
<input-type>series</input-type>
|
||||
<hint>Enter the series and number assigned to this item by your community.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>identifier</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<!-- An input-type of qualdrop_value MUST be marked as repeatable -->
|
||||
<repeatable>true</repeatable>
|
||||
<label>Identifiers</label>
|
||||
<input-type value-pairs-name="common_identifiers">qualdrop_value</input-type>
|
||||
<hint>If the item has any identification numbers or codes associated with
|
||||
it, please enter the types and the actual numbers or codes.
|
||||
</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>type</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>true</repeatable>
|
||||
<label>Type</label>
|
||||
<input-type value-pairs-name="common_types">dropdown</input-type>
|
||||
<hint>Select the type(s) of content of the item. To select more than one value in the list, you may have
|
||||
to hold down the "CTRL" or "Shift" key.
|
||||
</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>language</dc-element>
|
||||
<dc-qualifier>iso</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Language</label>
|
||||
<input-type value-pairs-name="common_iso_languages">dropdown</input-type>
|
||||
<hint>Select the language of the main content of the item. If the language does not appear in the list,
|
||||
please select 'Other'. If the content does not really have a language (for example, if it is a
|
||||
dataset or an image) please select 'N/A'.
|
||||
</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
<form name="traditionalpagetwo">
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>subject</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<!-- An input-type of twobox MUST be marked as repeatable -->
|
||||
<repeatable>true</repeatable>
|
||||
<label>Subject Keywords</label>
|
||||
<input-type>twobox</input-type>
|
||||
<hint>Enter appropriate subject keywords or phrases.</hint>
|
||||
<required></required>
|
||||
<vocabulary>srsc</vocabulary>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier>abstract</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Abstract</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter the abstract of the item.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier>sponsorship</dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Sponsors</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter the names of any sponsors and/or funding codes in the box.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
|
||||
<field>
|
||||
<dc-schema>dc</dc-schema>
|
||||
<dc-element>description</dc-element>
|
||||
<dc-qualifier></dc-qualifier>
|
||||
<repeatable>false</repeatable>
|
||||
<label>Description</label>
|
||||
<input-type>textarea</input-type>
|
||||
<hint>Enter any other description or comments in this box.</hint>
|
||||
<required></required>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
</form-definitions>
|
||||
</form-definitions>
|
||||
|
||||
|
||||
<!-- form-value-pairs populate dropdown and qualdrop-value lists. -->
|
||||
<!-- The form-value-pairs element holds child elements named 'value-pairs' -->
|
||||
<!-- A 'value-pairs' element has a value-pairs-name and a dc-term -->
|
||||
<!-- attribute. The dc-term attribute specifies which to which Dublin Core -->
|
||||
<!-- Term this set of value-pairs applies. -->
|
||||
<!-- Current dc-terms are: identifier-pairs, type-pairs, and -->
|
||||
<!-- language_iso-pairs. The name attribute matches a name -->
|
||||
<!-- in the form-map, above. -->
|
||||
<!-- A value-pair contains one 'pair' for each value displayed in the list -->
|
||||
<!-- Each pair contains a 'displayed-value' element and a 'stored-value' -->
|
||||
<!-- element. A UI list displays the displayed-values, but the program -->
|
||||
<!-- stores the associated stored-values in the database. -->
|
||||
<!-- form-value-pairs populate dropdown and qualdrop-value lists. -->
|
||||
<!-- The form-value-pairs element holds child elements named 'value-pairs' -->
|
||||
<!-- A 'value-pairs' element has a value-pairs-name and a dc-term -->
|
||||
<!-- attribute. The dc-term attribute specifies which to which Dublin Core -->
|
||||
<!-- Term this set of value-pairs applies. -->
|
||||
<!-- Current dc-terms are: identifier-pairs, type-pairs, and -->
|
||||
<!-- language_iso-pairs. The name attribute matches a name -->
|
||||
<!-- in the form-map, above. -->
|
||||
<!-- A value-pair contains one 'pair' for each value displayed in the list -->
|
||||
<!-- Each pair contains a 'displayed-value' element and a 'stored-value' -->
|
||||
<!-- element. A UI list displays the displayed-values, but the program -->
|
||||
<!-- stores the associated stored-values in the database. -->
|
||||
|
||||
<form-value-pairs>
|
||||
<value-pairs value-pairs-name="common_identifiers" dc-term="identifier">
|
||||
<pair>
|
||||
<displayed-value>ISSN</displayed-value>
|
||||
<stored-value>issn</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Other</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>ISMN</displayed-value>
|
||||
<stored-value>ismn</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Gov't Doc #</displayed-value>
|
||||
<stored-value>govdoc</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>URI</displayed-value>
|
||||
<stored-value>uri</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>ISBN</displayed-value>
|
||||
<stored-value>isbn</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
<form-value-pairs>
|
||||
<value-pairs value-pairs-name="common_identifiers" dc-term="identifier">
|
||||
<pair>
|
||||
<displayed-value>ISSN</displayed-value>
|
||||
<stored-value>issn</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Other</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>ISMN</displayed-value>
|
||||
<stored-value>ismn</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Gov't Doc #</displayed-value>
|
||||
<stored-value>govdoc</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>URI</displayed-value>
|
||||
<stored-value>uri</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>ISBN</displayed-value>
|
||||
<stored-value>isbn</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
|
||||
<value-pairs value-pairs-name="common_types" dc-term="type">
|
||||
<pair>
|
||||
<displayed-value>Animation</displayed-value>
|
||||
<stored-value>Animation</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Article</displayed-value>
|
||||
<stored-value>Article</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Book</displayed-value>
|
||||
<stored-value>Book</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Book chapter</displayed-value>
|
||||
<stored-value>Book chapter</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Dataset</displayed-value>
|
||||
<stored-value>Dataset</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Learning Object</displayed-value>
|
||||
<stored-value>Learning Object</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Image</displayed-value>
|
||||
<stored-value>Image</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Image, 3-D</displayed-value>
|
||||
<stored-value>Image, 3-D</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Map</displayed-value>
|
||||
<stored-value>Map</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Musical Score</displayed-value>
|
||||
<stored-value>Musical Score</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Plan or blueprint</displayed-value>
|
||||
<stored-value>Plan or blueprint</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Preprint</displayed-value>
|
||||
<stored-value>Preprint</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Presentation</displayed-value>
|
||||
<stored-value>Presentation</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, acoustical</displayed-value>
|
||||
<stored-value>Recording, acoustical</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, musical</displayed-value>
|
||||
<stored-value>Recording, musical</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, oral</displayed-value>
|
||||
<stored-value>Recording, oral</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Software</displayed-value>
|
||||
<stored-value>Software</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Technical Report</displayed-value>
|
||||
<stored-value>Technical Report</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Thesis</displayed-value>
|
||||
<stored-value>Thesis</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Video</displayed-value>
|
||||
<stored-value>Video</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Working Paper</displayed-value>
|
||||
<stored-value>Working Paper</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Other</displayed-value>
|
||||
<stored-value>Other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
<value-pairs value-pairs-name="common_types" dc-term="type">
|
||||
<pair>
|
||||
<displayed-value>Animation</displayed-value>
|
||||
<stored-value>Animation</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Article</displayed-value>
|
||||
<stored-value>Article</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Book</displayed-value>
|
||||
<stored-value>Book</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Book chapter</displayed-value>
|
||||
<stored-value>Book chapter</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Dataset</displayed-value>
|
||||
<stored-value>Dataset</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Learning Object</displayed-value>
|
||||
<stored-value>Learning Object</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Image</displayed-value>
|
||||
<stored-value>Image</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Image, 3-D</displayed-value>
|
||||
<stored-value>Image, 3-D</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Map</displayed-value>
|
||||
<stored-value>Map</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Musical Score</displayed-value>
|
||||
<stored-value>Musical Score</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Plan or blueprint</displayed-value>
|
||||
<stored-value>Plan or blueprint</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Preprint</displayed-value>
|
||||
<stored-value>Preprint</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Presentation</displayed-value>
|
||||
<stored-value>Presentation</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, acoustical</displayed-value>
|
||||
<stored-value>Recording, acoustical</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, musical</displayed-value>
|
||||
<stored-value>Recording, musical</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Recording, oral</displayed-value>
|
||||
<stored-value>Recording, oral</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Software</displayed-value>
|
||||
<stored-value>Software</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Technical Report</displayed-value>
|
||||
<stored-value>Technical Report</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Thesis</displayed-value>
|
||||
<stored-value>Thesis</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Video</displayed-value>
|
||||
<stored-value>Video</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Working Paper</displayed-value>
|
||||
<stored-value>Working Paper</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Other</displayed-value>
|
||||
<stored-value>Other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
|
||||
<!-- default language order: (from dspace 1.2.1)
|
||||
"en_US", "en", "es", "de", "fr", "it", "ja", "zh", "other", ""
|
||||
-->
|
||||
<value-pairs value-pairs-name="common_iso_languages" dc-term="language_iso">
|
||||
<pair>
|
||||
<displayed-value>N/A</displayed-value>
|
||||
<stored-value></stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>English (United States)</displayed-value>
|
||||
<stored-value>en_US</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>English</displayed-value>
|
||||
<stored-value>en</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Spanish</displayed-value>
|
||||
<stored-value>es</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>German</displayed-value>
|
||||
<stored-value>de</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>French</displayed-value>
|
||||
<stored-value>fr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Italian</displayed-value>
|
||||
<stored-value>it</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Japanese</displayed-value>
|
||||
<stored-value>ja</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Chinese</displayed-value>
|
||||
<stored-value>zh</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Turkish</displayed-value>
|
||||
<stored-value>tr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>(Other)</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
<!-- default language order: (from dspace 1.2.1)
|
||||
"en_US", "en", "es", "de", "fr", "it", "ja", "zh", "other", ""
|
||||
-->
|
||||
<value-pairs value-pairs-name="common_iso_languages" dc-term="language_iso">
|
||||
<pair>
|
||||
<displayed-value>N/A</displayed-value>
|
||||
<stored-value></stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>English (United States)</displayed-value>
|
||||
<stored-value>en_US</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>English</displayed-value>
|
||||
<stored-value>en</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Spanish</displayed-value>
|
||||
<stored-value>es</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>German</displayed-value>
|
||||
<stored-value>de</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>French</displayed-value>
|
||||
<stored-value>fr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Italian</displayed-value>
|
||||
<stored-value>it</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Japanese</displayed-value>
|
||||
<stored-value>ja</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Chinese</displayed-value>
|
||||
<stored-value>zh</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>Turkish</displayed-value>
|
||||
<stored-value>tr</stored-value>
|
||||
</pair>
|
||||
<pair>
|
||||
<displayed-value>(Other)</displayed-value>
|
||||
<stored-value>other</stored-value>
|
||||
</pair>
|
||||
</value-pairs>
|
||||
|
||||
</form-value-pairs>
|
||||
</form-value-pairs>
|
||||
|
||||
</input-forms>
|
||||
|
@@ -10,20 +10,29 @@ package org.dspace.statistics.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Principal;
|
||||
import java.util.Collections;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.servlet.AsyncContext;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpUpgradeHandler;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.dspace.core.Utils;
|
||||
@@ -54,6 +63,15 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
this.remoteHost = host;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#changeSessionId
|
||||
*/
|
||||
@Override
|
||||
public String changeSessionId() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#getAuthType()
|
||||
*/
|
||||
@@ -99,6 +117,15 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
List<String> values = headers.computeIfAbsent(headerName, k -> new LinkedList<>());
|
||||
values.add(headerValue);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#getDispatcherType()
|
||||
*/
|
||||
@Override
|
||||
public DispatcherType getDispatcherType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
|
||||
*/
|
||||
@@ -270,6 +297,55 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public boolean authenticate(HttpServletResponse httpServletResponse) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#login(java.lang.String,java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void login(String s, String s1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#logout()
|
||||
*/
|
||||
@Override
|
||||
public void logout() {
|
||||
return;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Part getPart(String arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#getParts()
|
||||
*/
|
||||
@Override
|
||||
public Collection<Part> getParts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#upgrade(java.lang.Class<T>)
|
||||
*/
|
||||
@Override
|
||||
public <T extends HttpUpgradeHandler> T upgrade(Class<T> aClass) throws IOException, ServletException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
|
||||
*/
|
||||
@@ -324,6 +400,14 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#getContentLengthLong()
|
||||
*/
|
||||
@Override
|
||||
public long getContentLengthLong() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#getContentType()
|
||||
*/
|
||||
@@ -505,10 +589,51 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
*/
|
||||
@Override
|
||||
public void setCharacterEncoding(String arg0)
|
||||
throws UnsupportedEncodingException {
|
||||
throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#startAsync
|
||||
*/
|
||||
@Override
|
||||
public AsyncContext startAsync() throws IllegalStateException {
|
||||
throw new IllegalStateException("Not supported yet.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#startAsync(javax.servlet.ServletRequest,javax.servlet.ServletResponse)
|
||||
*/
|
||||
@Override
|
||||
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
|
||||
throws IllegalStateException {
|
||||
throw new IllegalStateException("Not supported yet.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#isAsyncStarted
|
||||
*/
|
||||
@Override
|
||||
public boolean isAsyncStarted() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#isAsyncSupported
|
||||
*/
|
||||
@Override
|
||||
public boolean isAsyncSupported() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#getAsyncContext
|
||||
*/
|
||||
@Override
|
||||
public AsyncContext getAsyncContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRemotePort() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
@@ -529,4 +654,12 @@ public class DummyHttpServletRequest implements HttpServletRequest {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.ServletRequest#getServletContext
|
||||
*/
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -16,7 +16,6 @@
|
||||
<properties>
|
||||
<!-- This is the path to the root [dspace-src] directory. -->
|
||||
<root.basedir>${basedir}/..</root.basedir>
|
||||
<spring.version>3.2.5.RELEASE</spring.version>
|
||||
<xoai.version>3.2.10</xoai.version>
|
||||
<jtwig.version>2.0.1</jtwig.version>
|
||||
</properties>
|
||||
@@ -144,10 +143,6 @@
|
||||
<artifactId>jtwig-spring</artifactId>
|
||||
<version>${jtwig.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
@@ -160,6 +155,10 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
@@ -185,7 +184,7 @@
|
||||
<!-- Web API -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -224,10 +223,12 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Note: XOAI requires hamcrest both for testing and runtime -->
|
||||
<!-- As our Parent POM sets this to 'test' scope, we must override it -->
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-all</artifactId>
|
||||
<scope>test</scope>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
|
@@ -8,9 +8,9 @@
|
||||
http://www.dspace.org/license/
|
||||
|
||||
-->
|
||||
<web-app id="XOAILynCode" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
|
||||
<web-app id="DSpace-OAI" version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
|
||||
|
||||
<display-name>XOAI Data Provider</display-name>
|
||||
|
||||
|
@@ -64,7 +64,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -8,10 +8,9 @@
|
||||
http://www.dspace.org/license/
|
||||
|
||||
-->
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
id="WebApp_ID" version="2.5">
|
||||
<web-app id="DSpace-RDF" version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
|
||||
|
||||
<display-name>RDF Data Provider</display-name>
|
||||
|
||||
|
@@ -220,7 +220,6 @@
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -8,10 +8,9 @@
|
||||
http://www.dspace.org/license/
|
||||
|
||||
-->
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
id="WebApp_ID" version="2.5">
|
||||
<web-app id="DSpace-RESTv6" version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
|
||||
|
||||
<filter>
|
||||
<filter-name>dspace.request</filter-name>
|
||||
@@ -109,4 +108,4 @@
|
||||
</listener>
|
||||
|
||||
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
@@ -108,7 +108,7 @@
|
||||
<!-- for filters -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -12,7 +12,9 @@ import javax.mail.Authenticator;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
import javax.naming.InitialContext;
|
||||
import javax.naming.NameNotFoundException;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.NoInitialContextException;
|
||||
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
@@ -33,7 +35,7 @@ import org.springframework.beans.factory.annotation.Required;
|
||||
public class EmailServiceImpl
|
||||
extends Authenticator
|
||||
implements EmailService, InitializedService {
|
||||
private static final Logger logger = (Logger) LoggerFactory.getLogger(EmailServiceImpl.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmailServiceImpl.class);
|
||||
|
||||
private Session session = null;
|
||||
|
||||
@@ -53,7 +55,7 @@ public class EmailServiceImpl
|
||||
/**
|
||||
* Provide a reference to the JavaMail session.
|
||||
*
|
||||
* @return the managed Session, or null if none could be created.
|
||||
* @return the managed Session, or {@code null} if none could be created.
|
||||
*/
|
||||
@Override
|
||||
public Session getSession() {
|
||||
@@ -67,12 +69,16 @@ public class EmailServiceImpl
|
||||
if (null == sessionName) {
|
||||
sessionName = "Session";
|
||||
}
|
||||
String sessionUri = "java:comp/env/mail/" + sessionName;
|
||||
logger.debug("Looking up Session as {}", sessionUri);
|
||||
try {
|
||||
InitialContext ctx = new InitialContext(null);
|
||||
session = (Session) ctx.lookup("java:comp/env/mail/" + sessionName);
|
||||
session = (Session) ctx.lookup(sessionUri);
|
||||
} catch (NameNotFoundException | NoInitialContextException ex) {
|
||||
// Not a problem -- build a new Session from configuration.
|
||||
} catch (NamingException ex) {
|
||||
logger.warn("Couldn't get an email session from environment: {}",
|
||||
ex.getMessage());
|
||||
logger.warn("Couldn't get an email session from environment: {}: {}",
|
||||
ex.getClass().getName(), ex.getMessage());
|
||||
}
|
||||
|
||||
if (null != session) {
|
||||
@@ -106,8 +112,6 @@ public class EmailServiceImpl
|
||||
props.put("mail.smtp.auth", "true");
|
||||
session = Session.getInstance(props, this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -249,7 +249,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -27,6 +27,7 @@ import org.dspace.content.BitstreamFormat;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.disseminate.service.CitationDocumentService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.EventService;
|
||||
import org.dspace.usage.UsageEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -70,6 +71,9 @@ public class BitstreamContentRestController {
|
||||
@Autowired
|
||||
private CitationDocumentService citationDocumentService;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@PreAuthorize("hasPermission(#uuid, 'BITSTREAM', 'READ')")
|
||||
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
|
||||
public void retrieve(@PathVariable UUID uuid, HttpServletResponse response,
|
||||
@@ -104,6 +108,12 @@ public class BitstreamContentRestController {
|
||||
.with(request)
|
||||
.with(response);
|
||||
|
||||
//Determine if we need to send the file as a download or if the browser can open it inline
|
||||
long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold");
|
||||
if (dispositionThreshold >= 0 && bitstreamTuple.getRight() > dispositionThreshold) {
|
||||
sender.withDisposition(MultipartFileSender.CONTENT_DISPOSITION_ATTACHMENT);
|
||||
}
|
||||
|
||||
if (sender.isNoRangeRequest() && isNotAnErrorResponse(response)) {
|
||||
//We only log a download request when serving a request without Range header. This is because
|
||||
//a browser always sends a regular request first to check for Range support.
|
||||
|
@@ -142,7 +142,8 @@ public class DiscoveryRestController implements InitializingBean {
|
||||
}
|
||||
|
||||
//Get the Search results in JSON format
|
||||
SearchResultsRest searchResultsRest = discoveryRestRepository
|
||||
SearchResultsRest searchResultsRest = null;
|
||||
searchResultsRest = discoveryRestRepository
|
||||
.getSearchObjects(query, dsoType, dsoScope, configurationName, searchFilters, page);
|
||||
|
||||
//Convert the Search JSON results to paginated HAL resources
|
||||
|
@@ -10,18 +10,22 @@ package org.dspace.app.rest;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
@@ -46,6 +50,7 @@ import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||
import org.dspace.app.rest.repository.LinkRestRepository;
|
||||
import org.dspace.app.rest.utils.RestRepositoryUtils;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -60,6 +65,7 @@ import org.springframework.hateoas.Link;
|
||||
import org.springframework.hateoas.PagedResources;
|
||||
import org.springframework.hateoas.Resource;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.hateoas.Resources;
|
||||
import org.springframework.hateoas.UriTemplate;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -426,17 +432,21 @@ public class RestResourceController implements InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in POST, multipart, upload a resource passed into "file" request parameter
|
||||
* Called in POST, multipart, upload to a specific rest resource the file passed as "file" request parameter
|
||||
*
|
||||
* Note that the regular expression in the request mapping accept a number as identifier;
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* the api category
|
||||
* @param model
|
||||
* the rest model that identify the REST resource collection
|
||||
* @param id
|
||||
* @param extraField
|
||||
* the id of the specific rest resource
|
||||
* @param uploadfile
|
||||
* @return
|
||||
* the file to upload
|
||||
* @return the created resource
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.POST, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT, headers =
|
||||
@@ -445,26 +455,28 @@ public class RestResourceController implements InitializingBean {
|
||||
@PathVariable String apiCategory,
|
||||
@PathVariable String model,
|
||||
@PathVariable Integer id,
|
||||
@RequestParam(required = false, value =
|
||||
"extraField") String extraField,
|
||||
@RequestParam("file") MultipartFile
|
||||
uploadfile)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
return uploadInternal(request, apiCategory, model, id, extraField, uploadfile);
|
||||
return uploadInternal(request, apiCategory, model, id, uploadfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in POST, multipart, upload a resource passed into "file" request parameter
|
||||
* Called in POST, multipart, upload to a specific rest resource the file passed as "file" request parameter
|
||||
*
|
||||
* Note that the regular expression in the request mapping accept a UUID as identifier;
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* the api category
|
||||
* @param model
|
||||
* the rest model that identify the REST resource collection
|
||||
* @param id
|
||||
* @param extraField
|
||||
* the id of the specific rest resource
|
||||
* @param uploadfile
|
||||
* @return
|
||||
* the file to upload
|
||||
* @return the created resource
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
*/
|
||||
@RequestMapping(method = RequestMethod.POST, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID, headers =
|
||||
@@ -473,12 +485,10 @@ public class RestResourceController implements InitializingBean {
|
||||
@PathVariable String apiCategory,
|
||||
@PathVariable String model,
|
||||
@PathVariable UUID id,
|
||||
@RequestParam(required = false, value =
|
||||
"extraField") String extraField,
|
||||
@RequestParam("file") MultipartFile
|
||||
uploadfile)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
return uploadInternal(request, apiCategory, model, id, extraField, uploadfile);
|
||||
return uploadInternal(request, apiCategory, model, id, uploadfile);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -488,21 +498,19 @@ public class RestResourceController implements InitializingBean {
|
||||
* @param apiCategory
|
||||
* @param model
|
||||
* @param id
|
||||
* @param extraField
|
||||
* @param uploadfile
|
||||
* @return
|
||||
*/
|
||||
private <ID extends Serializable> ResponseEntity<ResourceSupport> uploadInternal(HttpServletRequest request,
|
||||
String apiCategory, String model,
|
||||
ID id,
|
||||
String extraField,
|
||||
MultipartFile uploadfile) {
|
||||
checkModelPluralForm(apiCategory, model);
|
||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
|
||||
RestAddressableModel modelObject = null;
|
||||
try {
|
||||
modelObject = repository.upload(request, apiCategory, model, id, extraField, uploadfile);
|
||||
modelObject = repository.upload(request, apiCategory, model, id, uploadfile);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return ControllerUtils.toEmptyResponse(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
@@ -512,6 +520,46 @@ public class RestResourceController implements InitializingBean {
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file against the collection resource endpoint. This is typically used for bulk creation of resources
|
||||
* such for instance multiple workspaceitems from a CSV or bibliographic file
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* the api category
|
||||
* @param model
|
||||
* the rest model that identify the REST resource collection
|
||||
* @param uploadfile
|
||||
* the bulk file
|
||||
* @return the list of generated resources
|
||||
* @throws SQLException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@RequestMapping(method = { RequestMethod.POST }, headers = "content-type=multipart/form-data")
|
||||
public <T extends RestAddressableModel> ResponseEntity<ResourceSupport> upload(HttpServletRequest request,
|
||||
@PathVariable String apiCategory,
|
||||
@PathVariable String model,
|
||||
@RequestParam("file") MultipartFile
|
||||
uploadfile)
|
||||
throws SQLException, FileNotFoundException, IOException, AuthorizeException {
|
||||
|
||||
checkModelPluralForm(apiCategory, model);
|
||||
DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model);
|
||||
|
||||
Iterable<T> content = repository.upload(request, uploadfile);
|
||||
|
||||
List<DSpaceResource> resources = new ArrayList<>();
|
||||
for (T modelObject : content) {
|
||||
DSpaceResource result = repository.wrapResource(modelObject);
|
||||
linkService.addLinks(result);
|
||||
resources.add(result);
|
||||
}
|
||||
return ControllerUtils.toResponseEntity(HttpStatus.OK, null, Resources.wrap(resources));
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH method, using operation on the resources following (JSON) Patch notation (https://tools.ietf
|
||||
* .org/html/rfc6902)
|
||||
@@ -573,7 +621,6 @@ public class RestResourceController implements InitializingBean {
|
||||
String model, ID id,
|
||||
JsonNode jsonNode)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
|
||||
checkModelPluralForm(apiCategory, model);
|
||||
DSpaceRestRepository<RestAddressableModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||
RestAddressableModel modelObject = null;
|
||||
@@ -736,8 +783,9 @@ public class RestResourceController implements InitializingBean {
|
||||
EmbeddedPage ep = (EmbeddedPage) resource.getEmbeddedResources().get(rel);
|
||||
List<? extends RestAddressableModel> fullList = ep.getFullList();
|
||||
if (fullList == null || fullList.size() == 0) {
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
return null;
|
||||
PageImpl<RestAddressableModel> pageResult = new PageImpl(fullList, page, 0);
|
||||
result = assembler.toResource(pageResult);
|
||||
return result;
|
||||
}
|
||||
int start = page.getOffset();
|
||||
int end = (start + page.getPageSize()) > fullList.size() ? fullList.size() : (start + page.getPageSize());
|
||||
@@ -759,7 +807,6 @@ public class RestResourceController implements InitializingBean {
|
||||
if (resource.getEmbeddedResources().get(rel) == null) {
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
return (ResourceSupport) resource.getEmbeddedResources().get(rel);
|
||||
}
|
||||
|
||||
|
@@ -17,8 +17,10 @@ import org.dspace.app.rest.model.ScopeEnum;
|
||||
import org.dspace.app.rest.model.SubmissionFormFieldRest;
|
||||
import org.dspace.app.rest.model.SubmissionFormInputTypeRest;
|
||||
import org.dspace.app.rest.model.SubmissionFormRest;
|
||||
import org.dspace.app.rest.model.SubmissionFormRowRest;
|
||||
import org.dspace.app.rest.model.SubmissionVisibilityRest;
|
||||
import org.dspace.app.rest.model.VisibilityEnum;
|
||||
import org.dspace.app.rest.repository.SubmissionFormRestRepository;
|
||||
import org.dspace.app.rest.utils.AuthorityUtils;
|
||||
import org.dspace.app.util.DCInput;
|
||||
import org.dspace.app.util.DCInputSet;
|
||||
@@ -44,30 +46,41 @@ public class SubmissionFormConverter extends DSpaceConverter<DCInputSet, Submiss
|
||||
@Autowired
|
||||
private AuthorityUtils authorityUtils;
|
||||
|
||||
@Autowired
|
||||
private SubmissionFormRestRepository submissionFormRestRepository;
|
||||
|
||||
@Override
|
||||
public SubmissionFormRest fromModel(DCInputSet obj) {
|
||||
SubmissionFormRest sd = new SubmissionFormRest();
|
||||
sd.setName(obj.getFormName());
|
||||
DCInput[] step = obj.getFields();
|
||||
List<SubmissionFormFieldRest> fields = getPage(step);
|
||||
sd.setFields(fields);
|
||||
DCInput[][] step = obj.getFields();
|
||||
List<SubmissionFormRowRest> rows = getPage(step, obj.getFormName());
|
||||
sd.setRows(rows);
|
||||
return sd;
|
||||
}
|
||||
|
||||
private List<SubmissionFormFieldRest> getPage(DCInput[] page) {
|
||||
List<SubmissionFormFieldRest> fields = new LinkedList<SubmissionFormFieldRest>();
|
||||
for (DCInput dcinput : page) {
|
||||
fields.add(getField(dcinput));
|
||||
private List<SubmissionFormRowRest> getPage(DCInput[][] page, String formName) {
|
||||
List<SubmissionFormRowRest> rows = new LinkedList<SubmissionFormRowRest>();
|
||||
|
||||
for (DCInput[] row : page) {
|
||||
List<SubmissionFormFieldRest> fields = new LinkedList<SubmissionFormFieldRest>();
|
||||
SubmissionFormRowRest rowRest = new SubmissionFormRowRest();
|
||||
rowRest.setFields(fields);
|
||||
rows.add(rowRest);
|
||||
for (DCInput dcinput : row) {
|
||||
fields.add(getField(dcinput, formName));
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
return rows;
|
||||
}
|
||||
|
||||
private SubmissionFormFieldRest getField(DCInput dcinput) {
|
||||
private SubmissionFormFieldRest getField(DCInput dcinput, String formName) {
|
||||
SubmissionFormFieldRest inputField = new SubmissionFormFieldRest();
|
||||
List<SelectableMetadata> selectableMetadata = new ArrayList<SelectableMetadata>();
|
||||
|
||||
inputField.setLabel(dcinput.getLabel());
|
||||
inputField.setHints(dcinput.getHints());
|
||||
inputField.setStyle(dcinput.getStyle());
|
||||
inputField.setMandatoryMessage(dcinput.getWarning());
|
||||
inputField.setMandatory(dcinput.isRequired());
|
||||
inputField.setScope(ScopeEnum.fromString(dcinput.getScope()));
|
||||
@@ -99,17 +112,16 @@ public class SubmissionFormConverter extends DSpaceConverter<DCInputSet, Submiss
|
||||
SelectableMetadata selMd = new SelectableMetadata();
|
||||
if (authorityUtils.isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier())) {
|
||||
inputRest.setType(
|
||||
getPresentation(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(), inputType));
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
dcinput.getQualifier(), dcinput.getPairsType(),
|
||||
dcinput.getVocabulary()));
|
||||
getPresentation(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(), inputType));
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(),
|
||||
dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||
selMd.setClosed(
|
||||
authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier()));
|
||||
authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier()));
|
||||
} else {
|
||||
inputRest.setType(inputType);
|
||||
}
|
||||
selMd.setMetadata(org.dspace.core.Utils
|
||||
.standardize(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(), "."));
|
||||
.standardize(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier(), "."));
|
||||
selectableMetadata.add(selMd);
|
||||
|
||||
} else {
|
||||
@@ -119,11 +131,10 @@ public class SubmissionFormConverter extends DSpaceConverter<DCInputSet, Submiss
|
||||
SelectableMetadata selMd = new SelectableMetadata();
|
||||
selMd.setLabel((String) pairs.get(idx));
|
||||
selMd.setMetadata(org.dspace.core.Utils
|
||||
.standardize(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1), "."));
|
||||
.standardize(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1), "."));
|
||||
if (authorityUtils.isChoice(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier())) {
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(),
|
||||
pairs.get(idx + 1), dcinput.getPairsType(),
|
||||
dcinput.getVocabulary()));
|
||||
selMd.setAuthority(getAuthorityName(dcinput.getSchema(), dcinput.getElement(), pairs.get(idx + 1),
|
||||
dcinput.getPairsType(), dcinput.getVocabulary()));
|
||||
selMd.setClosed(
|
||||
authorityUtils.isClosed(dcinput.getSchema(), dcinput.getElement(), dcinput.getQualifier()));
|
||||
}
|
||||
@@ -160,12 +171,11 @@ public class SubmissionFormConverter extends DSpaceConverter<DCInputSet, Submiss
|
||||
} else if (StringUtils.isNotBlank(vocabularyName)) {
|
||||
return vocabularyName;
|
||||
}
|
||||
return authorityUtils.getAuthorityName(schema, element,
|
||||
qualifier);
|
||||
return authorityUtils.getAuthorityName(schema, element, qualifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DCInputSet toModel(SubmissionFormRest obj) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -24,7 +24,6 @@ import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -86,6 +85,10 @@ public class WorkspaceItemConverter
|
||||
// info
|
||||
|
||||
if (collection != null) {
|
||||
// we set the status to true as we will discover validation error later in this block
|
||||
// we could eventually leave the status to empty if we don't have collection information, this could be
|
||||
// eventually the case when projection support will be included
|
||||
witem.setStatus(true);
|
||||
SubmissionDefinitionRest def = submissionDefinitionConverter
|
||||
.convert(submissionConfigReader.getSubmissionConfigByCollection(collection.getHandle()));
|
||||
witem.setSubmissionDefinition(def);
|
||||
@@ -103,22 +106,21 @@ public class WorkspaceItemConverter
|
||||
|
||||
Object stepInstance = stepClass.newInstance();
|
||||
|
||||
if (stepInstance instanceof AbstractProcessingStep) {
|
||||
if (stepInstance instanceof AbstractRestProcessingStep) {
|
||||
// load the interface for this step
|
||||
AbstractRestProcessingStep stepProcessing = (AbstractRestProcessingStep) stepClass
|
||||
.newInstance();
|
||||
AbstractRestProcessingStep stepProcessing =
|
||||
(AbstractRestProcessingStep) stepClass.newInstance();
|
||||
for (ErrorRest error : stepProcessing.validate(submissionService, obj, stepConfig)) {
|
||||
addError(witem.getErrors(), error);
|
||||
witem.setStatus(false);
|
||||
}
|
||||
witem.getSections()
|
||||
.put(sections.getId(), stepProcessing.getData(submissionService, obj, stepConfig));
|
||||
.put(sections.getId(), stepProcessing.getData(submissionService, obj, stepConfig));
|
||||
} else {
|
||||
throw new Exception("The submission step class specified by '"
|
||||
+ stepConfig.getProcessingClassName()
|
||||
+ "' does not extend the class org.dspace.app.rest.submit" +
|
||||
".AbstractRestProcessingStep!"
|
||||
+ " Therefore it cannot be used by the Configurable Submission as the" +
|
||||
" <processing-class>!");
|
||||
log.warn("The submission step class specified by '" + stepConfig.getProcessingClassName() +
|
||||
"' does not extend the class org.dspace.app.rest.submit.AbstractRestProcessingStep!" +
|
||||
" Therefore it cannot be used by the Configurable Submission as the " +
|
||||
"<processing-class>!");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@@ -38,6 +38,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionHandler {
|
||||
|
||||
@Autowired
|
||||
private RestAuthenticationService restAuthenticationService;
|
||||
|
||||
@@ -51,6 +52,12 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
|
||||
}
|
||||
}
|
||||
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
protected void handleIllegalArgumentException(HttpServletRequest request, HttpServletResponse response,
|
||||
Exception ex) throws IOException {
|
||||
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_BAD_REQUEST);
|
||||
}
|
||||
|
||||
@ExceptionHandler(SQLException.class)
|
||||
protected void handleSQLException(HttpServletRequest request, HttpServletResponse response, Exception ex)
|
||||
throws IOException {
|
||||
|
@@ -28,6 +28,13 @@ public abstract class BaseObjectRest<T extends Serializable> implements Identifi
|
||||
@JsonInclude(Include.NON_EMPTY)
|
||||
private List<ErrorRest> errors;
|
||||
|
||||
private Boolean status;
|
||||
|
||||
@JsonInclude(Include.NON_NULL)
|
||||
public Boolean isStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getId() {
|
||||
return id;
|
||||
@@ -48,4 +55,7 @@ public abstract class BaseObjectRest<T extends Serializable> implements Identifi
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public void setStatus(Boolean status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.rest.model;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* The Community REST Resource
|
||||
@@ -61,6 +62,7 @@ public class CommunityRest extends DSpaceObjectRest {
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
public String getType() {
|
||||
return NAME;
|
||||
}
|
||||
|
@@ -21,6 +21,11 @@ public class ErrorRest {
|
||||
|
||||
private List<String> paths;
|
||||
|
||||
/**
|
||||
* The error message as i18key
|
||||
*
|
||||
* @return The message as i18key
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
@@ -29,6 +34,13 @@ public class ErrorRest {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* The json paths where the error message apply. They can be as detailed as a specific value in a multivalues
|
||||
* attributes (i.e. sections.traditionalpageone['dc.contributor.author'][1] to identify the second author - 0 based)
|
||||
* or generic to apply to a whole section (sections.license)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<String> getPaths() {
|
||||
if (this.paths == null) {
|
||||
this.paths = new ArrayList<String>();
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.rest.model;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
@@ -17,6 +18,7 @@ import org.dspace.app.rest.RestResourceController;
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class GroupRest extends DSpaceObjectRest {
|
||||
public static final String NAME = "group";
|
||||
|
||||
@@ -69,4 +71,4 @@ public class GroupRest extends DSpaceObjectRest {
|
||||
public Class getController() {
|
||||
return RestResourceController.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ package org.dspace.app.rest.model;
|
||||
|
||||
/**
|
||||
* The possible restriction options for the scope attributes in the
|
||||
* SubmissionPanel resource and InputFormPage resource
|
||||
* SubmissionPanel resource and SubmissionForm's fields
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
|
@@ -17,74 +17,194 @@ import org.dspace.submit.model.LanguageFormField;
|
||||
import org.dspace.submit.model.SelectableMetadata;
|
||||
|
||||
/**
|
||||
* The InputFormField REST Resource. It is not addressable directly, only used
|
||||
* The SubmissionFormField REST Resource. It is not addressable directly, only used
|
||||
* as inline object in the InputForm resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@JsonInclude(value = Include.NON_NULL)
|
||||
public class SubmissionFormFieldRest {
|
||||
|
||||
/**
|
||||
* The SubmissionFormInputType for this field
|
||||
*/
|
||||
private SubmissionFormInputTypeRest input;
|
||||
|
||||
/**
|
||||
* The main scope of the field
|
||||
*/
|
||||
private ScopeEnum scope;
|
||||
|
||||
/**
|
||||
* The visibility restriction for the field
|
||||
*/
|
||||
private SubmissionVisibilityRest visibility;
|
||||
|
||||
/**
|
||||
* The label of the field
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* <code>true</code> if the field is required
|
||||
*/
|
||||
private boolean mandatory;
|
||||
|
||||
/**
|
||||
* <code>true</code> if the field allows multiple value
|
||||
*/
|
||||
private boolean repeatable;
|
||||
|
||||
/**
|
||||
* The message to return if the information is missing
|
||||
*/
|
||||
private String mandatoryMessage;
|
||||
|
||||
/**
|
||||
* A text to help field input
|
||||
*/
|
||||
private String hints;
|
||||
|
||||
/**
|
||||
* Extra information to be used by the UI to customize the presentation of the field. The format is dependent from
|
||||
* the UI implementation, the default Angular UI expects whitespace separated CSS class to add to the field
|
||||
*/
|
||||
private String style;
|
||||
|
||||
/**
|
||||
* The list of metadata, often a single element, to offer for the storage of the information. This map the DSpace <
|
||||
* 7 concepts of qualdrop
|
||||
*/
|
||||
private List<SelectableMetadata> selectableMetadata;
|
||||
|
||||
/**
|
||||
* The list of language that can be used to fill the field
|
||||
*/
|
||||
private List<LanguageFormField> languageCodes;
|
||||
|
||||
/**
|
||||
* Getter for {@link #selectableMetadata}
|
||||
*
|
||||
* @return {@link #selectableMetadata}
|
||||
*/
|
||||
public List<SelectableMetadata> getSelectableMetadata() {
|
||||
return selectableMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #selectableMetadata}
|
||||
*
|
||||
*/
|
||||
public void setSelectableMetadata(List<SelectableMetadata> selectableMetadata) {
|
||||
this.selectableMetadata = selectableMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #label}
|
||||
*
|
||||
* @return {@link #label}
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #label}
|
||||
*
|
||||
*/
|
||||
public void setLabel(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #mandatory}
|
||||
*
|
||||
* @return {@link #mandatory}
|
||||
*/
|
||||
public boolean isMandatory() {
|
||||
return mandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #mandatory}
|
||||
*
|
||||
*/
|
||||
public void setMandatory(boolean mandatory) {
|
||||
this.mandatory = mandatory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #repeatable}
|
||||
*
|
||||
* @return {@link #repeatable}
|
||||
*/
|
||||
public boolean isRepeatable() {
|
||||
return repeatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #repeatable}
|
||||
*
|
||||
*/
|
||||
public void setRepeatable(boolean repeatable) {
|
||||
this.repeatable = repeatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #mandatoryMessage}
|
||||
*
|
||||
* @return {@link #mandatoryMessage}
|
||||
*/
|
||||
public String getMandatoryMessage() {
|
||||
return mandatoryMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #mandatoryMessage}
|
||||
*
|
||||
*/
|
||||
public void setMandatoryMessage(String mandatoryMessage) {
|
||||
this.mandatoryMessage = mandatoryMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #hints}
|
||||
*
|
||||
* @return {@link #hints}
|
||||
*/
|
||||
public String getHints() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #hints}
|
||||
*
|
||||
*/
|
||||
public void setHints(String hints) {
|
||||
this.hints = hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #style}
|
||||
*
|
||||
* @return {@link #style}
|
||||
*/
|
||||
public String getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #style}
|
||||
*
|
||||
*/
|
||||
public void setStyle(String style) {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #languageCodes}
|
||||
*
|
||||
* @return {@link #languageCodes}
|
||||
*/
|
||||
public List<LanguageFormField> getLanguageCodes() {
|
||||
if (languageCodes == null) {
|
||||
languageCodes = new ArrayList<LanguageFormField>();
|
||||
@@ -92,22 +212,44 @@ public class SubmissionFormFieldRest {
|
||||
return languageCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #languageCodes}
|
||||
*
|
||||
*/
|
||||
public void setLanguageCodes(List<LanguageFormField> languageCodes) {
|
||||
this.languageCodes = languageCodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #input}
|
||||
*
|
||||
* @return {@link #input}
|
||||
*/
|
||||
public SubmissionFormInputTypeRest getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #input}
|
||||
*
|
||||
*/
|
||||
public void setInput(SubmissionFormInputTypeRest input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #scope}
|
||||
*
|
||||
* @return {@link #selectableMetadata}
|
||||
*/
|
||||
public ScopeEnum getScope() {
|
||||
return scope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #scope}
|
||||
*
|
||||
*/
|
||||
public void setScope(ScopeEnum scope) {
|
||||
this.scope = scope;
|
||||
}
|
||||
@@ -121,4 +263,5 @@ public class SubmissionFormFieldRest {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
|
||||
/**
|
||||
* The InputFormField REST Resource. It is not addressable directly, only used
|
||||
* The SubmissionFormInputType REST Resource. It is not addressable directly, only used
|
||||
* as inline object in the InputForm resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
|
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
import org.dspace.app.rest.RestResourceController;
|
||||
|
||||
/**
|
||||
* The Input Form REST Resource
|
||||
* The Submission Form REST Resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@@ -21,19 +21,37 @@ public class SubmissionFormRest extends BaseObjectRest<String> {
|
||||
public static final String NAME_LINK_ON_PANEL = RestAddressableModel.CONFIGURATION;
|
||||
public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
|
||||
|
||||
/**
|
||||
* An unique name identifying the submission form
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private List<SubmissionFormFieldRest> fields;
|
||||
/**
|
||||
* The list of row in the submission form
|
||||
*/
|
||||
private List<SubmissionFormRowRest> rows;
|
||||
|
||||
@Override
|
||||
/**
|
||||
* The id of the submission form is its name
|
||||
*/
|
||||
public String getId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #name}
|
||||
*
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for {@link #name}
|
||||
*
|
||||
* @return {@link #name}
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -53,11 +71,20 @@ public class SubmissionFormRest extends BaseObjectRest<String> {
|
||||
return CATEGORY;
|
||||
}
|
||||
|
||||
public List<SubmissionFormFieldRest> getFields() {
|
||||
return fields;
|
||||
/**
|
||||
* Getter for {@link #rows}
|
||||
*
|
||||
* @return {@link #rows}
|
||||
*/
|
||||
public List<SubmissionFormRowRest> getRows() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public void setFields(List<SubmissionFormFieldRest> fields) {
|
||||
this.fields = fields;
|
||||
/**
|
||||
* Setter for {@link #rows}
|
||||
*
|
||||
*/
|
||||
public void setRows(List<SubmissionFormRowRest> rows) {
|
||||
this.rows = rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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.app.rest.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The InputFormRow REST Resource. It is not addressable directly, only used
|
||||
* as inline object in the InputForm resource
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class SubmissionFormRowRest {
|
||||
/**
|
||||
* The list of fields in the row
|
||||
*/
|
||||
private List<SubmissionFormFieldRest> fields;
|
||||
|
||||
/**
|
||||
* Getter for {@link #fields}
|
||||
*
|
||||
* @return {@link #fields}
|
||||
*/
|
||||
public List<SubmissionFormFieldRest> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link #fields}
|
||||
*
|
||||
*/
|
||||
public void setFields(List<SubmissionFormFieldRest> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
|
@@ -12,13 +12,19 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The SubmissionVisibility REST Resource. It is not addressable directly, only
|
||||
* used as inline object in the SubmissionPanel resource and InputFormPage
|
||||
* resource
|
||||
* used as inline object in the SubmissionPanel resource and SubmissionForm's fields
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class SubmissionVisibilityRest {
|
||||
/**
|
||||
* The visibility to apply within the main scope
|
||||
*/
|
||||
private VisibilityEnum main;
|
||||
|
||||
/**
|
||||
* The visibility to apply outside the main scope
|
||||
*/
|
||||
private VisibilityEnum other;
|
||||
|
||||
public SubmissionVisibilityRest(VisibilityEnum main, VisibilityEnum other) {
|
||||
|
@@ -10,7 +10,7 @@ package org.dspace.app.rest.model;
|
||||
|
||||
/**
|
||||
* The possible restriction options for the visibility attributes in the
|
||||
* SubmissionPanel resource and InputFormPage resource
|
||||
* SubmissionPanel resource and SubmissionForm's fields
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
|
@@ -129,7 +129,9 @@ public abstract class DSpaceResource<T extends RestAddressableModel> extends HAL
|
||||
page.map(resourceRepository::wrapResource),
|
||||
linkedRMList, name);
|
||||
} else {
|
||||
wrapObject = null;
|
||||
PageImpl<RestAddressableModel> page = new PageImpl(linkedRMList);
|
||||
wrapObject = new EmbeddedPage(linkToSubResource.getHref(), page,
|
||||
linkedRMList, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,16 +7,24 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.ServletInputStream;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.CommunityConverter;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.CommunityRest;
|
||||
import org.dspace.app.rest.model.MetadataEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.CommunityResource;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.core.Context;
|
||||
@@ -29,7 +37,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the repository responsible to manage Item Rest object
|
||||
* This is the repository responsible to manage Community Rest object
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
@@ -47,6 +55,38 @@ public class CommunityRestRepository extends DSpaceRestRepository<CommunityRest,
|
||||
System.out.println("Repository initialized by Spring");
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
protected CommunityRest createAndReturn(Context context) throws AuthorizeException {
|
||||
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
CommunityRest communityRest = null;
|
||||
try {
|
||||
ServletInputStream input = req.getInputStream();
|
||||
communityRest = mapper.readValue(input, CommunityRest.class);
|
||||
} catch (IOException e1) {
|
||||
throw new UnprocessableEntityException("Error parsing request body: " + e1.toString());
|
||||
}
|
||||
|
||||
Community community = null;
|
||||
|
||||
try {
|
||||
community = cs.create(null, context);
|
||||
cs.update(context, community);
|
||||
if (communityRest.getMetadata() != null) {
|
||||
for (MetadataEntryRest mer : communityRest.getMetadata()) {
|
||||
String[] metadatakey = mer.getKey().split("\\.");
|
||||
cs.addMetadata(context, community, metadatakey[0], metadatakey[1],
|
||||
metadatakey.length == 3 ? metadatakey[2] : null, mer.getLanguage(), mer.getValue());
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return converter.convert(community);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#id, 'COMMUNITY', 'READ')")
|
||||
public CommunityRest findOne(Context context, UUID id) {
|
||||
|
@@ -7,8 +7,11 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
@@ -19,7 +22,6 @@ import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.RestAddressableModel;
|
||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
@@ -66,48 +68,94 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to support full update of a REST object. This is usually required by a PUT request.
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param entity
|
||||
* the REST object to update
|
||||
* @return the new state of the REST object after persistence
|
||||
* @throws AuthorizeException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
* returned by the default implementation when the operation is not supported for the entity
|
||||
*/
|
||||
protected <S extends T> S save(Context context, S entity) throws AuthorizeException,
|
||||
RepositoryMethodNotImplementedException {
|
||||
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Method to implement to support bulk update of a REST objects via a PUT request
|
||||
*/
|
||||
public <S extends T> Iterable<S> save(Iterable<S> entities) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Return a specific REST object
|
||||
*
|
||||
* @return the REST object identified by its ID
|
||||
*/
|
||||
public T findOne(ID id) {
|
||||
Context context = obtainContext();
|
||||
return thisRepository.findOne(context, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to support retrieval of a specific REST object instance
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param id
|
||||
* the rest object id
|
||||
* @return the REST object identified by its ID
|
||||
*/
|
||||
public abstract T findOne(Context context, ID id);
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Return true if an object exist for the specified ID. The default implementation is inefficient as it retrieves
|
||||
* the actual object to state that it exists. This could lead to retrieve and inizialize lot of linked objects
|
||||
*/
|
||||
public boolean exists(ID id) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
return findOne(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll() {
|
||||
/**
|
||||
* This method cannot be implemented we required all the find method to be paginated
|
||||
*/
|
||||
public final Iterable<T> findAll() {
|
||||
throw new RuntimeException("findAll MUST be paginated");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* This method could be implemented to support bulk retrieval of specific object by their IDs. Unfortunately, this
|
||||
* method doesn't allow pagination and it could be misused to retrieve thousand objects at once
|
||||
*/
|
||||
public Iterable<T> findAll(Iterable<ID> ids) {
|
||||
throw new RuntimeException("findAll MUST be paginated");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* This method return the number of object instances of the type managed by the repository class available in the
|
||||
* system
|
||||
*/
|
||||
public long count() {
|
||||
// TODO Auto-generated method stub
|
||||
// FIXME DS-4038
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Delete the object identified by its ID
|
||||
*/
|
||||
public void delete(ID id) {
|
||||
Context context = obtainContext();
|
||||
try {
|
||||
@@ -120,44 +168,96 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to support delete of a single object instance
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param id
|
||||
* the id of the rest object to delete
|
||||
* @throws AuthorizeException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
* returned by the default implementation when the operation is not supported for the entity
|
||||
*/
|
||||
protected void delete(Context context, ID id) throws AuthorizeException, RepositoryMethodNotImplementedException {
|
||||
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Method to implement to allow delete of a specific entity instance
|
||||
*/
|
||||
public void delete(T entity) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Method to implement to support bulk delete of multiple entity instances
|
||||
*/
|
||||
public void delete(Iterable<? extends T> entities) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Method to implement to support bulk delete of ALL entity instances
|
||||
*/
|
||||
public void deleteAll() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<T> findAll(Sort sort) {
|
||||
/**
|
||||
* This method cannot be implemented we required all the find method to be paginated
|
||||
*/
|
||||
public final Iterable<T> findAll(Sort sort) {
|
||||
throw new RuntimeException("findAll MUST be paginated");
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Provide access to the manage entity instances in a paginated way
|
||||
*/
|
||||
public Page<T> findAll(Pageable pageable) {
|
||||
Context context = obtainContext();
|
||||
return thisRepository.findAll(context, pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to support scroll of entity instances from the collection resource endpoin
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param pageable
|
||||
* object embedding the requested pagination info
|
||||
* @return
|
||||
*/
|
||||
public abstract Page<T> findAll(Context context, Pageable pageable);
|
||||
|
||||
/**
|
||||
* The REST model supported by the repository
|
||||
*/
|
||||
public abstract Class<T> getDomainClass();
|
||||
|
||||
/**
|
||||
* Wrap the REST model in a REST HAL Resource
|
||||
*
|
||||
* @param model
|
||||
* the rest model instance
|
||||
* @param rels
|
||||
* the HAL links
|
||||
* @return the REST Resource
|
||||
*/
|
||||
public abstract DSpaceResource<T> wrapResource(T model, String... rels);
|
||||
|
||||
/**
|
||||
* Create and return a new instance. Data are usually retrieved from the thread bound http request
|
||||
*
|
||||
* @return the created REST object
|
||||
*/
|
||||
public T createAndReturn() {
|
||||
Context context = null;
|
||||
try {
|
||||
@@ -172,15 +272,58 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
}
|
||||
}
|
||||
|
||||
protected T createAndReturn(Context context) throws AuthorizeException, RepositoryMethodNotImplementedException {
|
||||
/**
|
||||
* Method to implement to support the creation of a new instance. Usually require to retrieve the http request from
|
||||
* the thread bound attribute
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @return the created REST object
|
||||
* @throws AuthorizeException
|
||||
* @throws SQLException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
* returned by the default implementation when the operation is not supported for the entity
|
||||
*/
|
||||
protected T createAndReturn(Context context)
|
||||
throws AuthorizeException, SQLException, RepositoryMethodNotImplementedException {
|
||||
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||
}
|
||||
|
||||
public <U extends UploadStatusResponse> U upload(HttpServletRequest request, String apiCategory, String model,
|
||||
ID id, String extraField, MultipartFile file) throws Exception {
|
||||
/**
|
||||
* Method to implement to attach/upload a file to a specific REST object
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* @param model
|
||||
* @param id
|
||||
* the ID of the target REST object
|
||||
* @param file
|
||||
* the uploaded file
|
||||
* @return the new state of the REST object
|
||||
* @throws Exception
|
||||
*/
|
||||
public T upload(HttpServletRequest request, String apiCategory, String model,
|
||||
ID id, MultipartFile file) throws Exception {
|
||||
throw new RuntimeException("No implementation found; Method not allowed!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a partial update to the REST object via JSON Patch
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* @param model
|
||||
* @param id
|
||||
* the ID of the target REST object
|
||||
* @param patch
|
||||
* the JSON Patch (https://tools.ietf.org/html/rfc6902) operation
|
||||
* @return
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
* @throws UnprocessableEntityException
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
public T patch(HttpServletRequest request, String apiCategory, String model, ID id, Patch patch)
|
||||
throws HttpRequestMethodNotSupportedException, UnprocessableEntityException, PatchBadRequestException {
|
||||
Context context = obtainContext();
|
||||
@@ -195,10 +338,73 @@ public abstract class DSpaceRestRepository<T extends RestAddressableModel, ID ex
|
||||
return findOne(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to allow partial update of the REST object via JSON Patch
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param apiCategory
|
||||
* @param model
|
||||
* @param id
|
||||
* the ID of the target REST object
|
||||
* @param patch
|
||||
* the JSON Patch (https://tools.ietf.org/html/rfc6902) operation
|
||||
* @return the full new state of the REST object after patching
|
||||
* @throws HttpRequestMethodNotSupportedException
|
||||
* @throws UnprocessableEntityException
|
||||
* @throws PatchBadRequestException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
* returned by the default implementation when the operation is not supported for the entity
|
||||
*
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
* @throws DCInputsReaderException
|
||||
*/
|
||||
protected void patch(Context context, HttpServletRequest request, String apiCategory, String model, ID id,
|
||||
Patch patch)
|
||||
throws RepositoryMethodNotImplementedException, SQLException, AuthorizeException, DCInputsReaderException {
|
||||
throw new RepositoryMethodNotImplementedException(apiCategory, model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk create object instances from an uploaded file
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param uploadfile
|
||||
* the file to process
|
||||
* @return the created objects
|
||||
* @throws SQLException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
public Iterable<T> upload(HttpServletRequest request, MultipartFile uploadfile)
|
||||
throws SQLException, FileNotFoundException, IOException, AuthorizeException {
|
||||
Context context = obtainContext();
|
||||
Iterable<T> entity = upload(context, request, uploadfile);
|
||||
context.commit();
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to implement to support bulk creation of objects from a file
|
||||
*
|
||||
* @param request
|
||||
* the http request
|
||||
* @param uploadfile
|
||||
* the file to process
|
||||
* @return the created objects
|
||||
* @throws SQLException
|
||||
* @throws FileNotFoundException
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
* @throws RepositoryMethodNotImplementedException
|
||||
*/
|
||||
protected Iterable<T> upload(Context context, HttpServletRequest request,
|
||||
MultipartFile uploadfile)
|
||||
throws SQLException, FileNotFoundException, IOException, AuthorizeException {
|
||||
throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ package org.dspace.app.rest.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.converter.DiscoverConfigurationConverter;
|
||||
import org.dspace.app.rest.converter.DiscoverFacetConfigurationConverter;
|
||||
@@ -91,7 +93,7 @@ public class DiscoveryRestRepository extends AbstractDSpaceRestRepository {
|
||||
public SearchResultsRest getSearchObjects(final String query, final String dsoType, final String dsoScope,
|
||||
final String configurationName,
|
||||
final List<SearchFilter> searchFilters, final Pageable page)
|
||||
throws InvalidRequestException {
|
||||
throws InvalidRequestException, BadRequestException {
|
||||
Context context = obtainContext();
|
||||
|
||||
DSpaceObject scopeObject = scopeResolver.resolveScope(context, dsoScope);
|
||||
@@ -108,6 +110,7 @@ public class DiscoveryRestRepository extends AbstractDSpaceRestRepository {
|
||||
|
||||
} catch (SearchServiceException e) {
|
||||
log.error("Error while searching with Discovery", e);
|
||||
throw new IllegalArgumentException("Error while searching with Discovery: " + e.getMessage());
|
||||
}
|
||||
|
||||
return discoverResultConverter
|
||||
|
@@ -10,6 +10,7 @@ package org.dspace.app.rest.repository;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
@@ -19,11 +20,15 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.EPersonConverter;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.MetadataEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.EPersonResource;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.repository.patch.EPersonPatch;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.core.Context;
|
||||
@@ -34,6 +39,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -54,6 +60,9 @@ public class EPersonRestRepository extends DSpaceRestRepository<EPersonRest, UUI
|
||||
@Autowired
|
||||
EPersonConverter converter;
|
||||
|
||||
@Autowired
|
||||
EPersonPatch epersonPatch;
|
||||
|
||||
@Override
|
||||
protected EPersonRest createAndReturn(Context context)
|
||||
throws AuthorizeException {
|
||||
@@ -179,6 +188,56 @@ public class EPersonRestRepository extends DSpaceRestRepository<EPersonRest, UUI
|
||||
return converter.fromModel(eperson);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
||||
Patch patch)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, AuthorizeException,
|
||||
ResourceNotFoundException {
|
||||
|
||||
try {
|
||||
EPerson eperson = es.find(context, uuid);
|
||||
if (eperson == null) {
|
||||
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
|
||||
}
|
||||
List<Operation> operations = patch.getOperations();
|
||||
EPersonRest ePersonRest = findOne(context, uuid);
|
||||
EPersonRest patchedModel = (EPersonRest) epersonPatch.patch(ePersonRest, operations);
|
||||
updatePatchedValues(context, patchedModel, eperson);
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies changes in the rest model.
|
||||
* @param context
|
||||
* @param ePersonRest the updated eperson rest
|
||||
* @param ePerson the eperson content object
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
private void updatePatchedValues(Context context, EPersonRest ePersonRest, EPerson ePerson)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
if (ePersonRest.getPassword() != null) {
|
||||
es.setPassword(ePerson, ePersonRest.getPassword());
|
||||
}
|
||||
if (ePersonRest.isRequireCertificate() != ePerson.getRequireCertificate()) {
|
||||
ePerson.setRequireCertificate(ePersonRest.isRequireCertificate());
|
||||
}
|
||||
if (ePersonRest.isCanLogIn() != ePerson.canLogIn()) {
|
||||
ePerson.setCanLogIn(ePersonRest.isCanLogIn());
|
||||
}
|
||||
if (!Objects.equals(ePersonRest.getNetid(), ePerson.getNetid())) {
|
||||
ePerson.setNetid(ePersonRest.getNetid());
|
||||
}
|
||||
|
||||
es.update(context, ePerson);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void delete(Context context, UUID id) throws AuthorizeException {
|
||||
EPerson eperson = null;
|
||||
|
@@ -7,16 +7,23 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dspace.app.rest.converter.GroupConverter;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.GroupRest;
|
||||
import org.dspace.app.rest.model.MetadataEntryRest;
|
||||
import org.dspace.app.rest.model.hateoas.GroupResource;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -33,11 +40,46 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
@Component(GroupRest.CATEGORY + "." + GroupRest.NAME)
|
||||
public class GroupRestRepository extends DSpaceRestRepository<GroupRest, UUID> {
|
||||
GroupService gs = EPersonServiceFactory.getInstance().getGroupService();
|
||||
@Autowired
|
||||
GroupService gs;
|
||||
|
||||
@Autowired
|
||||
GroupConverter converter;
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
protected GroupRest createAndReturn(Context context)
|
||||
throws AuthorizeException, RepositoryMethodNotImplementedException {
|
||||
HttpServletRequest req = getRequestService().getCurrentRequest().getHttpServletRequest();
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
GroupRest groupRest = null;
|
||||
|
||||
try {
|
||||
groupRest = mapper.readValue(req.getInputStream(), GroupRest.class);
|
||||
} catch (IOException excIO) {
|
||||
throw new UnprocessableEntityException("error parsing the body ..." + excIO.getMessage());
|
||||
}
|
||||
|
||||
Group group = null;
|
||||
try {
|
||||
group = gs.create(context);
|
||||
gs.setName(group, groupRest.getName());
|
||||
gs.update(context, group);
|
||||
|
||||
if (groupRest.getMetadata() != null) {
|
||||
for (MetadataEntryRest mer: groupRest.getMetadata()) {
|
||||
String[] metadatakey = mer.getKey().split("\\.");
|
||||
gs.addMetadata(context, group, metadatakey[0], metadatakey[1],
|
||||
metadatakey.length == 3 ? metadatakey[2] : null, mer.getLanguage(), mer.getValue());
|
||||
}
|
||||
}
|
||||
} catch (SQLException excSQL) {
|
||||
throw new RuntimeException(excSQL.getMessage(), excSQL);
|
||||
}
|
||||
|
||||
return converter.convert(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#id, 'GROUP', 'READ')")
|
||||
public GroupRest findOne(Context context, UUID id) {
|
||||
@@ -78,4 +120,4 @@ public class GroupRestRepository extends DSpaceRestRepository<GroupRest, UUID> {
|
||||
return new GroupResource(eperson, utils, rels);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
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.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.repository.patch.ItemPatch;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
@@ -52,9 +53,6 @@ public class ItemRestRepository extends DSpaceRestRepository<ItemRest, UUID> {
|
||||
@Autowired
|
||||
ItemConverter converter;
|
||||
|
||||
/**
|
||||
* Proposed helper class for Item patches.
|
||||
*/
|
||||
@Autowired
|
||||
ItemPatch itemPatch;
|
||||
|
||||
@@ -99,16 +97,51 @@ public class ItemRestRepository extends DSpaceRestRepository<ItemRest, UUID> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid, Patch
|
||||
patch)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException,
|
||||
ResourceNotFoundException {
|
||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, UUID uuid,
|
||||
Patch patch)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException,
|
||||
ResourceNotFoundException {
|
||||
|
||||
ItemRest restModel = findOne(context, uuid);
|
||||
if (restModel == null) {
|
||||
Item item = is.find(context, uuid);
|
||||
|
||||
if (item == null) {
|
||||
throw new ResourceNotFoundException(apiCategory + "." + model + " with id: " + uuid + " not found");
|
||||
}
|
||||
itemPatch.patch(restModel, context, patch);
|
||||
|
||||
List<Operation> operations = patch.getOperations();
|
||||
ItemRest itemRest = findOne(uuid);
|
||||
|
||||
ItemRest patchedModel = (ItemRest) itemPatch.patch(itemRest, operations);
|
||||
updatePatchedValues(context, patchedModel, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists changes to the rest model.
|
||||
* @param context
|
||||
* @param itemRest the updated item rest resource
|
||||
* @param item the item content object
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
private void updatePatchedValues(Context context, ItemRest itemRest, Item item)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
try {
|
||||
if (itemRest.getWithdrawn() != item.isWithdrawn()) {
|
||||
if (itemRest.getWithdrawn()) {
|
||||
is.withdraw(context, item);
|
||||
} else {
|
||||
is.reinstate(context, item);
|
||||
}
|
||||
}
|
||||
if (itemRest.getDiscoverable() != item.isDiscoverable()) {
|
||||
item.setDiscoverable(itemRest.getDiscoverable());
|
||||
is.update(context, item);
|
||||
}
|
||||
} catch (SQLException | AuthorizeException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -7,51 +7,65 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import gr.ekt.bte.core.TransformationEngine;
|
||||
import gr.ekt.bte.core.TransformationSpec;
|
||||
import gr.ekt.bte.exceptions.BadTransformationSpec;
|
||||
import gr.ekt.bte.exceptions.MalformedSourceException;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.WorkspaceItemConverter;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||
import org.dspace.app.rest.model.hateoas.WorkspaceItemResource;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||
import org.dspace.app.rest.submit.AbstractRestProcessingStep;
|
||||
import org.dspace.app.rest.submit.SubmissionService;
|
||||
import org.dspace.app.rest.submit.UploadableStep;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.app.util.SubmissionConfig;
|
||||
import org.dspace.app.util.SubmissionConfigReader;
|
||||
import org.dspace.app.util.SubmissionConfigReaderException;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.BitstreamFormat;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.service.BitstreamFormatService;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.EPersonServiceImpl;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.submit.AbstractProcessingStep;
|
||||
import org.dspace.submit.lookup.DSpaceWorkspaceItemOutputGenerator;
|
||||
import org.dspace.submit.lookup.MultipleSubmissionLookupDataLoader;
|
||||
import org.dspace.submit.lookup.SubmissionItemDataLoader;
|
||||
import org.dspace.submit.lookup.SubmissionLookupOutputGenerator;
|
||||
import org.dspace.submit.lookup.SubmissionLookupService;
|
||||
import org.dspace.submit.util.ItemSubmissionLookupDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -60,7 +74,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
*
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
|
||||
@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME)
|
||||
public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceItemRest, Integer> {
|
||||
|
||||
@@ -87,6 +100,12 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
@Autowired
|
||||
EPersonServiceImpl epersonService;
|
||||
|
||||
@Autowired
|
||||
SubmissionLookupService submissionLookupService;
|
||||
|
||||
@Autowired
|
||||
CollectionService collectionService;
|
||||
|
||||
private SubmissionConfigReader submissionConfigReader;
|
||||
|
||||
public WorkspaceItemRestRepository() throws SubmissionConfigReaderException {
|
||||
@@ -132,8 +151,8 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
try {
|
||||
Context context = obtainContext();
|
||||
EPerson ep = epersonService.find(context, submitterID);
|
||||
witems = wis.findByEPerson(context, ep);
|
||||
total = witems.size();
|
||||
witems = wis.findByEPerson(context, ep, pageable.getPageSize(), pageable.getOffset());
|
||||
total = wis.countByEPerson(context, ep);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
@@ -142,7 +161,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WorkspaceItemRest createAndReturn(Context context) {
|
||||
protected WorkspaceItemRest createAndReturn(Context context) throws SQLException, AuthorizeException {
|
||||
WorkspaceItem source = submissionService.createWorkspaceItem(context, getRequestService().getCurrentRequest());
|
||||
return converter.convert(source);
|
||||
}
|
||||
@@ -170,7 +189,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
// load the JSPStep interface for this step
|
||||
AbstractProcessingStep stepProcessing = (AbstractProcessingStep) stepClass
|
||||
.newInstance();
|
||||
stepProcessing.doProcessing(context, getRequestService().getCurrentRequest(), source);
|
||||
stepProcessing.doPreProcessing(context, source);
|
||||
} else {
|
||||
throw new Exception("The submission step class specified by '"
|
||||
+ stepConfig.getProcessingClassName()
|
||||
@@ -199,52 +218,55 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@Override
|
||||
public UploadBitstreamRest upload(HttpServletRequest request, String apiCategory, String model, Integer id,
|
||||
String extraField, MultipartFile file) throws Exception {
|
||||
|
||||
UploadBitstreamRest result;
|
||||
Bitstream source = null;
|
||||
BitstreamFormat bf = null;
|
||||
public WorkspaceItemRest upload(HttpServletRequest request, String apiCategory, String model, Integer id,
|
||||
MultipartFile file) throws Exception {
|
||||
|
||||
Context context = obtainContext();
|
||||
WorkspaceItem wsi = wis.find(context, id);
|
||||
Item item = wsi.getItem();
|
||||
// do we already have a bundle?
|
||||
List<Bundle> bundles = itemService.getBundles(item, Constants.CONTENT_BUNDLE_NAME);
|
||||
WorkspaceItemRest wsi = findOne(id);
|
||||
WorkspaceItem source = wis.find(context, id);
|
||||
List<ErrorRest> errors = new ArrayList<ErrorRest>();
|
||||
SubmissionConfig submissionConfig =
|
||||
submissionConfigReader.getSubmissionConfigByName(wsi.getSubmissionDefinition().getName());
|
||||
for (int i = 0; i < submissionConfig.getNumberOfSteps(); i++) {
|
||||
SubmissionStepConfig stepConfig = submissionConfig.getStep(i);
|
||||
|
||||
try {
|
||||
InputStream inputStream = new BufferedInputStream(file.getInputStream());
|
||||
if (bundles.size() < 1) {
|
||||
// set bundle's name to ORIGINAL
|
||||
source = itemService.createSingleBitstream(context, inputStream, item, Constants.CONTENT_BUNDLE_NAME);
|
||||
} else {
|
||||
// we have a bundle already, just add bitstream
|
||||
source = bitstreamService.create(context, bundles.get(0), inputStream);
|
||||
/*
|
||||
* First, load the step processing class (using the current
|
||||
* class loader)
|
||||
*/
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
Class stepClass;
|
||||
try {
|
||||
stepClass = loader.loadClass(stepConfig.getProcessingClassName());
|
||||
|
||||
Object stepInstance = stepClass.newInstance();
|
||||
if (UploadableStep.class.isAssignableFrom(stepClass)) {
|
||||
UploadableStep uploadableStep = (UploadableStep) stepInstance;
|
||||
uploadableStep.doPreProcessing(context, source);
|
||||
ErrorRest err =
|
||||
uploadableStep.upload(context, submissionService, stepConfig, source, file);
|
||||
uploadableStep.doPostProcessing(context, source);
|
||||
if (err != null) {
|
||||
errors.add(err);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
result = new UploadBitstreamRest();
|
||||
result.setMessage(e.getMessage());
|
||||
result.setStatus(false);
|
||||
return result;
|
||||
|
||||
}
|
||||
wsi = converter.convert(source);
|
||||
|
||||
if (errors.isEmpty()) {
|
||||
wsi.setStatus(true);
|
||||
} else {
|
||||
wsi.setStatus(false);
|
||||
wsi.getErrors().addAll(errors);
|
||||
}
|
||||
|
||||
source.setName(context, file.getOriginalFilename());
|
||||
// TODO how retrieve this information?
|
||||
source.setSource(context, extraField);
|
||||
|
||||
// Identify the format
|
||||
bf = bitstreamFormatService.guessFormat(context, source);
|
||||
source.setFormat(context, bf);
|
||||
|
||||
// Update to DB
|
||||
bitstreamService.update(context, source);
|
||||
itemService.update(context, item);
|
||||
context.commit();
|
||||
|
||||
result = submissionService.buildUploadBitstream(configurationService, source);
|
||||
result.setStatus(true);
|
||||
return result;
|
||||
return wsi;
|
||||
}
|
||||
|
||||
//TODO @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'WRITE')")
|
||||
@@ -290,20 +312,21 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
|
||||
if (stepInstance instanceof AbstractRestProcessingStep) {
|
||||
// load the JSPStep interface for this step
|
||||
AbstractRestProcessingStep stepProcessing = (AbstractRestProcessingStep) stepClass
|
||||
.newInstance();
|
||||
AbstractRestProcessingStep stepProcessing =
|
||||
(AbstractRestProcessingStep) stepClass.newInstance();
|
||||
stepProcessing.doPreProcessing(context, source);
|
||||
stepProcessing.doPatchProcessing(context, getRequestService().getCurrentRequest(), source, op);
|
||||
stepProcessing.doPostProcessing(context, source);
|
||||
} else {
|
||||
throw new PatchBadRequestException("The submission step class specified by '"
|
||||
+ stepConfig.getProcessingClassName()
|
||||
+ "' does not extend the class org.dspace.submit" +
|
||||
".AbstractProcessingStep!"
|
||||
+ " Therefore it cannot be used by the Configurable " +
|
||||
"Submission as the <processing-class>!");
|
||||
throw new PatchBadRequestException(
|
||||
"The submission step class specified by '" + stepConfig.getProcessingClassName() +
|
||||
"' does not extend the class org.dspace.submit.AbstractProcessingStep!" +
|
||||
" Therefore it cannot be used by the Configurable Submission as the <processing-class>!");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new PatchException("Error processing the patch request", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,8 +339,161 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
||||
try {
|
||||
witem = wis.find(context, id);
|
||||
wis.deleteAll(context, witem);
|
||||
context.addEvent(new Event(Event.DELETE, Constants.ITEM, witem.getItem().getID(), null,
|
||||
itemService.getIdentifiers(context, witem.getItem())));
|
||||
} catch (SQLException | IOException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<WorkspaceItemRest> upload(Context context, HttpServletRequest request,
|
||||
MultipartFile uploadfile)
|
||||
throws SQLException, FileNotFoundException, IOException, AuthorizeException {
|
||||
File file = Utils.getFile(uploadfile, "upload-loader", "filedataloader");
|
||||
List<WorkspaceItemRest> results = new ArrayList<>();
|
||||
|
||||
try {
|
||||
String uuid = request.getParameter("collection");
|
||||
if (StringUtils.isBlank(uuid)) {
|
||||
uuid = configurationService.getProperty("submission.default.collection");
|
||||
}
|
||||
|
||||
Collection collection = null;
|
||||
if (StringUtils.isNotBlank(uuid)) {
|
||||
collection = collectionService.find(context, UUID.fromString(uuid));
|
||||
} else {
|
||||
collection = collectionService.findAuthorizedOptimized(context, Constants.ADD).get(0);
|
||||
}
|
||||
|
||||
SubmissionConfig submissionConfig =
|
||||
submissionConfigReader.getSubmissionConfigByCollection(collection.getHandle());
|
||||
|
||||
|
||||
List<ItemSubmissionLookupDTO> tmpResult = new ArrayList<ItemSubmissionLookupDTO>();
|
||||
|
||||
TransformationEngine transformationEngine1 = submissionLookupService.getPhase1TransformationEngine();
|
||||
TransformationSpec spec = new TransformationSpec();
|
||||
// FIXME this is mostly due to the need to test. The BTE framework has an assert statement that check if the
|
||||
// number of found record is less than the requested and treat 0 as is, instead, the implementation assume
|
||||
// 0=unlimited this lead to test failure.
|
||||
// It is unclear if BTE really respect values other than 0/MAX allowing us to put a protection against heavy
|
||||
// load
|
||||
spec.setNumberOfRecords(Integer.MAX_VALUE);
|
||||
if (transformationEngine1 != null) {
|
||||
MultipleSubmissionLookupDataLoader dataLoader =
|
||||
(MultipleSubmissionLookupDataLoader) transformationEngine1.getDataLoader();
|
||||
|
||||
List<String> fileDataLoaders = submissionLookupService.getFileProviders();
|
||||
for (String fileDataLoader : fileDataLoaders) {
|
||||
dataLoader.setFile(file.getAbsolutePath(), fileDataLoader);
|
||||
|
||||
try {
|
||||
SubmissionLookupOutputGenerator outputGenerator =
|
||||
(SubmissionLookupOutputGenerator) transformationEngine1.getOutputGenerator();
|
||||
outputGenerator.setDtoList(new ArrayList<ItemSubmissionLookupDTO>());
|
||||
log.debug("BTE transformation is about to start!");
|
||||
transformationEngine1.transform(spec);
|
||||
log.debug("BTE transformation finished!");
|
||||
tmpResult.addAll(outputGenerator.getDtoList());
|
||||
if (!tmpResult.isEmpty()) {
|
||||
//exit with the results founded on the first data provided
|
||||
break;
|
||||
}
|
||||
} catch (BadTransformationSpec e1) {
|
||||
log.error(e1.getMessage(), e1);
|
||||
} catch (MalformedSourceException e1) {
|
||||
log.error(e1.getMessage(), e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<WorkspaceItem> result = null;
|
||||
|
||||
//try to ingest workspaceitems
|
||||
if (!tmpResult.isEmpty()) {
|
||||
TransformationEngine transformationEngine2 = submissionLookupService.getPhase2TransformationEngine();
|
||||
if (transformationEngine2 != null) {
|
||||
SubmissionItemDataLoader dataLoader =
|
||||
(SubmissionItemDataLoader) transformationEngine2.getDataLoader();
|
||||
dataLoader.setDtoList(tmpResult);
|
||||
// dataLoader.setProviders()
|
||||
|
||||
DSpaceWorkspaceItemOutputGenerator outputGenerator =
|
||||
(DSpaceWorkspaceItemOutputGenerator) transformationEngine2.getOutputGenerator();
|
||||
outputGenerator.setCollection(collection);
|
||||
outputGenerator.setContext(context);
|
||||
outputGenerator.setFormName(submissionConfig.getSubmissionName());
|
||||
outputGenerator.setDto(tmpResult.get(0));
|
||||
|
||||
try {
|
||||
transformationEngine2.transform(spec);
|
||||
result = outputGenerator.getWitems();
|
||||
} catch (BadTransformationSpec e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (MalformedSourceException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//we have to create the workspaceitem to push the file also if nothing found before
|
||||
if (result == null) {
|
||||
WorkspaceItem source =
|
||||
submissionService.createWorkspaceItem(context, getRequestService().getCurrentRequest());
|
||||
result = new ArrayList<>();
|
||||
result.add(source);
|
||||
}
|
||||
|
||||
//perform upload of bitstream if there is exact one result and convert workspaceitem to entity rest
|
||||
if (result != null && !result.isEmpty()) {
|
||||
for (WorkspaceItem wi : result) {
|
||||
|
||||
List<ErrorRest> errors = new ArrayList<ErrorRest>();
|
||||
|
||||
//load bitstream into bundle ORIGINAL only if there is one result (approximately this is the
|
||||
// right behaviour for pdf file but not for other bibliographic format e.g. bibtex)
|
||||
if (result.size() == 1) {
|
||||
|
||||
for (int i = 0; i < submissionConfig.getNumberOfSteps(); i++) {
|
||||
SubmissionStepConfig stepConfig = submissionConfig.getStep(i);
|
||||
|
||||
ClassLoader loader = this.getClass().getClassLoader();
|
||||
Class stepClass;
|
||||
try {
|
||||
stepClass = loader.loadClass(stepConfig.getProcessingClassName());
|
||||
|
||||
Object stepInstance = stepClass.newInstance();
|
||||
if (UploadableStep.class.isAssignableFrom(stepClass)) {
|
||||
UploadableStep uploadableStep = (UploadableStep) stepInstance;
|
||||
ErrorRest err = uploadableStep.upload(context, submissionService, stepConfig, wi,
|
||||
uploadfile);
|
||||
if (err != null) {
|
||||
errors.add(err);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
WorkspaceItemRest wsi = converter.convert(wi);
|
||||
if (result.size() == 1) {
|
||||
if (errors.isEmpty()) {
|
||||
wsi.setStatus(true);
|
||||
} else {
|
||||
wsi.setStatus(false);
|
||||
wsi.getErrors().addAll(errors);
|
||||
}
|
||||
}
|
||||
results.add(wsi);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
file.delete();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
@@ -7,16 +7,12 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository.patch;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.patch.Patch;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The base class for resource PATCH operations.
|
||||
@@ -26,85 +22,80 @@ import org.dspace.core.Context;
|
||||
public abstract class AbstractResourcePatch<R extends RestModel> {
|
||||
|
||||
/**
|
||||
* Handles the patch operations, delegating actions to sub-class implementations. If no sub-class method
|
||||
* is provided, the default method throws a UnprocessableEntityException.
|
||||
* Handles the patch operations. Patch implementations are provided by subclasses.
|
||||
* The default methods throw an UnprocessableEntityException.
|
||||
*
|
||||
* @param restModel the REST resource to patch
|
||||
* @param context
|
||||
* @param patch
|
||||
* @param restModel the rest resource to patch
|
||||
* @param operations list of patch operations
|
||||
* @throws UnprocessableEntityException
|
||||
* @throws PatchBadRequestException
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
public void patch(R restModel, Context context, Patch patch)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
|
||||
List<Operation> operations = patch.getOperations();
|
||||
public RestModel patch(R restModel, List<Operation> operations) {
|
||||
|
||||
// Note: the list of possible operations is taken from JsonPatchConverter class. Does not implement
|
||||
// test https://tools.ietf.org/html/rfc6902#section-4.6
|
||||
ops: for (Operation op : operations) {
|
||||
switch (op.getOp()) {
|
||||
case "add":
|
||||
add(restModel, context, op);
|
||||
restModel = add(restModel, op);
|
||||
continue ops;
|
||||
case "replace":
|
||||
replace(restModel, context, op);
|
||||
restModel = replace(restModel, op);
|
||||
continue ops;
|
||||
case "remove":
|
||||
remove(restModel, context, op);
|
||||
restModel = remove(restModel, op);
|
||||
continue ops;
|
||||
case "copy":
|
||||
copy(restModel, context, op);
|
||||
restModel = copy(restModel, op);
|
||||
continue ops;
|
||||
case "move":
|
||||
move(restModel, context, op);
|
||||
restModel = move(restModel, op);
|
||||
continue ops;
|
||||
default:
|
||||
// JsonPatchConverter should have thrown error before this point.
|
||||
throw new PatchBadRequestException("Missing or illegal patch operation: " + op.getOp());
|
||||
}
|
||||
}
|
||||
|
||||
return restModel;
|
||||
|
||||
}
|
||||
// The default patch methods throw an error when no sub-class implementation is provided.
|
||||
|
||||
protected void add(R restModel, Context context, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
protected R add(R restModel, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException {
|
||||
throw new UnprocessableEntityException(
|
||||
"The add operation is not supported."
|
||||
"The add operation is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
protected void replace(R restModel, Context context, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
// The replace operation is functionally identical to a "remove" operation for
|
||||
// a value, followed immediately by an "add" operation at the same
|
||||
// location with the replacement value. https://tools.ietf.org/html/rfc6902#section-4.3
|
||||
remove(restModel, context, operation);
|
||||
add(restModel, context, operation);
|
||||
}
|
||||
|
||||
protected void remove(R restModel, Context context, Operation operation)
|
||||
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
protected R replace(R restModel, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException {
|
||||
throw new UnprocessableEntityException(
|
||||
"The remove operation is not supported."
|
||||
"The replace operation is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
protected void copy(R restModel, Context context, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
protected R remove(R restModel, Operation operation)
|
||||
|
||||
throws UnprocessableEntityException, PatchBadRequestException {
|
||||
throw new UnprocessableEntityException(
|
||||
"The copy operation is not supported."
|
||||
"The remove operation is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
protected void move(R restModel, Context context, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
protected R copy(R restModel, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException {
|
||||
throw new UnprocessableEntityException(
|
||||
"The move operation is not supported."
|
||||
"The copy operation is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
protected R move(R restModel, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException {
|
||||
throw new UnprocessableEntityException(
|
||||
"The move operation is not supported."
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.repository.patch;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.repository.patch.factories.EPersonOperationFactory;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Provides patch operations for eperson updates.
|
||||
*/
|
||||
@Component
|
||||
public class EPersonPatch extends AbstractResourcePatch<EPersonRest> {
|
||||
|
||||
@Autowired
|
||||
EPersonOperationFactory patchFactory;
|
||||
|
||||
/**
|
||||
* Performs the replace operation.
|
||||
* @param eperson the eperson rest representation
|
||||
* @param operation the replace operation
|
||||
* @throws UnprocessableEntityException
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
protected EPersonRest replace(EPersonRest eperson, Operation operation) {
|
||||
|
||||
ResourcePatchOperation<EPersonRest> patchOperation =
|
||||
patchFactory.getReplaceOperationForPath(operation.getPath());
|
||||
|
||||
return patchOperation.perform(eperson, operation);
|
||||
|
||||
}
|
||||
}
|
@@ -7,137 +7,37 @@
|
||||
*/
|
||||
package org.dspace.app.rest.repository.patch;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.app.rest.repository.patch.factories.ItemOperationFactory;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the implementation for Item resource patches.
|
||||
*
|
||||
* @author Michael Spalti
|
||||
* Provides PATCH operations for item updates.
|
||||
*/
|
||||
@Component
|
||||
public class ItemPatch extends AbstractResourcePatch<ItemRest> {
|
||||
|
||||
private static final String OPERATION_PATH_WITHDRAW = "/withdrawn";
|
||||
|
||||
private static final String OPERATION_PATH_DISCOVERABLE = "/discoverable";
|
||||
|
||||
private static final Logger log = Logger.getLogger(ItemPatch.class);
|
||||
|
||||
@Autowired
|
||||
ItemService is;
|
||||
ItemOperationFactory patchFactory;
|
||||
|
||||
/**
|
||||
* Implementation of the PATCH replace operation.
|
||||
*
|
||||
* @param restModel
|
||||
* @param context
|
||||
* @param operation
|
||||
* Peforms the replace operation.
|
||||
* @param item the rest representation of the item
|
||||
* @param operation the replace operation
|
||||
* @throws UnprocessableEntityException
|
||||
* @throws PatchBadRequestException
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@Override
|
||||
protected void replace(ItemRest restModel, Context context, Operation operation)
|
||||
throws UnprocessableEntityException, PatchBadRequestException, SQLException, AuthorizeException {
|
||||
protected ItemRest replace(ItemRest item, Operation operation) {
|
||||
|
||||
switch (operation.getPath()) {
|
||||
case OPERATION_PATH_WITHDRAW:
|
||||
withdraw(restModel, context, (Boolean) operation.getValue());
|
||||
break;
|
||||
case OPERATION_PATH_DISCOVERABLE:
|
||||
discoverable(restModel, context, (Boolean) operation.getValue());
|
||||
break;
|
||||
default:
|
||||
throw new UnprocessableEntityException(
|
||||
"Unrecognized patch operation path: " + operation.getPath()
|
||||
);
|
||||
}
|
||||
}
|
||||
ResourcePatchOperation<ItemRest> patchOperation =
|
||||
patchFactory.getReplaceOperationForPath(operation.getPath());
|
||||
|
||||
/**
|
||||
* Withdraws or reinstates the item based on boolean value provided in the patch request.
|
||||
*
|
||||
* @param restModel
|
||||
* @param context
|
||||
* @param withdrawItem
|
||||
* @throws PatchBadRequestException
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
private void withdraw(ItemRest restModel, Context context, Boolean withdrawItem)
|
||||
throws PatchBadRequestException, SQLException, AuthorizeException {
|
||||
|
||||
try {
|
||||
if (withdrawItem == null) {
|
||||
throw new PatchBadRequestException("Boolean value not provided for withdrawal operation.");
|
||||
}
|
||||
if (withdrawItem) {
|
||||
// Item is not withdrawn but is also NOT archived. Is this a possible situation?
|
||||
if (!restModel.getWithdrawn() && !restModel.getInArchive()) {
|
||||
throw new UnprocessableEntityException("Cannot withdraw item because it is not archived.");
|
||||
}
|
||||
// Item is already withdrawn. No-op, 200 response.
|
||||
// (The operation is not idempotent since it results in a provenance note in the record.)
|
||||
if (restModel.getWithdrawn()) {
|
||||
return;
|
||||
}
|
||||
Item item = is.find(context, UUID.fromString(restModel.getUuid()));
|
||||
is.withdraw(context, item);
|
||||
} else {
|
||||
// No need to reinstate item if it has not previously been not withdrawn.
|
||||
// No-op, 200 response. (The operation is not idempotent since it results
|
||||
// in a provenance note in the record.)
|
||||
if (!restModel.getWithdrawn()) {
|
||||
return;
|
||||
}
|
||||
Item item = is.find(context, UUID.fromString(restModel.getUuid()));
|
||||
is.reinstate(context, item);
|
||||
}
|
||||
|
||||
} catch (SQLException | AuthorizeException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets discoverable field on the item.
|
||||
*
|
||||
* @param restModel
|
||||
* @param context
|
||||
* @param isDiscoverable
|
||||
* @throws SQLException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
private void discoverable(ItemRest restModel, Context context, Boolean isDiscoverable)
|
||||
throws SQLException, AuthorizeException {
|
||||
|
||||
if (isDiscoverable == null) {
|
||||
throw new PatchBadRequestException("Boolean value not provided for discoverable operation.");
|
||||
}
|
||||
try {
|
||||
Item item = is.find(context, UUID.fromString(restModel.getUuid()));
|
||||
item.setDiscoverable(isDiscoverable);
|
||||
is.update(context, item);
|
||||
} catch (SQLException | AuthorizeException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
return patchOperation.perform(item, operation);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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.app.rest.repository.patch.factories;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.EPersonCertificateReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.EPersonLoginReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.EPersonNetidReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.EPersonPasswordReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Provides factory methods for obtaining instances of eperson patch operations.
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class EPersonOperationFactory {
|
||||
|
||||
@Autowired
|
||||
EPersonPasswordReplaceOperation passwordReplaceOperation;
|
||||
|
||||
@Autowired
|
||||
EPersonLoginReplaceOperation loginReplaceOperation;
|
||||
|
||||
@Autowired
|
||||
EPersonCertificateReplaceOperation certificateReplaceOperation;
|
||||
|
||||
@Autowired
|
||||
EPersonNetidReplaceOperation netidReplaceOperation;
|
||||
|
||||
private static final String OPERATION_PASSWORD_CHANGE = "/password";
|
||||
private static final String OPERATION_CAN_LOGIN = "/canLogin";
|
||||
private static final String OPERATION_REQUIRE_CERTIFICATE = "/certificate";
|
||||
private static final String OPERATION_SET_NETID = "/netid";
|
||||
|
||||
/**
|
||||
* Returns the patch instance for the replace operation (based on the operation path).
|
||||
*
|
||||
* @param path the operation path
|
||||
* @return the patch operation implementation
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
public ResourcePatchOperation<EPersonRest> getReplaceOperationForPath(String path) {
|
||||
|
||||
switch (path) {
|
||||
case OPERATION_PASSWORD_CHANGE:
|
||||
return passwordReplaceOperation;
|
||||
case OPERATION_CAN_LOGIN:
|
||||
return loginReplaceOperation;
|
||||
case OPERATION_REQUIRE_CERTIFICATE:
|
||||
return certificateReplaceOperation;
|
||||
case OPERATION_SET_NETID:
|
||||
return netidReplaceOperation;
|
||||
default:
|
||||
throw new PatchBadRequestException("Missing patch operation for: " + path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 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.repository.patch.factories;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ItemDiscoverableReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ItemWithdrawReplaceOperation;
|
||||
import org.dspace.app.rest.repository.patch.factories.impl.ResourcePatchOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Provides factory methods for obtaining instances of item patch operations.
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class ItemOperationFactory {
|
||||
|
||||
@Autowired
|
||||
ItemDiscoverableReplaceOperation itemDiscoverableReplaceOperation;
|
||||
|
||||
@Autowired
|
||||
ItemWithdrawReplaceOperation itemWithdrawReplaceOperation;
|
||||
|
||||
private static final String OPERATION_PATH_WITHDRAW = "/withdrawn";
|
||||
private static final String OPERATION_PATH_DISCOVERABLE = "/discoverable";
|
||||
|
||||
/**
|
||||
* Returns the patch instance for the replace operation (based on the operation path).
|
||||
*
|
||||
* @param path the operation path
|
||||
* @return the patch operation implementation
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
public ResourcePatchOperation<ItemRest> getReplaceOperationForPath(String path) {
|
||||
|
||||
switch (path) {
|
||||
case OPERATION_PATH_DISCOVERABLE:
|
||||
return itemDiscoverableReplaceOperation;
|
||||
case OPERATION_PATH_WITHDRAW:
|
||||
return itemWithdrawReplaceOperation;
|
||||
default:
|
||||
throw new PatchBadRequestException("Missing patch operation for: " + path);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation for EPerson requires certificate patches.
|
||||
*
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/epersons/eperson/<:id-eperson> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /certificate", "value": true|false]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class EPersonCertificateReplaceOperation extends ReplacePatchOperation<EPersonRest, Boolean>
|
||||
implements ResourcePatchOperation<EPersonRest> {
|
||||
|
||||
@Override
|
||||
public EPersonRest replace(EPersonRest eperson, Operation operation) {
|
||||
|
||||
Boolean requireCert = getBooleanOperationValue(operation.getValue());
|
||||
eperson.setRequireCertificate(requireCert);
|
||||
return eperson;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(EPersonRest resource) {
|
||||
// TODO: many (all?) boolean values on the rest model should never be null.
|
||||
// So perhaps the error to throw in this case is different...IllegalStateException?
|
||||
// Or perhaps do nothing (no check is required).
|
||||
if ((Object) resource.isRequireCertificate() == null) {
|
||||
throw new PatchBadRequestException("Attempting to replace a non-existent value.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Boolean[]> getArrayClassForEvaluation() {
|
||||
return Boolean[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Boolean> getClassForEvaluation() {
|
||||
return Boolean.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation for EPerson canLogin patches.
|
||||
*
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/epersons/eperson/<:id-eperson> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /canLogin", "value": true|false]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class EPersonLoginReplaceOperation extends ReplacePatchOperation<EPersonRest, Boolean>
|
||||
implements ResourcePatchOperation<EPersonRest> {
|
||||
|
||||
@Override
|
||||
public EPersonRest replace(EPersonRest eperson, Operation operation) {
|
||||
|
||||
Boolean canLogin = getBooleanOperationValue(operation.getValue());
|
||||
eperson.setCanLogIn(canLogin);
|
||||
return eperson;
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(EPersonRest resource) {
|
||||
if ((Object) resource.isCanLogIn() == null) {
|
||||
throw new PatchBadRequestException("Attempting to replace a non-existent value.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Boolean[]> getArrayClassForEvaluation() {
|
||||
return Boolean[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<Boolean> getClassForEvaluation() {
|
||||
return Boolean.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation for EPerson netid patches.
|
||||
*
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/epersons/eperson/<:id-eperson> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /netid", "value": "newNetId"]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class EPersonNetidReplaceOperation extends ReplacePatchOperation<EPersonRest, String>
|
||||
implements ResourcePatchOperation<EPersonRest> {
|
||||
|
||||
@Override
|
||||
EPersonRest replace(EPersonRest eperson, Operation operation) {
|
||||
|
||||
eperson.setNetid((String) operation.getValue());
|
||||
return eperson;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(EPersonRest resource) {
|
||||
if (resource.getNetid() == null) {
|
||||
throw new PatchBadRequestException("Attempting to replace a non-existent value.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<String[]> getArrayClassForEvaluation() {
|
||||
return String[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<String> getClassForEvaluation() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Implementation for EPerson password patches.
|
||||
*
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/epersons/eperson/<:id-eperson> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /password", "value": "newpassword"]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class EPersonPasswordReplaceOperation extends ReplacePatchOperation<EPersonRest, String> {
|
||||
|
||||
@Override
|
||||
EPersonRest replace(EPersonRest eperson, Operation operation) {
|
||||
|
||||
eperson.setPassword((String) operation.getValue());
|
||||
return eperson;
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(EPersonRest resource) {
|
||||
/*
|
||||
* FIXME: the password field in eperson rest model is always null because
|
||||
* the value is not set in the rest converter.
|
||||
* We would normally throw an exception here since replace
|
||||
* operations are not allowed on non-existent values, but that
|
||||
* would prevent the password update from ever taking place.
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<String[]> getArrayClassForEvaluation() {
|
||||
return String[].class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<String> getClassForEvaluation() {
|
||||
return String.class;
|
||||
}
|
||||
}
|
@@ -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.app.rest.repository.patch.factories.impl;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the implementation for Item resource patches.
|
||||
*
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/item/<:id-item> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /discoverable", "value": true|false]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class ItemDiscoverableReplaceOperation extends ReplacePatchOperation<ItemRest, Boolean> {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ItemDiscoverableReplaceOperation.class);
|
||||
|
||||
|
||||
@Override
|
||||
public ItemRest replace(ItemRest item, Operation operation) {
|
||||
|
||||
Boolean discoverable = getBooleanOperationValue(operation.getValue());
|
||||
item.setDiscoverable(discoverable);
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(ItemRest resource) {
|
||||
if ((Object) resource.getDiscoverable() == null) {
|
||||
throw new PatchBadRequestException("Attempting to replace a non-existent value.");
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<Boolean[]> getArrayClassForEvaluation() {
|
||||
return Boolean[].class;
|
||||
}
|
||||
|
||||
protected Class<Boolean> getClassForEvaluation() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
}
|
@@ -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.app.rest.repository.patch.factories.impl;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is the implementation for Item resource patches.
|
||||
* <p>
|
||||
* Example: <code>
|
||||
* curl -X PATCH http://${dspace.url}/api/item/<:id-item> -H "
|
||||
* Content-Type: application/json" -d '[{ "op": "replace", "path": "
|
||||
* /withdrawn", "value": true|false]'
|
||||
* </code>
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
@Component
|
||||
public class ItemWithdrawReplaceOperation extends ReplacePatchOperation<ItemRest, Boolean> {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ItemWithdrawReplaceOperation.class);
|
||||
|
||||
@Override
|
||||
public ItemRest replace(ItemRest item, Operation operation) {
|
||||
|
||||
Boolean withdraw = getBooleanOperationValue(operation.getValue());
|
||||
|
||||
// This is a request to withdraw the item.
|
||||
if (withdraw) {
|
||||
// The item is currently not withdrawn and also not archived. Is this a possible situation?
|
||||
if (!item.getWithdrawn() && !item.getInArchive()) {
|
||||
throw new UnprocessableEntityException("Cannot withdraw item when it is not in archive.");
|
||||
}
|
||||
// Item is already withdrawn. No-op, 200 response.
|
||||
// (The operation is not idempotent since it results in a provenance note in the record.)
|
||||
if (item.getWithdrawn()) {
|
||||
return item;
|
||||
}
|
||||
item.setWithdrawn(true);
|
||||
return item;
|
||||
|
||||
} else {
|
||||
// No need to reinstate item if it has not previously been not withdrawn.
|
||||
// No-op, 200 response. (The operation is not idempotent since it results
|
||||
// in a provenance note in the record.)
|
||||
if (!item.getWithdrawn()) {
|
||||
return item;
|
||||
}
|
||||
item.setWithdrawn(false);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkModelForExistingValue(ItemRest resource) {
|
||||
if ((Object) resource.getWithdrawn() == null) {
|
||||
throw new PatchBadRequestException("Attempting to replace a non-existent value.");
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<Boolean[]> getArrayClassForEvaluation() {
|
||||
return Boolean[].class;
|
||||
}
|
||||
|
||||
protected Class<Boolean> getClassForEvaluation() {
|
||||
return Boolean.class;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator;
|
||||
|
||||
/**
|
||||
* Base class for all resource patch operations.
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
public abstract class PatchOperation<R extends RestModel, T>
|
||||
implements ResourcePatchOperation<R> {
|
||||
|
||||
/**
|
||||
* Updates the rest model by applying the patch operation.
|
||||
*
|
||||
* @param resource the rest model.
|
||||
* @param operation the patch operation.
|
||||
* @return the updated rest model.
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
public abstract R perform(R resource, Operation operation);
|
||||
|
||||
/**
|
||||
* Throws PatchBadRequestException for missing operation value.
|
||||
*
|
||||
* @param value the value to test
|
||||
*/
|
||||
void checkOperationValue(Object value) {
|
||||
if (value == null) {
|
||||
throw new PatchBadRequestException("No value provided for the operation.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows clients to use either a boolean or a string representation of boolean value.
|
||||
*
|
||||
* @param value the operation value
|
||||
* @return the original or derived boolean value
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
Boolean getBooleanOperationValue(Object value) {
|
||||
Boolean bool;
|
||||
|
||||
if (value instanceof String) {
|
||||
bool = BooleanUtils.toBooleanObject((String) value);
|
||||
if (bool == null) {
|
||||
// make sure the string was converted to boolean.
|
||||
throw new PatchBadRequestException("Boolean value not provided.");
|
||||
}
|
||||
} else {
|
||||
bool = (Boolean) value;
|
||||
}
|
||||
return bool;
|
||||
}
|
||||
|
||||
// This is duplicated code (see org.dspace.app.rest.submit.factory.impl.PatchOperation)
|
||||
// If it stays here, it should be DRY. Current patch resource patch operations do not
|
||||
// use these methods since operation values are either strings or booleans.
|
||||
// These methods handle JsonValueEvaluator instances for json objects and arrays,
|
||||
// as returned by the JsonPatchConverter. A complete implementation of the PatchOperation
|
||||
// class will need these methods.
|
||||
public List<T> evaluateArrayObject(LateObjectEvaluator value) {
|
||||
List<T> results = new ArrayList<T>();
|
||||
T[] list = null;
|
||||
if (value != null) {
|
||||
LateObjectEvaluator object = (LateObjectEvaluator) value;
|
||||
list = (T[]) object.evaluate(getArrayClassForEvaluation());
|
||||
}
|
||||
|
||||
for (T t : list) {
|
||||
results.add(t);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public T evaluateSingleObject(LateObjectEvaluator value) {
|
||||
T single = null;
|
||||
if (value != null) {
|
||||
LateObjectEvaluator object = (LateObjectEvaluator) value;
|
||||
single = (T) object.evaluate(getClassForEvaluation());
|
||||
}
|
||||
return single;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method should return the typed array to be used in the
|
||||
* LateObjectEvaluator evaluation of json arrays.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<T[]> getArrayClassForEvaluation();
|
||||
|
||||
/**
|
||||
* This method should return the object type to be used in the
|
||||
* LateObjectEvaluator evaluation of json objects.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected abstract Class<T> getClassForEvaluation();
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.exception.UnprocessableEntityException;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
|
||||
/**
|
||||
* Base class for replace patch operations.
|
||||
*
|
||||
* @author Michael Spalti
|
||||
*/
|
||||
public abstract class ReplacePatchOperation<R extends RestModel, T>
|
||||
extends PatchOperation<R, T> {
|
||||
|
||||
/**
|
||||
* Implements the patch operation for replace operations.
|
||||
* Before performing the replace operation this method checks
|
||||
* for a non-null operation value and a non-null value on the rest model
|
||||
* (replace operations should only be applied to an existing value).
|
||||
* @param resource the rest model.
|
||||
* @param operation the replace patch operation.
|
||||
* @return the updated rest model.
|
||||
* @throws PatchBadRequestException
|
||||
* @throws UnprocessableEntityException
|
||||
*/
|
||||
@Override
|
||||
public R perform(R resource, Operation operation) {
|
||||
|
||||
checkOperationValue(operation.getValue());
|
||||
checkModelForExistingValue(resource);
|
||||
return replace(resource, operation);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the replace patch operation.
|
||||
*
|
||||
* @param resource the rest model.
|
||||
* @param operation the replace patch operation.
|
||||
* @return the updated rest model.
|
||||
* @throws PatchBadRequestException
|
||||
* @throws UnprocessableEntityException
|
||||
*/
|
||||
abstract R replace(R resource, Operation operation);
|
||||
|
||||
/**
|
||||
* Replace operations are not allowed on non-existent values.
|
||||
* Null values may exist in the RestModel for certain fields
|
||||
* (usually non-boolean). This method should be implemented
|
||||
* to assure that the replace operation acts only on an existing value.
|
||||
* @param resource the rest model.
|
||||
* @throws PatchBadRequestException
|
||||
*/
|
||||
abstract void checkModelForExistingValue(R resource);
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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.repository.patch.factories.impl;
|
||||
|
||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||
import org.dspace.app.rest.model.RestModel;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
|
||||
/**
|
||||
* The patch interface used by repository classes.
|
||||
* @param <R>
|
||||
*/
|
||||
public interface ResourcePatchOperation<R extends RestModel> {
|
||||
|
||||
R perform(R resource, Operation operation)
|
||||
throws PatchBadRequestException;
|
||||
|
||||
}
|
@@ -21,11 +21,12 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.services.model.Request;
|
||||
|
||||
/**
|
||||
* Interface to retrieve information about section
|
||||
* Interface for the submission steps to populate sections in the in progress submission and react to patch requests.
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public interface AbstractRestProcessingStep {
|
||||
public interface AbstractRestProcessingStep extends ListenerProcessingStep {
|
||||
|
||||
public static final String DESCRIBE_STEP_METADATA_OPERATION_ENTRY = "itemmetadata";
|
||||
public static final String COLLECTION_STEP_OPERATION_ENTRY = "collection";
|
||||
@@ -37,9 +38,33 @@ public interface AbstractRestProcessingStep {
|
||||
|
||||
public static final String UPLOAD_STEP_METADATA_PATH = "metadata";
|
||||
|
||||
/**
|
||||
* Method to expose data in the a dedicated section of the in progress submission. The step needs to return a
|
||||
* serializable object that will be included in a section with the name (id) assigned to the step in the
|
||||
* item-submission.xml file
|
||||
*
|
||||
* @param submissionService
|
||||
* the submission service
|
||||
* @param obj
|
||||
* the in progress submission
|
||||
* @param config
|
||||
* the submission step configuration
|
||||
* @return the serializable object to include in the step generated section
|
||||
* @throws Exception
|
||||
*/
|
||||
public <T extends Serializable> T getData(SubmissionService submissionService, WorkspaceItem obj,
|
||||
SubmissionStepConfig config) throws Exception;
|
||||
|
||||
/**
|
||||
* The method will expose the list of validation errors identified by the step. The default implementation will
|
||||
* found a {@link Validation} spring bean in the context with the same name that the step id
|
||||
*
|
||||
* @param submissionService
|
||||
* @param obj
|
||||
* @param config
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
default public List<ErrorRest> validate(SubmissionService submissionService, WorkspaceItem obj,
|
||||
SubmissionStepConfig config) throws Exception {
|
||||
List<ErrorRest> errors = new ArrayList<ErrorRest>();
|
||||
@@ -55,6 +80,19 @@ public interface AbstractRestProcessingStep {
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to react to a patch request against the step managed section data
|
||||
*
|
||||
* @param context
|
||||
* the DSpace context
|
||||
* @param currentRequest
|
||||
* the http request
|
||||
* @param source
|
||||
* the in progress submission
|
||||
* @param op
|
||||
* the json patch operation
|
||||
* @throws Exception
|
||||
*/
|
||||
public void doPatchProcessing(Context context, Request currentRequest, WorkspaceItem source, Operation op)
|
||||
throws Exception;
|
||||
|
||||
|
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 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.submit;
|
||||
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* This interface allows a submission step to access and modify if needed an inprogress submission also when changes are
|
||||
* requested to sections other than the one managed by the step itself.
|
||||
*
|
||||
* This could be useful to allow a step wide validations or changes over multiple sections.
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public interface ListenerProcessingStep {
|
||||
|
||||
public void doPreProcessing(Context context, InProgressSubmission wsi);
|
||||
|
||||
public void doPostProcessing(Context context, InProgressSubmission wsi);
|
||||
|
||||
}
|
@@ -18,12 +18,14 @@ import org.apache.log4j.Logger;
|
||||
import org.atteo.evo.inflector.English;
|
||||
import org.dspace.app.rest.converter.BitstreamFormatConverter;
|
||||
import org.dspace.app.rest.converter.ResourcePolicyConverter;
|
||||
import org.dspace.app.rest.exception.RESTAuthorizationException;
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
import org.dspace.app.rest.model.CheckSumRest;
|
||||
import org.dspace.app.rest.model.MetadataValueRest;
|
||||
import org.dspace.app.rest.model.ResourcePolicyRest;
|
||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||
import org.dspace.app.rest.utils.ContextUtil;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Collection;
|
||||
@@ -31,12 +33,14 @@ import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.datasource.init.UncategorizedScriptException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -64,23 +68,35 @@ public class SubmissionService {
|
||||
|
||||
public WorkspaceItem createWorkspaceItem(Context context, Request request) {
|
||||
WorkspaceItem wsi = null;
|
||||
Collection collection = null;
|
||||
String collectionUUID = request.getHttpServletRequest().getParameter("collection");
|
||||
|
||||
if (StringUtils.isBlank(collectionUUID)) {
|
||||
String uuid = configurationService.getProperty("submission.default.collection");
|
||||
Collection collection = null;
|
||||
try {
|
||||
if (StringUtils.isNotBlank(uuid)) {
|
||||
collection = collectionService.find(context, UUID.fromString(uuid));
|
||||
collectionUUID = configurationService.getProperty("submission.default.collection");
|
||||
}
|
||||
|
||||
try {
|
||||
if (StringUtils.isNotBlank(collectionUUID)) {
|
||||
collection = collectionService.find(context, UUID.fromString(collectionUUID));
|
||||
} else {
|
||||
final List<Collection> findAuthorizedOptimized = collectionService.findAuthorizedOptimized(context,
|
||||
Constants.ADD);
|
||||
if (findAuthorizedOptimized != null && findAuthorizedOptimized.size() > 0) {
|
||||
collection = findAuthorizedOptimized.get(0);
|
||||
} else {
|
||||
collection = collectionService.findAll(context, 1, 0).get(0);
|
||||
throw new RESTAuthorizationException("No collection suitable for submission for the current user");
|
||||
}
|
||||
wsi = workspaceItemService.create(context, collection, true);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
} else {
|
||||
//TODO manage setup of default collection in the case WSI it is not null
|
||||
//TODO manage setup of collection discovered into request
|
||||
|
||||
if (collection == null) {
|
||||
throw new RESTAuthorizationException("collectionUUID=" + collectionUUID + " not found");
|
||||
}
|
||||
wsi = workspaceItemService.create(context, collection, true);
|
||||
} catch (SQLException e) {
|
||||
// wrap in a runtime exception as we cannot change the method signature
|
||||
throw new UncategorizedScriptException(e.getMessage(), e);
|
||||
} catch (AuthorizeException ae) {
|
||||
throw new RESTAuthorizationException(ae);
|
||||
}
|
||||
return wsi;
|
||||
}
|
||||
|
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* 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.submit;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* The interface for submission Steps that need to deal with file upload
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public interface UploadableStep extends ListenerProcessingStep {
|
||||
|
||||
/**
|
||||
* The method to implement to support upload of a file in the submission section (aka panel / step)
|
||||
*
|
||||
* @param context
|
||||
* the dspace context
|
||||
* @param submissionService
|
||||
* the submission service
|
||||
* @param stepConfig
|
||||
* the configuration of the submission section
|
||||
* @param wsi
|
||||
* the inprogress submission
|
||||
* @param file
|
||||
* the multipart file, please note that it is a complex object containing additional information other
|
||||
* than just the binary such as the filename and the mimetype
|
||||
* @return the encountered error if any
|
||||
* @throws IOException
|
||||
*/
|
||||
public ErrorRest upload(Context context, SubmissionService submissionService, SubmissionStepConfig stepConfig,
|
||||
InProgressSubmission wsi, MultipartFile file) throws IOException;
|
||||
|
||||
}
|
@@ -52,7 +52,13 @@ public class LicenseAddPatchOperation extends AddPatchOperation<String> {
|
||||
void add(Context context, Request currentRequest, WorkspaceItem source, String path, Object value)
|
||||
throws Exception {
|
||||
|
||||
Boolean grant = BooleanUtils.toBooleanObject((String) value);
|
||||
Boolean grant = null;
|
||||
// we are friendly with the client and accept also a string representation for the boolean
|
||||
if (value instanceof String) {
|
||||
grant = BooleanUtils.toBooleanObject((String) value);
|
||||
} else {
|
||||
grant = (Boolean) value;
|
||||
}
|
||||
|
||||
if (grant == null) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@@ -33,7 +33,13 @@ public class LicenseReplacePatchOperation extends ReplacePatchOperation<String>
|
||||
void replace(Context context, Request currentRequest, WorkspaceItem source, String path, Object value)
|
||||
throws Exception {
|
||||
|
||||
Boolean grant = BooleanUtils.toBooleanObject((String) value);
|
||||
Boolean grant = null;
|
||||
// we are friendly with the client and accept also a string representation for the boolean
|
||||
if (value instanceof String) {
|
||||
grant = BooleanUtils.toBooleanObject((String) value);
|
||||
} else {
|
||||
grant = (Boolean) value;
|
||||
}
|
||||
|
||||
if (grant == null) {
|
||||
throw new IllegalArgumentException(
|
||||
|
@@ -23,6 +23,7 @@ import org.dspace.app.util.DCInputSet;
|
||||
import org.dspace.app.util.DCInputsReader;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.core.Context;
|
||||
@@ -30,9 +31,11 @@ import org.dspace.core.Utils;
|
||||
import org.dspace.services.model.Request;
|
||||
|
||||
/**
|
||||
* Describe step for DSpace Spring Rest. Handle the exposition of metadata own by the in progress submission.
|
||||
* Describe step for DSpace Spring Rest. Expose and allow patching of the in progress submission metadata. It is
|
||||
* configured via the config/submission-forms.xml file
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
* @author Andrea Bollini (andrea.bollini at 4science.it)
|
||||
*/
|
||||
public class DescribeStep extends org.dspace.submit.step.DescribeStep implements AbstractRestProcessingStep {
|
||||
|
||||
@@ -49,7 +52,17 @@ public class DescribeStep extends org.dspace.submit.step.DescribeStep implements
|
||||
DataDescribe data = new DataDescribe();
|
||||
try {
|
||||
DCInputSet inputConfig = inputReader.getInputsByFormName(config.getId());
|
||||
for (DCInput input : inputConfig.getFields()) {
|
||||
readField(obj, config, data, inputConfig);
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private void readField(InProgressSubmission obj, SubmissionStepConfig config, DataDescribe data,
|
||||
DCInputSet inputConfig) throws DCInputsReaderException {
|
||||
for (DCInput[] row : inputConfig.getFields()) {
|
||||
for (DCInput input : row) {
|
||||
|
||||
List<String> fieldsName = new ArrayList<String>();
|
||||
if (input.isQualdropValue()) {
|
||||
@@ -93,10 +106,7 @@ public class DescribeStep extends org.dspace.submit.step.DescribeStep implements
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DCInputsReaderException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -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.submit.step;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import gr.ekt.bte.core.Record;
|
||||
import gr.ekt.bte.core.RecordSet;
|
||||
import gr.ekt.bte.core.Value;
|
||||
import gr.ekt.bte.dataloader.FileDataLoader;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
import org.dspace.app.rest.repository.WorkspaceItemRestRepository;
|
||||
import org.dspace.app.rest.submit.SubmissionService;
|
||||
import org.dspace.app.rest.submit.UploadableStep;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.submit.extraction.MetadataExtractor;
|
||||
import org.dspace.submit.step.ExtractionStep;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* This submission step allows to extract metadata from an uploaded file to enrich or initialize a submission. The
|
||||
* processing is delegated to a list of extractor specialized by format (i.e. a Grobid extractor to get data from a PDF
|
||||
* file, an extractor to get data from bibliographic file such as BibTeX, etc)
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class ExtractMetadataStep extends ExtractionStep implements UploadableStep {
|
||||
|
||||
private static final Logger log = Logger.getLogger(ExtractMetadataStep.class);
|
||||
|
||||
@Override
|
||||
public ErrorRest upload(Context context, SubmissionService submissionService, SubmissionStepConfig stepConfig,
|
||||
InProgressSubmission wsi, MultipartFile multipartFile)
|
||||
throws IOException {
|
||||
|
||||
Item item = wsi.getItem();
|
||||
try {
|
||||
List<MetadataExtractor> extractors =
|
||||
DSpaceServicesFactory.getInstance().getServiceManager().getServicesByType(MetadataExtractor.class);
|
||||
File file = null;
|
||||
for (MetadataExtractor extractor : extractors) {
|
||||
FileDataLoader dataLoader = extractor.getDataLoader();
|
||||
RecordSet recordSet = null;
|
||||
if (extractor.getExtensions()
|
||||
.contains(FilenameUtils.getExtension(multipartFile.getOriginalFilename()))) {
|
||||
|
||||
if (file == null) {
|
||||
file = Utils.getFile(multipartFile, "submissionlookup-loader", stepConfig.getId());
|
||||
}
|
||||
|
||||
FileDataLoader fdl = (FileDataLoader) dataLoader;
|
||||
fdl.setFilename(Utils.getFileName(multipartFile));
|
||||
|
||||
|
||||
recordSet = convertFields(dataLoader.getRecords(), bteBatchImportService.getOutputMap());
|
||||
|
||||
enrichItem(context, recordSet.getRecords(), item);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
ErrorRest result = new ErrorRest();
|
||||
result.setMessage(e.getMessage());
|
||||
result.getPaths().add("/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + stepConfig.getId());
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RecordSet convertFields(RecordSet recordSet, Map<String, String> fieldMap) {
|
||||
RecordSet result = new RecordSet();
|
||||
for (Record publication : recordSet.getRecords()) {
|
||||
for (String fieldName : fieldMap.keySet()) {
|
||||
String md = null;
|
||||
if (fieldMap != null) {
|
||||
md = fieldMap.get(fieldName);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(md)) {
|
||||
continue;
|
||||
} else {
|
||||
md = md.trim();
|
||||
}
|
||||
|
||||
if (publication.isMutable()) {
|
||||
List<Value> values = publication.getValues(md);
|
||||
publication.makeMutable().removeField(md);
|
||||
publication.makeMutable().addField(fieldName, values);
|
||||
}
|
||||
}
|
||||
|
||||
result.addRecord(publication);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -7,22 +7,33 @@
|
||||
*/
|
||||
package org.dspace.app.rest.submit.step;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
import org.dspace.app.rest.model.patch.Operation;
|
||||
import org.dspace.app.rest.model.step.DataUpload;
|
||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||
import org.dspace.app.rest.repository.WorkspaceItemRestRepository;
|
||||
import org.dspace.app.rest.submit.AbstractRestProcessingStep;
|
||||
import org.dspace.app.rest.submit.SubmissionService;
|
||||
import org.dspace.app.rest.submit.UploadableStep;
|
||||
import org.dspace.app.rest.submit.factory.PatchOperationFactory;
|
||||
import org.dspace.app.rest.submit.factory.impl.PatchOperation;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.BitstreamFormat;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.model.Request;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* Upload step for DSpace Spring Rest. Expose information about the bitstream
|
||||
@@ -30,8 +41,10 @@ import org.dspace.services.model.Request;
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class UploadStep extends org.dspace.submit.step.UploadStep implements AbstractRestProcessingStep {
|
||||
public class UploadStep extends org.dspace.submit.step.UploadStep
|
||||
implements AbstractRestProcessingStep, UploadableStep {
|
||||
|
||||
private static final Logger log = Logger.getLogger(UploadStep.class);
|
||||
|
||||
@Override
|
||||
public DataUpload getData(SubmissionService submissionService, WorkspaceItem obj, SubmissionStepConfig config)
|
||||
@@ -79,4 +92,54 @@ public class UploadStep extends org.dspace.submit.step.UploadStep implements Abs
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorRest upload(Context context, SubmissionService submissionService, SubmissionStepConfig stepConfig,
|
||||
InProgressSubmission wsi, MultipartFile file) {
|
||||
|
||||
Bitstream source = null;
|
||||
BitstreamFormat bf = null;
|
||||
|
||||
Item item = wsi.getItem();
|
||||
List<Bundle> bundles = null;
|
||||
try {
|
||||
// do we already have a bundle?
|
||||
bundles = itemService.getBundles(item, Constants.CONTENT_BUNDLE_NAME);
|
||||
|
||||
InputStream inputStream = new BufferedInputStream(file.getInputStream());
|
||||
if (bundles.size() < 1) {
|
||||
// set bundle's name to ORIGINAL
|
||||
source = itemService.createSingleBitstream(context, inputStream, item, Constants.CONTENT_BUNDLE_NAME);
|
||||
} else {
|
||||
// we have a bundle already, just add bitstream
|
||||
source = bitstreamService.create(context, bundles.get(0), inputStream);
|
||||
}
|
||||
|
||||
source.setName(context, Utils.getFileName(file));
|
||||
source.setSource(context, file.getOriginalFilename());
|
||||
|
||||
// Identify the format
|
||||
bf = bitstreamFormatService.guessFormat(context, source);
|
||||
source.setFormat(context, bf);
|
||||
|
||||
// Update to DB
|
||||
bitstreamService.update(context, source);
|
||||
itemService.update(context, item);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
ErrorRest result = new ErrorRest();
|
||||
result.setMessage(e.getMessage());
|
||||
if (bundles != null && bundles.size() > 0) {
|
||||
result.getPaths().add(
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + stepConfig.getId() + "/files/" +
|
||||
bundles.get(0).getBitstreams().size());
|
||||
} else {
|
||||
result.getPaths()
|
||||
.add("/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + stepConfig.getId());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import org.apache.commons.lang.StringUtils;
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
|
||||
/**
|
||||
* Abstract class to manage errors on validation during submission process
|
||||
* Abstract class to provide basic management of errors resulting from a validation on a submission
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
@@ -24,6 +24,9 @@ public abstract class AbstractValidation implements Validation {
|
||||
|
||||
private List<ErrorRest> errors = new ArrayList<ErrorRest>();
|
||||
|
||||
/**
|
||||
* An unique name to identify the validation implementation
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -32,6 +35,15 @@ public abstract class AbstractValidation implements Validation {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error message (i18nKey) for a specific json path
|
||||
*
|
||||
* @param i18nKey
|
||||
* the validation error message as a key to internationalize
|
||||
* @param path
|
||||
* the json path that identify the wrong data in the submission. It could be as specific as a single
|
||||
* value in a multivalued attribute or general of a "whole" section
|
||||
*/
|
||||
public void addError(String i18nKey, String path) {
|
||||
boolean found = false;
|
||||
if (StringUtils.isNotBlank(i18nKey)) {
|
||||
@@ -51,6 +63,11 @@ public abstract class AbstractValidation implements Validation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose the identified errors
|
||||
*
|
||||
* @return the list of identified {@link ErrorRest}
|
||||
*/
|
||||
public List<ErrorRest> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* 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.submit.step.validation;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.model.ErrorRest;
|
||||
import org.dspace.app.rest.repository.WorkspaceItemRestRepository;
|
||||
import org.dspace.app.rest.submit.SubmissionService;
|
||||
import org.dspace.app.util.DCInputsReaderException;
|
||||
import org.dspace.app.util.SubmissionStepConfig;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This submission validation check that the license has been grant for the inprogress submission looking for the
|
||||
* presence of a license bitstream in the license bundle,
|
||||
*
|
||||
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||
*/
|
||||
public class LicenseValidation extends AbstractValidation {
|
||||
|
||||
private static final String ERROR_VALIDATION_LICENSEREQUIRED = "error.validation.license.notgranted";
|
||||
|
||||
private static final Logger log = Logger.getLogger(LicenseValidation.class);
|
||||
|
||||
@Autowired
|
||||
private BitstreamService bitstreamService;
|
||||
|
||||
@Override
|
||||
public List<ErrorRest> validate(SubmissionService submissionService, WorkspaceItem obj,
|
||||
SubmissionStepConfig config) throws DCInputsReaderException, SQLException {
|
||||
|
||||
Bitstream bitstream = bitstreamService
|
||||
.getBitstreamByName(obj.getItem(), Constants.LICENSE_BUNDLE_NAME, Constants.LICENSE_BITSTREAM_NAME);
|
||||
if (bitstream == null) {
|
||||
addError(ERROR_VALIDATION_LICENSEREQUIRED,
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + config.getId());
|
||||
}
|
||||
return getErrors();
|
||||
}
|
||||
|
||||
public BitstreamService getBitstreamService() {
|
||||
return bitstreamService;
|
||||
}
|
||||
|
||||
public void setBitstreamService(BitstreamService bitstreamService) {
|
||||
this.bitstreamService = bitstreamService;
|
||||
}
|
||||
|
||||
}
|
@@ -55,43 +55,46 @@ public class MetadataValidation extends AbstractValidation {
|
||||
SubmissionStepConfig config) throws DCInputsReaderException, SQLException {
|
||||
|
||||
DCInputSet inputConfig = getInputReader().getInputsByFormName(config.getId());
|
||||
for (DCInput input : inputConfig.getFields()) {
|
||||
for (DCInput[] row : inputConfig.getFields()) {
|
||||
for (DCInput input : row) {
|
||||
String fieldKey =
|
||||
metadataAuthorityService.makeFieldKey(input.getSchema(), input.getElement(), input.getQualifier());
|
||||
boolean isAuthorityControlled = metadataAuthorityService.isAuthorityControlled(fieldKey);
|
||||
|
||||
String fieldKey = metadataAuthorityService.makeFieldKey(input.getSchema(), input.getElement(),
|
||||
input.getQualifier());
|
||||
boolean isAuthorityControlled = metadataAuthorityService.isAuthorityControlled(fieldKey);
|
||||
|
||||
List<String> fieldsName = new ArrayList<String>();
|
||||
if (input.isQualdropValue()) {
|
||||
for (Object qualifier : input.getPairs()) {
|
||||
fieldsName.add(input.getFieldName() + "." + (String) qualifier);
|
||||
}
|
||||
} else {
|
||||
fieldsName.add(input.getFieldName());
|
||||
}
|
||||
|
||||
for (String fieldName : fieldsName) {
|
||||
List<MetadataValue> mdv = itemService.getMetadataByMetadataString(obj.getItem(), fieldName);
|
||||
for (MetadataValue md : mdv) {
|
||||
if (!(input.validate(md.getValue()))) {
|
||||
addError(ERROR_VALIDATION_REGEX, "/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/"
|
||||
+ config.getId() + "/" + input.getFieldName() + "/" + md.getPlace());
|
||||
List<String> fieldsName = new ArrayList<String>();
|
||||
if (input.isQualdropValue()) {
|
||||
for (Object qualifier : input.getPairs()) {
|
||||
fieldsName.add(input.getFieldName() + "." + (String) qualifier);
|
||||
}
|
||||
if (isAuthorityControlled) {
|
||||
String authKey = md.getAuthority();
|
||||
if (metadataAuthorityService.isAuthorityRequired(fieldKey) && StringUtils.isNotBlank(authKey)) {
|
||||
addError(ERROR_VALIDATION_AUTHORITY_REQUIRED,
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + config.getId()
|
||||
+ "/" + input.getFieldName() + "/" + md.getPlace());
|
||||
} else {
|
||||
fieldsName.add(input.getFieldName());
|
||||
}
|
||||
|
||||
for (String fieldName : fieldsName) {
|
||||
List<MetadataValue> mdv = itemService.getMetadataByMetadataString(obj.getItem(), fieldName);
|
||||
for (MetadataValue md : mdv) {
|
||||
if (!(input.validate(md.getValue()))) {
|
||||
addError(ERROR_VALIDATION_REGEX,
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + config.getId() + "/" +
|
||||
input.getFieldName() + "/" + md.getPlace());
|
||||
}
|
||||
if (isAuthorityControlled) {
|
||||
String authKey = md.getAuthority();
|
||||
if (metadataAuthorityService.isAuthorityRequired(fieldKey) &&
|
||||
StringUtils.isNotBlank(authKey)) {
|
||||
addError(ERROR_VALIDATION_AUTHORITY_REQUIRED,
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + config.getId() +
|
||||
"/" + input.getFieldName() + "/" + md.getPlace());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((input.isRequired() && mdv.size() == 0) && input.isVisible(DCInput.SUBMISSION_SCOPE)) {
|
||||
// since this field is missing add to list of error
|
||||
// fields
|
||||
addError(ERROR_VALIDATION_REQUIRED, "/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/"
|
||||
+ config.getId() + "/" + input.getFieldName());
|
||||
if ((input.isRequired() && mdv.size() == 0) && input.isVisible(DCInput.SUBMISSION_SCOPE)) {
|
||||
// since this field is missing add to list of error
|
||||
// fields
|
||||
addError(ERROR_VALIDATION_REQUIRED,
|
||||
"/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + config.getId() + "/" +
|
||||
input.getFieldName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -181,9 +181,7 @@ public class DiscoverQueryBuilder implements InitializingBean {
|
||||
|
||||
//Set search query
|
||||
if (StringUtils.isNotBlank(query)) {
|
||||
//Note that these quotes are needed incase we try to query OR for example.
|
||||
//If the quotes aren't present, it'll crash.
|
||||
queryArgs.setQuery("\"" + searchService.escapeQueryChars(query) + "\"");
|
||||
queryArgs.setQuery(query);
|
||||
}
|
||||
|
||||
//Limit results to DSO type
|
||||
|
@@ -41,8 +41,8 @@ public class MultipartFileSender {
|
||||
private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES";
|
||||
private static final String CONTENT_TYPE_MULTITYPE_WITH_BOUNDARY = "multipart/byteranges; boundary=" +
|
||||
MULTIPART_BOUNDARY;
|
||||
private static final String CONTENT_DISPOSITION_INLINE = "inline";
|
||||
private static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment";
|
||||
public static final String CONTENT_DISPOSITION_INLINE = "inline";
|
||||
public static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment";
|
||||
private static final String IF_NONE_MATCH = "If-None-Match";
|
||||
private static final String IF_MODIFIED_SINCE = "If-Modified-Since";
|
||||
private static final String ETAG = "ETag";
|
||||
@@ -134,6 +134,10 @@ public class MultipartFileSender {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public MultipartFileSender withDisposition(String contentDisposition) {
|
||||
this.disposition = contentDisposition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void serveResource() throws IOException {
|
||||
|
||||
@@ -172,9 +176,9 @@ public class MultipartFileSender {
|
||||
CONTENT_DISPOSITION_ATTACHMENT;
|
||||
}
|
||||
|
||||
response.setHeader(CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_FORMAT, disposition, fileName));
|
||||
log.debug("Content-Disposition : {}", disposition);
|
||||
}
|
||||
response.setHeader(CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_FORMAT, disposition, fileName));
|
||||
log.debug("Content-Disposition : {}", disposition);
|
||||
|
||||
// Content phase
|
||||
if (METHOD_HEAD.equals(request.getMethod())) {
|
||||
|
@@ -9,6 +9,13 @@ package org.dspace.app.rest.utils;
|
||||
|
||||
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -23,6 +30,7 @@ import org.dspace.app.rest.model.RestAddressableModel;
|
||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||
import org.dspace.app.rest.repository.LinkRestRepository;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -31,6 +39,7 @@ import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.Link;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
/**
|
||||
* Collection of utility methods
|
||||
@@ -155,4 +164,59 @@ public class Utils {
|
||||
public String getMetadataKey(String schema, String element, String qualifier) {
|
||||
return org.dspace.core.Utils.standardize(schema, element, qualifier, ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a temporary file from a multipart file upload
|
||||
*
|
||||
* @param multipartFile
|
||||
* the multipartFile representing the uploaded file. Please note that it is a complex object including
|
||||
* additional information other than the binary like the orginal file name and the mimetype
|
||||
* @param prefixTempName
|
||||
* the prefix to use to generate the filename of the temporary file
|
||||
* @param suffixTempName
|
||||
* the suffic to use to generate the filename of the temporary file
|
||||
* @return the temporary file on the server
|
||||
* @throws IOException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static File getFile(MultipartFile multipartFile, String prefixTempName, String suffixTempName)
|
||||
throws IOException, FileNotFoundException {
|
||||
// TODO after change item-submission into
|
||||
String tempDir = (ConfigurationManager.getProperty("upload.temp.dir") != null)
|
||||
? ConfigurationManager.getProperty("upload.temp.dir")
|
||||
: System.getProperty("java.io.tmpdir");
|
||||
File uploadDir = new File(tempDir);
|
||||
if (!uploadDir.exists()) {
|
||||
if (!uploadDir.mkdir()) {
|
||||
uploadDir = null;
|
||||
}
|
||||
}
|
||||
File file = File.createTempFile(prefixTempName + "-" + suffixTempName, ".temp", uploadDir);
|
||||
InputStream io = new BufferedInputStream(multipartFile.getInputStream());
|
||||
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
|
||||
org.dspace.core.Utils.bufferedCopy(io, out);
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filename part from a multipartFile upload that could eventually contains the fullpath on the client
|
||||
* filesystem
|
||||
*
|
||||
* @param multipartFile
|
||||
* the file uploaded
|
||||
* @return the filename part of the file on the client filesystem
|
||||
* @throws IOException
|
||||
* @throws FileNotFoundException
|
||||
*/
|
||||
public static String getFileName(MultipartFile multipartFile)
|
||||
throws IOException, FileNotFoundException {
|
||||
String originalFilename = multipartFile.getOriginalFilename();
|
||||
if (originalFilename != null) {
|
||||
// split by \ or / as we don't know the client OS (Win, Linux)
|
||||
String[] parts = originalFilename.split("[\\/]");
|
||||
return parts[parts.length - 1];
|
||||
} else {
|
||||
return multipartFile.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,13 +7,55 @@
|
||||
*/
|
||||
HAL.Http.Client = function(opts) {
|
||||
this.vent = opts.vent;
|
||||
this.defaultHeaders = { 'Accept': 'application/hal+json, application/json, */*; q=0.01' };
|
||||
cookie = document.cookie.match('(^|;)\\s*' + 'MyHalBrowserToken' + '\\s*=\\s*([^;]+)');
|
||||
cookie ? this.defaultHeaders.Authorization = 'Bearer ' + cookie.pop() : '';
|
||||
this.defaultHeaders = {'Accept': 'application/hal+json, application/json, */*; q=0.01'};
|
||||
var authorizationHeader = getAuthorizationHeader();
|
||||
authorizationHeader ? this.defaultHeaders.Authorization = authorizationHeader : '';
|
||||
console.log(this.defaultHeaders);
|
||||
this.headers = this.defaultHeaders;
|
||||
};
|
||||
|
||||
function getAuthorizationHeader() {
|
||||
var cookie = document.cookie.match('(^|;)\\s*' + 'MyHalBrowserToken' + '\\s*=\\s*([^;]+)');
|
||||
if(cookie != undefined) {
|
||||
return 'Bearer ' + cookie.pop();
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
function downloadFile(url) {
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('GET', url, true);
|
||||
request.responseType = 'blob';
|
||||
var authorizationHeader = getAuthorizationHeader();
|
||||
if (authorizationHeader != undefined) {
|
||||
request.setRequestHeader("Authorization", authorizationHeader);
|
||||
}
|
||||
request.onload = function () {
|
||||
// Only handle status code 200
|
||||
if (request.status === 200) {
|
||||
// Try to find out the filename from the content disposition `filename` value
|
||||
var disposition = request.getResponseHeader('content-disposition');
|
||||
var matches = /"([^"]*)"/.exec(disposition);
|
||||
var filename = (matches != null && matches[1] ? matches[1] : 'content');
|
||||
// The actual download
|
||||
var contentTypeHeader = request.getResponseHeader("content-type");
|
||||
if (contentTypeHeader === undefined || contentTypeHeader === "") {
|
||||
contentTypeHeader = "application/octet-stream";
|
||||
}
|
||||
var blob = new Blob([request.response], {type: contentTypeHeader});
|
||||
var link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
// some error handling should be done here...
|
||||
};
|
||||
request.send();
|
||||
}
|
||||
|
||||
|
||||
HAL.Http.Client.prototype.get = function(url) {
|
||||
var self = this;
|
||||
this.vent.trigger('location-change', { url: url });
|
||||
@@ -31,9 +73,14 @@ HAL.Http.Client.prototype.get = function(url) {
|
||||
headers: jqXHR.getAllResponseHeaders()
|
||||
});
|
||||
}
|
||||
}).error(function() {
|
||||
self.vent.trigger('fail-response', { jqxhr: jqxhr });
|
||||
});
|
||||
}).error(function (response) {
|
||||
self.vent.trigger('fail-response', {jqxhr: jqxhr});
|
||||
var contentTypeResponseHeader = jqxhr.getResponseHeader("content-type");
|
||||
if (contentTypeResponseHeader != undefined
|
||||
&& !contentTypeResponseHeader.startsWith("application/hal")
|
||||
&& !contentTypeResponseHeader.startsWith("application/json")) {
|
||||
downloadFile(url);
|
||||
}});
|
||||
};
|
||||
|
||||
HAL.Http.Client.prototype.request = function(opts) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user