Il seguente frammento di schema specifica il contenuto previsto contenuto in questa classe.
+ *
+ *
> nameOrNamespace;
+
+ /**
+ * Gets the value of the nameOrNamespace property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set
method for the nameOrNamespace property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getNameOrNamespace().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ public List> getNameOrNamespace() {
+ if (nameOrNamespace == null) {
+ nameOrNamespace = new ArrayList>();
+ }
+ return this.nameOrNamespace;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcSchemaBuilder.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcSchemaBuilder.java
new file mode 100644
index 000000000000..fe7144bda854
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcSchemaBuilder.java
@@ -0,0 +1,39 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.metadata.export.model;
+
+import javax.xml.bind.JAXBElement;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class DcSchemaBuilder extends AbstractJaxbBuilder {
+
+ protected DcSchemaBuilder() {
+ super(DcSchema.class);
+ }
+
+ public static DcSchemaBuilder createBuilder() {
+ return new DcSchemaBuilder();
+ }
+
+ public DcSchemaBuilder withName(String name) {
+ this.addChildElement(name, objectFactory::createName);
+ return this;
+ }
+
+ public DcSchemaBuilder withNamespace(String namespace) {
+ this.addChildElement(namespace, objectFactory::createNamespace);
+ return this;
+ }
+
+ @Override
+ protected void addChildElement(JAXBElement v) {
+ getObejct().getNameOrNamespace().add(v);
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcType.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcType.java
new file mode 100644
index 000000000000..bff2fc77978a
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcType.java
@@ -0,0 +1,86 @@
+/**
+ * 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.metadata.export.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementRefs;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Classe Java per anonymous complex type.
+ *
+ *
Il seguente frammento di schema specifica il contenuto previsto contenuto in questa classe.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <choice maxOccurs="unbounded" minOccurs="0">
+ * <element ref="{}schema"/>
+ * <element ref="{}element"/>
+ * <element ref="{}qualifier"/>
+ * <element ref="{}scope_note"/>
+ * </choice>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "schemaOrElementOrQualifier"
+})
+@XmlRootElement(name = "dc-type")
+public class DcType {
+
+ @XmlElementRefs({
+ @XmlElementRef(name = "schema", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "element", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "qualifier", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "scope_note", type = JAXBElement.class, required = false)
+ })
+ protected List> schemaOrElementOrQualifier;
+
+ /**
+ * Gets the value of the schemaOrElementOrQualifier property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set
method for the schemaOrElementOrQualifier property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getSchemaOrElementOrQualifier().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ public List> getSchemaOrElementOrQualifier() {
+ if (schemaOrElementOrQualifier == null) {
+ schemaOrElementOrQualifier = new ArrayList>();
+ }
+ return this.schemaOrElementOrQualifier;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcTypeBuilder.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcTypeBuilder.java
new file mode 100644
index 000000000000..47fd64763ead
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DcTypeBuilder.java
@@ -0,0 +1,49 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.metadata.export.model;
+
+import javax.xml.bind.JAXBElement;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class DcTypeBuilder extends AbstractJaxbBuilder {
+
+ protected DcTypeBuilder() {
+ super(DcType.class);
+ }
+
+ public static DcTypeBuilder createBuilder() {
+ return new DcTypeBuilder();
+ }
+
+ public DcTypeBuilder withSchema(String schema) {
+ addChildElement(schema, objectFactory::createSchema);
+ return this;
+ }
+
+ public DcTypeBuilder withElement(String element) {
+ addChildElement(element, objectFactory::createElement);
+ return this;
+ }
+
+ public DcTypeBuilder withQualifier(String qualifier) {
+ addChildElement(qualifier, objectFactory::createQualifier);
+ return this;
+ }
+
+ public DcTypeBuilder withScopeNote(String scopeNote) {
+ addChildElement(scopeNote, objectFactory::createScopeNote);
+ return this;
+ }
+
+ @Override
+ protected void addChildElement(JAXBElement v) {
+ getObejct().getSchemaOrElementOrQualifier().add(v);
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypes.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypes.java
new file mode 100644
index 000000000000..4cba081a8a30
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypes.java
@@ -0,0 +1,82 @@
+/**
+ * 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.metadata.export.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Classe Java per anonymous complex type.
+ *
+ *
Il seguente frammento di schema specifica il contenuto previsto contenuto in questa classe.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <choice maxOccurs="unbounded" minOccurs="0">
+ * <element ref="{}dspace-header"/>
+ * <element ref="{}dc-schema"/>
+ * <element ref="{}dc-type"/>
+ * </choice>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "dspaceHeaderOrDcSchemaOrDcType"
+})
+@XmlRootElement(name = "dspace-dc-types")
+public class DspaceDcTypes {
+
+ @XmlElements({
+ @XmlElement(name = "dspace-header", type = DspaceHeader.class),
+ @XmlElement(name = "dc-schema", type = DcSchema.class),
+ @XmlElement(name = "dc-type", type = DcType.class)
+ })
+ protected List dspaceHeaderOrDcSchemaOrDcType;
+
+ /**
+ * Gets the value of the dspaceHeaderOrDcSchemaOrDcType property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set
method for the dspaceHeaderOrDcSchemaOrDcType property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getDspaceHeaderOrDcSchemaOrDcType().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link DspaceHeader }
+ * {@link DcSchema }
+ * {@link DcType }
+ */
+ public List getDspaceHeaderOrDcSchemaOrDcType() {
+ if (dspaceHeaderOrDcSchemaOrDcType == null) {
+ dspaceHeaderOrDcSchemaOrDcType = new ArrayList();
+ }
+ return this.dspaceHeaderOrDcSchemaOrDcType;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypesBuilder.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypesBuilder.java
new file mode 100644
index 000000000000..1e4cdb83393c
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceDcTypesBuilder.java
@@ -0,0 +1,59 @@
+/**
+ * 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.metadata.export.model;
+
+import java.util.Collection;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class DspaceDcTypesBuilder {
+
+ private DspaceDcTypes dcTypes;
+
+ private final ObjectFactory objectFactory = new ObjectFactory();
+
+ private DspaceDcTypes getDcTypes() {
+ if (dcTypes == null) {
+ dcTypes = new DspaceDcTypes();
+ }
+ return dcTypes;
+ }
+
+ private DspaceDcTypesBuilder() {
+ }
+
+ public static DspaceDcTypesBuilder createBuilder() {
+ return new DspaceDcTypesBuilder();
+ }
+
+ public DspaceDcTypesBuilder witheader(DspaceHeader header) {
+ this.getDcTypes().getDspaceHeaderOrDcSchemaOrDcType().add(header);
+ return this;
+ }
+
+ public DspaceDcTypesBuilder withSchema(DcSchema schema) {
+ this.getDcTypes().getDspaceHeaderOrDcSchemaOrDcType().add(schema);
+ return this;
+ }
+
+ public DspaceDcTypesBuilder withDcType(DcType dcType) {
+ this.getDcTypes().getDspaceHeaderOrDcSchemaOrDcType().add(dcType);
+ return this;
+ }
+
+ public DspaceDcTypesBuilder withDcTypes(Collection dcTypes) {
+ this.getDcTypes().getDspaceHeaderOrDcSchemaOrDcType().addAll(dcTypes);
+ return this;
+ }
+
+ public DspaceDcTypes build() {
+ return dcTypes;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeader.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeader.java
new file mode 100644
index 000000000000..151c8b28292d
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeader.java
@@ -0,0 +1,92 @@
+/**
+ * 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.metadata.export.model;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementRefs;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Classe Java per anonymous complex type.
+ *
+ *
Il seguente frammento di schema specifica il contenuto previsto contenuto in questa classe.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <choice maxOccurs="unbounded" minOccurs="0">
+ * <element ref="{}title"/>
+ * <element ref="{}contributor.author"/>
+ * <element ref="{}contributor.editor"/>
+ * <element ref="{}date.created"/>
+ * <element ref="{}description"/>
+ * <element ref="{}description.version"/>
+ * </choice>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+ "titleOrContributorAuthorOrContributorEditor"
+})
+@XmlRootElement(name = "dspace-header")
+public class DspaceHeader {
+
+ @XmlElementRefs({
+ @XmlElementRef(name = "title", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "contributor.author", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "contributor.editor", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "date.created", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "description", type = JAXBElement.class, required = false),
+ @XmlElementRef(name = "description.version", type = JAXBElement.class, required = false)
+ })
+ protected List> titleOrContributorAuthorOrContributorEditor;
+
+ /**
+ * Gets the value of the titleOrContributorAuthorOrContributorEditor property.
+ *
+ *
+ * This accessor method returns a reference to the live list,
+ * not a snapshot. Therefore any modification you make to the
+ * returned list will be present inside the JAXB object.
+ * This is why there is not a set
method for the titleOrContributorAuthorOrContributorEditor property.
+ *
+ *
+ * For example, to add a new item, do as follows:
+ *
+ * getTitleOrContributorAuthorOrContributorEditor().add(newItem);
+ *
+ *
+ *
+ *
+ * Objects of the following type(s) are allowed in the list
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ * {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ public List> getTitleOrContributorAuthorOrContributorEditor() {
+ if (titleOrContributorAuthorOrContributorEditor == null) {
+ titleOrContributorAuthorOrContributorEditor = new ArrayList>();
+ }
+ return this.titleOrContributorAuthorOrContributorEditor;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeaderBuilder.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeaderBuilder.java
new file mode 100644
index 000000000000..fb4028a2057b
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/DspaceHeaderBuilder.java
@@ -0,0 +1,59 @@
+/**
+ * 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.metadata.export.model;
+
+import javax.xml.bind.JAXBElement;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class DspaceHeaderBuilder extends AbstractJaxbBuilder {
+
+ protected DspaceHeaderBuilder() {
+ super(DspaceHeader.class);
+ }
+
+ public static DspaceHeaderBuilder createBuilder() {
+ return new DspaceHeaderBuilder();
+ }
+
+ public DspaceHeaderBuilder withTitle(String title) {
+ addChildElement(title, objectFactory::createTitle);
+ return this;
+ }
+
+ public DspaceHeaderBuilder withContributorAuthor(String contributorAuthor) {
+ addChildElement(contributorAuthor, objectFactory::createContributorAuthor);
+ return this;
+ }
+
+ public DspaceHeaderBuilder withContributorEditor(String contributorEditor) {
+ addChildElement(contributorEditor, objectFactory::createContributorEditor);
+ return this;
+ }
+
+ public DspaceHeaderBuilder withDateCreated(String dateCreated) {
+ addChildElement(dateCreated, objectFactory::createDateCreated);
+ return this;
+ }
+
+ public DspaceHeaderBuilder withDescription(String description) {
+ addChildElement(description, objectFactory::createDescription);
+ return this;
+ }
+
+ public DspaceHeaderBuilder withDescriptionVersion(String descriptionVersion) {
+ addChildElement(descriptionVersion, objectFactory::createDescriptionVersion);
+ return this;
+ }
+
+ @Override
+ protected void addChildElement(JAXBElement v) {
+ getObejct().getTitleOrContributorAuthorOrContributorEditor().add(v);
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/model/ObjectFactory.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/ObjectFactory.java
new file mode 100644
index 000000000000..085e8af5f81b
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/model/ObjectFactory.java
@@ -0,0 +1,212 @@
+/**
+ * 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.metadata.export.model;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+
+/**
+ * This object contains factory methods for each
+ * Java content interface and Java element interface
+ * generated in the org.dspace.app.metadata.export.model package.
+ * An ObjectFactory allows you to programatically
+ * construct new instances of the Java representation
+ * for XML content. The Java representation of XML
+ * content can consist of schema derived interfaces
+ * and classes representing the binding of schema
+ * type definitions, element declarations and model
+ * groups. Factory methods for each of these are
+ * provided in this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final static QName _Title_QNAME = new QName("", "title");
+ private final static QName _ContributorAuthor_QNAME = new QName("", "contributor.author");
+ private final static QName _ContributorEditor_QNAME = new QName("", "contributor.editor");
+ private final static QName _DateCreated_QNAME = new QName("", "date.created");
+ private final static QName _Description_QNAME = new QName("", "description");
+ private final static QName _DescriptionVersion_QNAME = new QName("", "description.version");
+ private final static QName _Name_QNAME = new QName("", "name");
+ private final static QName _Namespace_QNAME = new QName("", "namespace");
+ private final static QName _Schema_QNAME = new QName("", "schema");
+ private final static QName _Element_QNAME = new QName("", "element");
+ private final static QName _Qualifier_QNAME = new QName("", "qualifier");
+ private final static QName _ScopeNote_QNAME = new QName("", "scope_note");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org
+ * .dspace.app.metadata.export.model
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link DspaceDcTypes }
+ */
+ public DspaceDcTypes createDspaceDcTypes() {
+ return new DspaceDcTypes();
+ }
+
+ /**
+ * Create an instance of {@link DspaceHeader }
+ */
+ public DspaceHeader createDspaceHeader() {
+ return new DspaceHeader();
+ }
+
+ /**
+ * Create an instance of {@link DcSchema }
+ */
+ public DcSchema createDcSchema() {
+ return new DcSchema();
+ }
+
+ /**
+ * Create an instance of {@link DcType }
+ */
+ public DcType createDcType() {
+ return new DcType();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "title")
+ public JAXBElement createTitle(String value) {
+ return new JAXBElement(_Title_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "contributor.author")
+ public JAXBElement createContributorAuthor(String value) {
+ return new JAXBElement(_ContributorAuthor_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "contributor.editor")
+ public JAXBElement createContributorEditor(String value) {
+ return new JAXBElement(_ContributorEditor_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "date.created")
+ public JAXBElement createDateCreated(String value) {
+ return new JAXBElement(_DateCreated_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "description")
+ public JAXBElement createDescription(String value) {
+ return new JAXBElement(_Description_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "description.version")
+ public JAXBElement createDescriptionVersion(String value) {
+ return new JAXBElement(_DescriptionVersion_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "name")
+ public JAXBElement createName(String value) {
+ return new JAXBElement(_Name_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "namespace")
+ public JAXBElement createNamespace(String value) {
+ return new JAXBElement(_Namespace_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "schema")
+ public JAXBElement createSchema(String value) {
+ return new JAXBElement(_Schema_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "element")
+ public JAXBElement createElement(String value) {
+ return new JAXBElement(_Element_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "qualifier")
+ public JAXBElement createQualifier(String value) {
+ return new JAXBElement(_Qualifier_QNAME, String.class, null, value);
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ *
+ * @param value Java instance representing xml element's value.
+ * @return the new instance of {@link JAXBElement }{@code <}{@link String }{@code >}
+ */
+ @XmlElementDecl(namespace = "", name = "scope_note")
+ public JAXBElement createScopeNote(String value) {
+ return new JAXBElement(_ScopeNote_QNAME, String.class, null, value);
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactory.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactory.java
new file mode 100644
index 000000000000..3553cbcba2fd
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactory.java
@@ -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.metadata.export.service;
+
+import org.dspace.services.factory.DSpaceServicesFactory;
+
+/**
+ * Factory for the export services related to metadata-schema and metadata-fields.
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public abstract class MetadataExportServiceFactory {
+
+ public static MetadataExportServiceFactory getInstance() {
+ return DSpaceServicesFactory
+ .getInstance().getServiceManager()
+ .getServiceByName("metadataExportServiceFactory", MetadataExportServiceFactory.class);
+ }
+
+ public abstract MetadataSchemaExportService getMetadataSchemaExportService();
+ public abstract MetadataFieldExportService getMetadataFieldExportService();
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactoryImpl.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactoryImpl.java
new file mode 100644
index 000000000000..a69d5dfd0fde
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataExportServiceFactoryImpl.java
@@ -0,0 +1,31 @@
+/**
+ * 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.metadata.export.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class MetadataExportServiceFactoryImpl extends MetadataExportServiceFactory {
+
+ @Autowired
+ private MetadataSchemaExportService metadataSchemaExportService;
+ @Autowired
+ private MetadataFieldExportService metadataFieldExportService;
+
+ @Override
+ public MetadataSchemaExportService getMetadataSchemaExportService() {
+ return metadataSchemaExportService;
+ }
+
+ @Override
+ public MetadataFieldExportService getMetadataFieldExportService() {
+ return metadataFieldExportService;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportService.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportService.java
new file mode 100644
index 000000000000..ace312885230
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportService.java
@@ -0,0 +1,35 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.metadata.export.service;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.dspace.app.metadata.export.model.DcType;
+import org.dspace.content.MetadataField;
+import org.dspace.content.MetadataSchema;
+import org.dspace.core.Context;
+
+/**
+ * Exports {@code MetadataField} into {@code DcType}
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public interface MetadataFieldExportService {
+
+ /**
+ * Creates a one {@link DCType} for each {@link MetadataField}
+ * in the given {@link MetadataSchema}, and returns them in a list
+ *
+ * @param context
+ * @param metadataSchema
+ * @return
+ * @throws SQLException
+ */
+ List exportMetadataFieldsBy(Context context, MetadataSchema metadataSchema) throws SQLException;
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportServiceImpl.java
new file mode 100644
index 000000000000..1ace35f4e45d
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataFieldExportServiceImpl.java
@@ -0,0 +1,49 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.metadata.export.service;
+
+import java.sql.SQLException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.dspace.app.metadata.export.model.DcType;
+import org.dspace.app.metadata.export.model.DcTypeBuilder;
+import org.dspace.content.MetadataField;
+import org.dspace.content.MetadataSchema;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.MetadataFieldService;
+import org.dspace.core.Context;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class MetadataFieldExportServiceImpl implements MetadataFieldExportService {
+
+ private MetadataFieldService metadataFieldService =
+ ContentServiceFactory.getInstance().getMetadataFieldService();
+
+ public List exportMetadataFieldsBy(Context context, MetadataSchema metadataSchema) throws SQLException {
+ return metadataFieldService
+ .findAllInSchema(context, metadataSchema)
+ .stream()
+ .map(this::toDcType)
+ .collect(Collectors.toList());
+ }
+
+ private DcType toDcType(MetadataField metadataField) {
+ return DcTypeBuilder
+ .createBuilder()
+ .withSchema(metadataField.getMetadataSchema().getName())
+ .withElement(metadataField.getElement())
+ .withQualifier(metadataField.getQualifier())
+ .withScopeNote(metadataField.getScopeNote())
+ .build();
+ }
+
+}
+
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportService.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportService.java
new file mode 100644
index 000000000000..cd1f35e2ef9b
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportService.java
@@ -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.metadata.export.service;
+
+import java.io.File;
+import java.sql.SQLException;
+
+import org.dspace.app.metadata.export.DspaceExportMetadataSchemaException;
+import org.dspace.app.metadata.export.model.DspaceDcTypes;
+import org.dspace.content.MetadataSchema;
+import org.dspace.core.Context;
+
+/**
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public interface MetadataSchemaExportService {
+
+ /**
+ * Exports the given {@code schemaId} into a {@link DspaceDcTypes} entity
+ *
+ * @param context
+ * @param schemaId
+ * @return
+ * @throws SQLException
+ */
+ DspaceDcTypes exportMetadataSchema(Context context, int schemaId) throws SQLException;
+
+ /**
+ * Exports the given {@code metadataSchema} into a {@link DspaceDcTypes} entity
+ *
+ * @param context
+ * @param metadataSchema
+ * @return
+ * @throws SQLException
+ */
+ DspaceDcTypes exportMetadataSchema(Context context, MetadataSchema metadataSchema) throws SQLException;
+
+ /**
+ * Exports the given {@code metadataSchema} to a temporary {@code File},
+ * that will respect the {@code registry} xml format of dspace
+ *
+ * @param context
+ * @param metadataSchema
+ * @return
+ * @throws DspaceExportMetadataSchemaException
+ */
+ File exportMetadataSchemaToFile(Context context, MetadataSchema metadataSchema)
+ throws DspaceExportMetadataSchemaException;
+
+ /**
+ * Exports the given {@code metadataSchema} to a target {@code File},
+ * that will respect the {@code registry} xml format of dspace
+ *
+ * @param context
+ * @param metadataSchema
+ * @param file
+ * @return
+ * @throws DspaceExportMetadataSchemaException
+ */
+ File exportMetadataSchemaToFile(Context context, MetadataSchema metadataSchema, File file)
+ throws DspaceExportMetadataSchemaException;
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportServiceImpl.java
new file mode 100644
index 000000000000..eea9a09f7970
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/metadata/export/service/MetadataSchemaExportServiceImpl.java
@@ -0,0 +1,107 @@
+/**
+ * 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.metadata.export.service;
+
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+
+import org.dspace.app.metadata.export.DspaceExportMetadataSchemaException;
+import org.dspace.app.metadata.export.model.DcSchema;
+import org.dspace.app.metadata.export.model.DcSchemaBuilder;
+import org.dspace.app.metadata.export.model.DspaceDcTypes;
+import org.dspace.app.metadata.export.model.DspaceDcTypesBuilder;
+import org.dspace.content.MetadataSchema;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.MetadataSchemaService;
+import org.dspace.core.Context;
+
+/**
+ * This service can be used to export a target schema into a registry-file
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class MetadataSchemaExportServiceImpl implements MetadataSchemaExportService {
+
+ private MetadataSchemaService metadataSchemaService =
+ ContentServiceFactory.getInstance().getMetadataSchemaService();
+
+ @Override
+ public DspaceDcTypes exportMetadataSchema(Context context, int schemaId) throws SQLException {
+ return this.exportMetadataSchema(context, metadataSchemaService.find(context, schemaId));
+ }
+
+ @Override
+ public DspaceDcTypes exportMetadataSchema(Context context, MetadataSchema metadataSchema) throws SQLException {
+ return DspaceDcTypesBuilder
+ .createBuilder()
+ .withSchema(this.mapToDcSchema(metadataSchema))
+ .withDcTypes(
+ MetadataExportServiceFactory.getInstance()
+ .getMetadataFieldExportService()
+ .exportMetadataFieldsBy(context, metadataSchema)
+ )
+ .build();
+ }
+
+ @Override
+ public File exportMetadataSchemaToFile(Context context, MetadataSchema metadataSchema)
+ throws DspaceExportMetadataSchemaException {
+ File tempFile;
+ try {
+ tempFile =
+ File.createTempFile(
+ metadataSchema.getName() + "-" + metadataSchema.getID(),
+ ".xml"
+ );
+ tempFile.deleteOnExit();
+ return this.exportMetadataSchemaToFile(context, metadataSchema, tempFile);
+ } catch (IOException e) {
+ throw new DspaceExportMetadataSchemaException(
+ "Probelm occured during while exporting to temporary file!",
+ e
+ );
+ }
+ }
+
+ @Override
+ public File exportMetadataSchemaToFile(Context context, MetadataSchema metadataSchema, File file)
+ throws DspaceExportMetadataSchemaException {
+ try {
+ DspaceDcTypes dspaceDcTypes = this.exportMetadataSchema(context, metadataSchema);
+
+ JAXBContext jaxb = JAXBContext.newInstance(DspaceDcTypes.class);
+ Marshaller jaxbMarshaller = jaxb.createMarshaller();
+ jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ jaxbMarshaller.marshal(dspaceDcTypes, file);
+ } catch (SQLException e) {
+ throw new DspaceExportMetadataSchemaException(
+ "Problem occured while retrieving data from DB!",
+ e
+ );
+ } catch (JAXBException e) {
+ throw new DspaceExportMetadataSchemaException(
+ "Problem occured during the export to XML file!",
+ e
+ );
+ }
+ return file;
+ }
+
+ private DcSchema mapToDcSchema(MetadataSchema metadataSchema) {
+ return DcSchemaBuilder
+ .createBuilder()
+ .withName(metadataSchema.getName())
+ .withNamespace(metadataSchema.getNamespace())
+ .build();
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
index 384f33decaf2..6499c45a7830 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/RequestItemEmailNotifier.java
@@ -11,55 +11,59 @@
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
+import javax.annotation.ManagedBean;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import javax.mail.MessagingException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-import org.dspace.app.requestitem.factory.RequestItemServiceFactory;
import org.dspace.app.requestitem.service.RequestItemService;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
-import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
import org.dspace.core.Email;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogHelper;
import org.dspace.eperson.EPerson;
-import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService;
-import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Send item requests and responses by email.
*
+ * The "strategy" by which approvers are chosen is in an implementation of
+ * {@link RequestItemAuthorExtractor} which is injected by the name
+ * {@code requestItemAuthorExtractor}. See the DI configuration documents.
+ *
* @author Mark H. Wood
*/
+@Singleton
+@ManagedBean
public class RequestItemEmailNotifier {
private static final Logger LOG = LogManager.getLogger();
- private static final BitstreamService bitstreamService
- = ContentServiceFactory.getInstance().getBitstreamService();
+ @Inject
+ protected BitstreamService bitstreamService;
- private static final ConfigurationService configurationService
- = DSpaceServicesFactory.getInstance().getConfigurationService();
+ @Inject
+ protected ConfigurationService configurationService;
- private static final HandleService handleService
- = HandleServiceFactory.getInstance().getHandleService();
+ @Inject
+ protected HandleService handleService;
- private static final RequestItemService requestItemService
- = RequestItemServiceFactory.getInstance().getRequestItemService();
+ @Inject
+ protected RequestItemService requestItemService;
- private static final RequestItemAuthorExtractor requestItemAuthorExtractor
- = DSpaceServicesFactory.getInstance()
- .getServiceManager()
- .getServiceByName("requestItemAuthorExtractor",
- RequestItemAuthorExtractor.class);
+ protected final RequestItemAuthorExtractor requestItemAuthorExtractor;
- private RequestItemEmailNotifier() {}
+ @Inject
+ public RequestItemEmailNotifier(RequestItemAuthorExtractor requestItemAuthorExtractor) {
+ this.requestItemAuthorExtractor = requestItemAuthorExtractor;
+ }
/**
* Send the request to the approver(s).
@@ -70,7 +74,7 @@ private RequestItemEmailNotifier() {}
* @throws IOException passed through.
* @throws SQLException if the message was not sent.
*/
- static public void sendRequest(Context context, RequestItem ri, String responseLink)
+ public void sendRequest(Context context, RequestItem ri, String responseLink)
throws IOException, SQLException {
// Who is making this request?
List authors = requestItemAuthorExtractor
@@ -147,12 +151,38 @@ static public void sendRequest(Context context, RequestItem ri, String responseL
* @param message email body (may be empty).
* @throws IOException if sending failed.
*/
- static public void sendResponse(Context context, RequestItem ri, String subject,
+ public void sendResponse(Context context, RequestItem ri, String subject,
String message)
throws IOException {
+ // Who granted this request?
+ List grantors;
+ try {
+ grantors = requestItemAuthorExtractor.getRequestItemAuthor(context, ri.getItem());
+ } catch (SQLException e) {
+ LOG.warn("Failed to get grantor's name and address: {}", e.getMessage());
+ grantors = List.of();
+ }
+
+ String grantorName;
+ String grantorAddress;
+ if (grantors.isEmpty()) {
+ grantorName = configurationService.getProperty("mail.admin.name");
+ grantorAddress = configurationService.getProperty("mail.admin");
+ } else {
+ RequestItemAuthor grantor = grantors.get(0); // XXX Cannot know which one
+ grantorName = grantor.getFullName();
+ grantorAddress = grantor.getEmail();
+ }
+
// Build an email back to the requester.
- Email email = new Email();
- email.setContent("body", message);
+ Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
+ ri.isAccept_request() ? "request_item.granted" : "request_item.rejected"));
+ email.addArgument(ri.getReqName()); // {0} requestor's name
+ email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle())); // {1} URL of the requested Item
+ email.addArgument(ri.getItem().getName()); // {2} title of the requested Item
+ email.addArgument(grantorName); // {3} name of the grantor
+ email.addArgument(grantorAddress); // {4} email of the grantor
+ email.addArgument(message); // {5} grantor's optional message
email.setSubject(subject);
email.addRecipient(ri.getReqEmail());
// Attach bitstreams.
@@ -167,17 +197,25 @@ static public void sendResponse(Context context, RequestItem ri, String subject,
if (!bitstream.getFormat(context).isInternal() &&
requestItemService.isRestricted(context,
bitstream)) {
- email.addAttachment(bitstreamService.retrieve(context,
- bitstream), bitstream.getName(),
+ // #8636 Anyone receiving the email can respond to the
+ // request without authenticating into DSpace
+ context.turnOffAuthorisationSystem();
+ email.addAttachment(
+ bitstreamService.retrieve(context, bitstream),
+ bitstream.getName(),
bitstream.getFormat(context).getMIMEType());
+ context.restoreAuthSystemState();
}
}
}
} else {
Bitstream bitstream = ri.getBitstream();
+ // #8636 Anyone receiving the email can respond to the request without authenticating into DSpace
+ context.turnOffAuthorisationSystem();
email.addAttachment(bitstreamService.retrieve(context, bitstream),
bitstream.getName(),
bitstream.getFormat(context).getMIMEType());
+ context.restoreAuthSystemState();
}
email.send();
} else {
@@ -207,7 +245,7 @@ static public void sendResponse(Context context, RequestItem ri, String subject,
* @throws IOException if the message body cannot be loaded or the message
* cannot be sent.
*/
- static public void requestOpenAccess(Context context, RequestItem ri)
+ public void requestOpenAccess(Context context, RequestItem ri)
throws IOException {
Email message = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
"request_item.admin"));
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java
index 008174ded88c..a09a2bf250e5 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java
@@ -46,6 +46,6 @@ public RequestItem findByToken(Context context, String token) throws SQLExceptio
public Iterator findByItem(Context context, Item item) throws SQLException {
Query query = createQuery(context, "FROM RequestItem WHERE item_id= :uuid");
query.setParameter("uuid", item.getID());
- return iterate(query);
+ return iterate(context, query, RequestItem.class);
}
}
diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/package-info.java b/dspace-api/src/main/java/org/dspace/app/requestitem/package-info.java
index 5886f16fde1a..fa7c15b23060 100644
--- a/dspace-api/src/main/java/org/dspace/app/requestitem/package-info.java
+++ b/dspace-api/src/main/java/org/dspace/app/requestitem/package-info.java
@@ -12,10 +12,15 @@
* e-mailed to a responsible party for consideration and action. Find details
* in the user documentation under the rubric "Request a Copy".
*
- * This package includes several "strategy" classes which discover responsible
- * parties in various ways. See {@link RequestItemSubmitterStrategy} and the
- * classes which extend it. A strategy class must be configured and identified
- * as {@link RequestItemAuthorExtractor} for injection into code which requires
- * Request a Copy services.
+ *
Mailing is handled by {@link RequestItemEmailNotifier}. Responsible
+ * parties are represented by {@link RequestItemAuthor}
+ *
+ *
This package includes several "strategy" classes which discover
+ * responsible parties in various ways. See
+ * {@link RequestItemSubmitterStrategy} and the classes which extend it, and
+ * others which implement {@link RequestItemAuthorExtractor}. A strategy class
+ * must be configured and identified as {@link requestItemAuthorExtractor}
+ * (note capitalization ) for injection into code which requires Request
+ * a Copy services.
*/
package org.dspace.app.requestitem;
diff --git a/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java b/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java
index 6188272aca47..f3e651d7d26e 100644
--- a/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java
+++ b/dspace-api/src/main/java/org/dspace/app/sitemap/GenerateSitemaps.java
@@ -17,10 +17,7 @@
import java.net.URL;
import java.net.URLEncoder;
import java.sql.SQLException;
-import java.util.Date;
import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -28,29 +25,26 @@
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
-import org.dspace.app.customurl.CustomUrlService;
-import org.dspace.content.Collection;
-import org.dspace.content.Community;
-import org.dspace.content.Item;
-import org.dspace.content.factory.ContentServiceFactory;
-import org.dspace.content.service.CollectionService;
-import org.dspace.content.service.CommunityService;
-import org.dspace.content.service.ItemService;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
-import org.dspace.discovery.DiscoverQuery;
-import org.dspace.discovery.DiscoverResult;
import org.dspace.discovery.SearchService;
-import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils;
+import org.dspace.discovery.SolrSearchCore;
+import org.dspace.eperson.Group;
+import org.dspace.eperson.factory.EPersonServiceFactory;
+import org.dspace.eperson.service.GroupService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
-import org.dspace.utils.DSpace;
/**
* Command-line utility for generating HTML and Sitemaps.org protocol Sitemaps.
@@ -64,15 +58,11 @@ public class GenerateSitemaps {
*/
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(GenerateSitemaps.class);
- private static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
- private static final CollectionService collectionService =
- ContentServiceFactory.getInstance().getCollectionService();
- private static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private static final ConfigurationService configurationService =
DSpaceServicesFactory.getInstance().getConfigurationService();
private static final SearchService searchService = SearchUtils.getSearchService();
-
- private static final CustomUrlService customUrlService = new DSpace().getSingletonService(CustomUrlService.class);
+ private static final GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
+ private static final int PAGE_SIZE = 1000;
/**
* Default constructor
@@ -213,112 +203,127 @@ public static void generateSitemaps(boolean makeHTMLMap, boolean makeSitemapOrg)
}
Context c = new Context(Context.Mode.READ_ONLY);
-
- List comms = communityService.findAll(c);
-
- for (Community comm : comms) {
- String url = uiURLStem + "/communities/" + comm.getID();
-
- if (makeHTMLMap) {
- html.addURL(url, null);
- }
- if (makeSitemapOrg) {
- sitemapsOrg.addURL(url, null);
- }
-
- c.uncacheEntity(comm);
- }
-
- List colls = collectionService.findAll(c);
-
- for (Collection coll : colls) {
- String url = uiURLStem + "/collections/" + coll.getID();
-
- if (makeHTMLMap) {
- html.addURL(url, null);
- }
- if (makeSitemapOrg) {
- sitemapsOrg.addURL(url, null);
- }
-
- c.uncacheEntity(coll);
+ SolrSearchCore solrSearchCore = searchService.getSolrSearchCore();
+ SolrClient solr = solrSearchCore.getSolr();
+ Group anonymousGroup = groupService.findByName(c, Group.ANONYMOUS);
+ String anonGroupId = "";
+ if (anonymousGroup != null) {
+ anonGroupId = anonymousGroup.getID().toString();
}
- Iterator- allItems = itemService.findAll(c);
- int itemCount = 0;
-
- while (allItems.hasNext()) {
- Item i = allItems.next();
-
- Optional
customUrl = customUrlService.getCustomUrl(i);
- if (customUrl.isPresent()) {
-
- String url = uiURLStem + "/entities/" + StringUtils.lowerCase(itemService.getEntityTypeLabel(i))
- + "/" + customUrl.get();
-
- if (makeHTMLMap) {
- html.addURL(url, null);
+ try {
+ SolrQuery solrQuery = new SolrQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":Community");
+ solrQuery.addFilterQuery("read:g" + anonGroupId);
+ solrQuery.setFields(SearchUtils.RESOURCE_ID_FIELD);
+ solrQuery.setRows(PAGE_SIZE);
+ int offset = 0;
+ long commsCount = 0;
+ QueryResponse rsp;
+ do {
+ solrQuery.setStart(offset);
+ rsp = solr.query(solrQuery, solrSearchCore.REQUEST_METHOD);
+ SolrDocumentList docs = rsp.getResults();
+ commsCount = docs.getNumFound();
+ Iterator iter = docs.iterator();
+
+ while (iter.hasNext()) {
+ SolrDocument doc = (SolrDocument) iter.next();
+ String url = uiURLStem + "/communities/" + doc.getFieldValue(SearchUtils.RESOURCE_ID_FIELD);
+
+ if (makeHTMLMap) {
+ html.addURL(url, null);
+ }
+ if (makeSitemapOrg) {
+ sitemapsOrg.addURL(url, null);
+ }
}
- if (makeSitemapOrg) {
- sitemapsOrg.addURL(url, null);
+ offset += PAGE_SIZE;
+ } while (offset < commsCount);
+
+ solrQuery = new SolrQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":Collection");
+ solrQuery.addFilterQuery("read:g" + anonGroupId);
+ solrQuery.setFields(SearchUtils.RESOURCE_ID_FIELD);
+ solrQuery.setRows(PAGE_SIZE);
+ offset = 0;
+ long collsCount = 0;
+ do {
+ solrQuery.setStart(offset);
+ rsp = solr.query(solrQuery, solrSearchCore.REQUEST_METHOD);
+ SolrDocumentList docs = rsp.getResults();
+ collsCount = docs.getNumFound();
+ Iterator iter = docs.iterator();
+
+ while (iter.hasNext()) {
+ SolrDocument doc = (SolrDocument) iter.next();
+ String url = uiURLStem + "/collections/" + doc.getFieldValue(SearchUtils.RESOURCE_ID_FIELD);
+
+ if (makeHTMLMap) {
+ html.addURL(url, null);
+ }
+ if (makeSitemapOrg) {
+ sitemapsOrg.addURL(url, null);
+ }
}
+ offset += PAGE_SIZE;
+ } while (offset < collsCount);
+
+ solrQuery = new SolrQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":Item");
+ solrQuery.setFields(SearchUtils.RESOURCE_ID_FIELD, "customurl", "search.entitytype");
+ solrQuery.addFilterQuery("read:g" + anonGroupId);
+ solrQuery.addFilterQuery("-discoverable:false");
+ solrQuery.setRows(PAGE_SIZE);
+ offset = 0;
+ long itemsCount = 0;
+ do {
+ solrQuery.setStart(offset);
+ rsp = solr.query(solrQuery, solrSearchCore.REQUEST_METHOD);
+ SolrDocumentList docs = rsp.getResults();
+ itemsCount = docs.getNumFound();
+ Iterator iter = docs.iterator();
+
+ while (iter.hasNext()) {
+ SolrDocument doc = (SolrDocument) iter.next();
+ String uuid = (String) doc.getFirstValue(SearchUtils.RESOURCE_ID_FIELD);
+ String entityType = (String) doc.getFirstValue("search.entitytype");
+ String customUrl = (String) doc.getFirstValue("customUrl");
+ String url = uiURLStem + "/items/" + uuid;
+
+ if (StringUtils.isNotBlank(customUrl)) {
+ url = uiURLStem + "/entities/" + StringUtils.lowerCase(entityType) + "/" + customUrl;
+ } else if (StringUtils.isNoneBlank(entityType)) {
+ url = uiURLStem + "/entities/" + StringUtils.lowerCase(entityType) + "/" + uuid;
+ }
+ if (makeHTMLMap) {
+ html.addURL(url, null);
+ }
+ if (makeSitemapOrg) {
+ sitemapsOrg.addURL(url, null);
+ }
- }
-
- DiscoverQuery entityQuery = new DiscoverQuery();
- entityQuery.setQuery("search.uniqueid:\"Item-" + i.getID() + "\" and entityType:*");
- entityQuery.addSearchField("entityType");
-
- try {
- DiscoverResult discoverResult = searchService.search(c, entityQuery);
-
- String url;
- if (CollectionUtils.isNotEmpty(discoverResult.getIndexableObjects())
- && CollectionUtils.isNotEmpty(discoverResult.getSearchDocument(
- discoverResult.getIndexableObjects().get(0)).get(0).getSearchFieldValues("entityType"))
- && StringUtils.isNotBlank(discoverResult.getSearchDocument(
- discoverResult.getIndexableObjects().get(0)).get(0).getSearchFieldValues("entityType").get(0))
- ) {
- url = uiURLStem + "/entities/" + StringUtils.lowerCase(discoverResult.getSearchDocument(
- discoverResult.getIndexableObjects().get(0))
- .get(0).getSearchFieldValues("entityType").get(0)) + "/" + i.getID();
- } else {
- url = uiURLStem + "/items/" + i.getID();
}
- Date lastMod = i.getLastModified();
+ offset += PAGE_SIZE;
+ } while (offset < itemsCount);
- if (makeHTMLMap) {
- html.addURL(url, lastMod);
- }
- if (makeSitemapOrg) {
- sitemapsOrg.addURL(url, lastMod);
- }
- } catch (SearchServiceException e) {
- log.error("Failed getting entitytype through solr for item " + i.getID() + ": " + e.getMessage());
+ if (makeHTMLMap) {
+ int files = html.finish();
+ log.info(LogHelper.getHeader(c, "write_sitemap",
+ "type=html,num_files=" + files + ",communities="
+ + commsCount + ",collections=" + collsCount
+ + ",items=" + itemsCount));
}
- c.uncacheEntity(i);
-
- itemCount++;
- }
-
- if (makeHTMLMap) {
- int files = html.finish();
- log.info(LogHelper.getHeader(c, "write_sitemap",
- "type=html,num_files=" + files + ",communities="
- + comms.size() + ",collections=" + colls.size()
- + ",items=" + itemCount));
- }
-
- if (makeSitemapOrg) {
- int files = sitemapsOrg.finish();
- log.info(LogHelper.getHeader(c, "write_sitemap",
- "type=html,num_files=" + files + ",communities="
- + comms.size() + ",collections=" + colls.size()
- + ",items=" + itemCount));
+ if (makeSitemapOrg) {
+ int files = sitemapsOrg.finish();
+ log.info(LogHelper.getHeader(c, "write_sitemap",
+ "type=html,num_files=" + files + ",communities="
+ + commsCount + ",collections=" + collsCount
+ + ",items=" + itemsCount));
+ }
+ } catch (SolrServerException e) {
+ throw new RuntimeException(e);
+ } finally {
+ c.abort();
}
-
- c.abort();
}
/**
diff --git a/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCliScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCliScriptConfiguration.java
index b238ccf061f3..067c76cce8b3 100644
--- a/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCliScriptConfiguration.java
+++ b/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCliScriptConfiguration.java
@@ -8,7 +8,6 @@
package org.dspace.app.solrdatabaseresync;
import org.apache.commons.cli.Options;
-import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
/**
@@ -27,11 +26,6 @@ public void setDspaceRunnableClass(Class dspaceRunnableCl
this.dspaceRunnableClass = dspaceRunnableClass;
}
- @Override
- public boolean isAllowedToExecute(Context context) {
- return true;
- }
-
@Override
public Options getOptions() {
if (options == null) {
diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java
index aae042d0cf01..6feb1e247551 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputSet.java
@@ -103,9 +103,9 @@ public boolean isDefinedMultTitles() {
* @return true if the current set has all the prev. published fields
*/
public boolean isDefinedPubBefore() {
- return (isFieldPresent("dc.date.issued") &&
+ return isFieldPresent("dc.date.issued") &&
isFieldPresent("dc.identifier.citation") &&
- isFieldPresent("dc.publisher"));
+ isFieldPresent("dc.publisher");
}
/**
@@ -145,6 +145,9 @@ public Optional getField(String fieldName) {
} catch (DCInputsReaderException e) {
log.error(e.getMessage(), e);
}
+ } else if (field.isRelationshipField() &&
+ ("relation." + field.getRelationshipType()).equals(fieldName)) {
+ return Optional.of(field);
} else {
String fullName = field.getFieldName();
if (fullName.equals(fieldName)) {
diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
index ac8031880233..86b45c367941 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
@@ -316,6 +316,9 @@ public List getInputsByGroup(String formName)
// cache miss - construct new DCInputSet
List>> pages = formDefns.get(formName);
+ if (pages == null) {
+ return results;
+ }
Iterator>> iterator = pages.iterator();
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
index 8eb3a0674049..2f591b6e7a8c 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
@@ -7,8 +7,6 @@
*/
package org.dspace.app.util;
-import static org.dspace.content.Item.ANY;
-
import java.io.File;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -25,10 +23,12 @@
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.InProgressSubmission;
+import org.dspace.content.Item;
import org.dspace.content.edit.EditItem;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
+import org.dspace.discovery.SearchServiceException;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.w3c.dom.Document;
@@ -111,6 +111,13 @@ public class SubmissionConfigReader {
*/
private SubmissionConfig lastSubmissionConfig = null;
+ /**
+ * Collection Service instance, needed to interact with collection's
+ * stored data
+ */
+ protected static final CollectionService collectionService
+ = ContentServiceFactory.getInstance().getCollectionService();
+
/**
* Load Submission Configuration from the
* item-submission.xml configuration file
@@ -158,6 +165,9 @@ private void buildInputs(String fileName) throws SubmissionConfigReaderException
} catch (FactoryConfigurationError fe) {
throw new SubmissionConfigReaderException(
"Cannot create Item Submission Configuration parser", fe);
+ } catch (SearchServiceException se) {
+ throw new SubmissionConfigReaderException(
+ "Cannot perform a discovery search for Item Submission Configuration", se);
} catch (Exception e) {
throw new SubmissionConfigReaderException(
"Error creating Item Submission Configuration: " + e);
@@ -229,8 +239,10 @@ public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle)
public SubmissionConfig getCorrectionSubmissionConfigByCollection(Collection collection) {
CollectionService collService = ContentServiceFactory.getInstance().getCollectionService();
- String submitName = collService.getMetadataFirstValue(collection,
- "cris", "submission", "definition-correction", ANY);
+ String submitName =
+ collService.getMetadataFirstValue(
+ collection, "cris", "submission", "definition-correction", Item.ANY
+ );
if (submitName != null) {
SubmissionConfig subConfig = getSubmissionConfigByName(submitName);
@@ -377,7 +389,7 @@ public SubmissionStepConfig getStepConfig(String stepID)
* should correspond to the collection-form maps, the form definitions, and
* the display/storage word pairs.
*/
- private void doNodes(Node n) throws SAXException, SubmissionConfigReaderException {
+ private void doNodes(Node n) throws SAXException, SearchServiceException, SubmissionConfigReaderException {
if (n == null) {
return;
}
@@ -424,18 +436,23 @@ private void doNodes(Node n) throws SAXException, SubmissionConfigReaderExceptio
* the collection handle and item submission name, put name in hashmap keyed
* by the collection handle.
*/
- private void processMap(Node e) throws SAXException {
+ private void processMap(Node e) throws SAXException, SearchServiceException {
+ // create a context
+ Context context = new Context();
+
NodeList nl = e.getChildNodes();
int len = nl.getLength();
for (int i = 0; i < len; i++) {
Node nd = nl.item(i);
if (nd.getNodeName().equals("name-map")) {
String id = getAttribute(nd, "collection-handle");
+ String entityType = getAttribute(nd, "collection-entity-type");
String value = getAttribute(nd, "submission-name");
String content = getValue(nd);
- if (id == null) {
+ if (id == null && entityType == null) {
throw new SAXException(
- "name-map element is missing collection-handle attribute in 'item-submission.xml'");
+ "name-map element is missing collection-handle or collection-entity-type attribute " +
+ "in 'item-submission.xml'");
}
if (value == null) {
throw new SAXException(
@@ -445,7 +462,17 @@ private void processMap(Node e) throws SAXException {
throw new SAXException(
"name-map element has content in 'item-submission.xml', it should be empty.");
}
- collectionToSubmissionConfig.put(id, value);
+ if (id != null) {
+ collectionToSubmissionConfig.put(id, value);
+
+ } else {
+ // get all collections for this entity-type
+ List collections = collectionService.findAllCollectionsByEntityType( context,
+ entityType);
+ for (Collection collection : collections) {
+ collectionToSubmissionConfig.putIfAbsent(collection.getHandle(), value);
+ }
+ }
} // ignore any child node that isn't a "name-map"
}
}
@@ -739,4 +766,4 @@ public SubmissionConfig getSubmissionConfigByInProgressSubmission(InProgressSubm
return getSubmissionConfigByCollection(object.getCollection());
}
-}
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
index 8f155b63307d..c1402499c444 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
@@ -51,6 +51,7 @@
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
+import org.dspace.core.I18nUtil;
import org.dspace.discovery.IndexableObject;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.dspace.discovery.indexobject.IndexableCommunity;
@@ -91,6 +92,7 @@ public class SyndicationFeed {
// default DC fields for entry
protected String defaultTitleField = "dc.title";
+ protected String defaultDescriptionField = "dc.description";
protected String defaultAuthorField = "dc.contributor.author";
protected String defaultDateField = "dc.date.issued";
private static final String[] defaultDescriptionFields =
@@ -196,15 +198,15 @@ public void populate(HttpServletRequest request, Context context, IndexableObjec
// dso is null for the whole site, or a search without scope
if (dso == null) {
defaultTitle = configurationService.getProperty("dspace.name");
- feed.setDescription(localize(labels, MSG_FEED_DESCRIPTION));
+ defaultDescriptionField = localize(labels, MSG_FEED_DESCRIPTION);
objectURL = resolveURL(request, null);
} else {
Bitstream logo = null;
if (dso instanceof IndexableCollection) {
Collection col = ((IndexableCollection) dso).getIndexedObject();
defaultTitle = col.getName();
- feed.setDescription(collectionService.getMetadataFirstValue(col,
- CollectionService.MD_SHORT_DESCRIPTION, Item.ANY));
+ defaultDescriptionField = collectionService.getMetadataFirstValue(col,
+ CollectionService.MD_SHORT_DESCRIPTION, Item.ANY);
logo = col.getLogo();
String cols = configurationService.getProperty("webui.feed.podcast.collections");
if (cols != null && cols.length() > 1 && cols.contains(col.getHandle())) {
@@ -214,8 +216,8 @@ public void populate(HttpServletRequest request, Context context, IndexableObjec
} else if (dso instanceof IndexableCommunity) {
Community comm = ((IndexableCommunity) dso).getIndexedObject();
defaultTitle = comm.getName();
- feed.setDescription(communityService.getMetadataFirstValue(comm,
- CommunityService.MD_SHORT_DESCRIPTION, Item.ANY));
+ defaultDescriptionField = communityService.getMetadataFirstValue(comm,
+ CommunityService.MD_SHORT_DESCRIPTION, Item.ANY);
logo = comm.getLogo();
String comms = configurationService.getProperty("webui.feed.podcast.communities");
if (comms != null && comms.length() > 1 && comms.contains(comm.getHandle())) {
@@ -230,6 +232,12 @@ public void populate(HttpServletRequest request, Context context, IndexableObjec
}
feed.setTitle(labels.containsKey(MSG_FEED_TITLE) ?
localize(labels, MSG_FEED_TITLE) : defaultTitle);
+
+ if (defaultDescriptionField == null || defaultDescriptionField == "") {
+ defaultDescriptionField = I18nUtil.getMessage("org.dspace.app.util.SyndicationFeed.no-description");
+ }
+
+ feed.setDescription(defaultDescriptionField);
feed.setLink(objectURL);
feed.setPublishedDate(new Date());
feed.setUri(objectURL);
diff --git a/dspace-api/src/main/java/org/dspace/app/util/TypeBindUtils.java b/dspace-api/src/main/java/org/dspace/app/util/TypeBindUtils.java
new file mode 100644
index 000000000000..97104bbb63fe
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/util/TypeBindUtils.java
@@ -0,0 +1,73 @@
+/**
+ * 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.util;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.dspace.content.InProgressSubmission;
+import org.dspace.content.MetadataValue;
+import org.dspace.content.authority.factory.ContentAuthorityServiceFactory;
+import org.dspace.content.authority.service.MetadataAuthorityService;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.ItemService;
+import org.dspace.core.Constants;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+
+/**
+ * Utility methods for the type bind functionality.
+ *
+ * @author Francesco Pio Scognamiglio (francescopio.scognamiglio at 4science.com)
+ *
+ */
+public class TypeBindUtils {
+
+ private static final ConfigurationService configurationService = DSpaceServicesFactory
+ .getInstance().getConfigurationService();
+ private static final ItemService itemService = ContentServiceFactory
+ .getInstance().getItemService();
+ private static final MetadataAuthorityService metadataAuthorityService = ContentAuthorityServiceFactory
+ .getInstance().getMetadataAuthorityService();
+
+ private TypeBindUtils() {}
+
+ /**
+ * This method gets the field used for type-bind.
+ * @return the field used for type-bind.
+ */
+ public static String getTypeBindField() {
+ return configurationService.getProperty("submit.type-bind.field", "dc.type");
+ }
+
+ /**
+ * This method gets the value of the type-bind field from the current item.
+ * @return the value of the type-bind field from the current item.
+ */
+ public static String getTypeBindValue(InProgressSubmission> obj) {
+ List documentType = itemService.getMetadataByMetadataString(
+ obj.getItem(), getTypeBindField());
+
+ // check empty type-bind field
+ if (documentType == null || documentType.isEmpty()
+ || StringUtils.isBlank(documentType.get(0).getValue())) {
+ return null;
+ }
+
+ MetadataValue typeBindValue = documentType.get(0);
+
+ boolean isAuthorityAllowed = metadataAuthorityService.isAuthorityAllowed(
+ getTypeBindField().replace(".","_"), Constants.ITEM, obj.getCollection());
+ if (isAuthorityAllowed && typeBindValue.getAuthority() != null) {
+ return typeBindValue.getAuthority();
+ }
+
+ return typeBindValue.getValue();
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java
index 9c37fcee4755..3b2366034489 100644
--- a/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java
+++ b/dspace-api/src/main/java/org/dspace/authenticate/IPAuthentication.java
@@ -52,11 +52,6 @@ public class IPAuthentication implements AuthenticationMethod {
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(IPAuthentication.class);
- /**
- * Whether to look for x-forwarded headers for logging IP addresses
- */
- protected static Boolean useProxies;
-
/**
* All the IP matchers
*/
@@ -250,7 +245,7 @@ public List getSpecialGroups(Context context, HttpServletRequest request)
log.debug(LogHelper.getHeader(context, "authenticated",
"special_groups=" + gsb.toString()
- + " (by IP=" + addr + ", useProxies=" + useProxies.toString() + ")"
+ + " (by IP=" + addr + ")"
));
}
diff --git a/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java b/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java
index f3c6022e02c2..afd82db863ba 100644
--- a/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java
+++ b/dspace-api/src/main/java/org/dspace/authenticate/LDAPAuthentication.java
@@ -11,9 +11,11 @@
import java.io.IOException;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Hashtable;
+import java.util.Iterator;
import java.util.List;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
@@ -64,6 +66,7 @@
* @author Reuben Pasquini
* @author Samuel Ottenhoff
* @author Ivan Masár
+ * @author Michael Plate
*/
public class LDAPAuthentication
implements AuthenticationMethod {
@@ -391,7 +394,7 @@ private static class SpeakerToLDAP {
protected String ldapGivenName = null;
protected String ldapSurname = null;
protected String ldapPhone = null;
- protected String ldapGroup = null;
+ protected ArrayList ldapGroup = null;
/**
* LDAP settings
@@ -406,9 +409,9 @@ private static class SpeakerToLDAP {
final String ldap_surname_field;
final String ldap_phone_field;
final String ldap_group_field;
-
final boolean useTLS;
+
SpeakerToLDAP(Logger thelog) {
ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
@@ -547,7 +550,11 @@ protected String getDNOfUser(String adminUser, String adminPassword, Context con
if (attlist[4] != null) {
att = atts.get(attlist[4]);
if (att != null) {
- ldapGroup = (String) att.get();
+ // loop through all groups returned by LDAP
+ ldapGroup = new ArrayList();
+ for (NamingEnumeration val = att.getAll(); val.hasMoreElements(); ) {
+ ldapGroup.add((String) val.next());
+ }
}
}
@@ -693,48 +700,69 @@ public String getName() {
/*
* Add authenticated users to the group defined in dspace.cfg by
* the authentication-ldap.login.groupmap.* key.
+ *
+ * @param dn
+ * The string containing distinguished name of the user
+ *
+ * @param group
+ * List of strings with LDAP dn of groups
+ *
+ * @param context
+ * DSpace context
*/
- private void assignGroups(String dn, String group, Context context) {
+ private void assignGroups(String dn, ArrayList group, Context context) {
if (StringUtils.isNotBlank(dn)) {
System.out.println("dn:" + dn);
int i = 1;
String groupMap = configurationService.getProperty("authentication-ldap.login.groupmap." + i);
-
boolean cmp;
+
+ // groupmap contains the mapping of LDAP groups to DSpace groups
+ // outer loop with the DSpace groups
while (groupMap != null) {
String t[] = groupMap.split(":");
String ldapSearchString = t[0];
String dspaceGroupName = t[1];
- if (group == null) {
- cmp = StringUtils.containsIgnoreCase(dn, ldapSearchString + ",");
- } else {
- cmp = StringUtils.equalsIgnoreCase(group, ldapSearchString);
- }
+ // list of strings with dn from LDAP groups
+ // inner loop
+ Iterator groupIterator = group.iterator();
+ while (groupIterator.hasNext()) {
- if (cmp) {
- // assign user to this group
- try {
- Group ldapGroup = groupService.findByName(context, dspaceGroupName);
- if (ldapGroup != null) {
- groupService.addMember(context, ldapGroup, context.getCurrentUser());
- groupService.update(context, ldapGroup);
- } else {
- // The group does not exist
- log.warn(LogHelper.getHeader(context,
- "ldap_assignGroupsBasedOnLdapDn",
- "Group defined in authentication-ldap.login.groupmap." + i
- + " does not exist :: " + dspaceGroupName));
+ // save the current entry from iterator for further use
+ String currentGroup = groupIterator.next();
+
+ // very much the old code from DSpace <= 7.5
+ if (currentGroup == null) {
+ cmp = StringUtils.containsIgnoreCase(dn, ldapSearchString + ",");
+ } else {
+ cmp = StringUtils.equalsIgnoreCase(currentGroup, ldapSearchString);
+ }
+
+ if (cmp) {
+ // assign user to this group
+ try {
+ Group ldapGroup = groupService.findByName(context, dspaceGroupName);
+ if (ldapGroup != null) {
+ groupService.addMember(context, ldapGroup, context.getCurrentUser());
+ groupService.update(context, ldapGroup);
+ } else {
+ // The group does not exist
+ log.warn(LogHelper.getHeader(context,
+ "ldap_assignGroupsBasedOnLdapDn",
+ "Group defined in authentication-ldap.login.groupmap." + i
+ + " does not exist :: " + dspaceGroupName));
+ }
+ } catch (AuthorizeException ae) {
+ log.debug(LogHelper.getHeader(context,
+ "assignGroupsBasedOnLdapDn could not authorize addition to " +
+ "group",
+ dspaceGroupName));
+ } catch (SQLException e) {
+ log.debug(LogHelper.getHeader(context, "assignGroupsBasedOnLdapDn could not find group",
+ dspaceGroupName));
}
- } catch (AuthorizeException ae) {
- log.debug(LogHelper.getHeader(context,
- "assignGroupsBasedOnLdapDn could not authorize addition to " +
- "group",
- dspaceGroupName));
- } catch (SQLException e) {
- log.debug(LogHelper.getHeader(context, "assignGroupsBasedOnLdapDn could not find group",
- dspaceGroupName));
}
}
diff --git a/dspace-api/src/main/java/org/dspace/authenticate/OrcidAuthenticationBean.java b/dspace-api/src/main/java/org/dspace/authenticate/OrcidAuthenticationBean.java
index f77d7e57119a..88797e9b1a79 100644
--- a/dspace-api/src/main/java/org/dspace/authenticate/OrcidAuthenticationBean.java
+++ b/dspace-api/src/main/java/org/dspace/authenticate/OrcidAuthenticationBean.java
@@ -27,7 +27,10 @@
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
+import org.dspace.eperson.RegistrationData;
+import org.dspace.eperson.RegistrationTypeEnum;
import org.dspace.eperson.service.EPersonService;
+import org.dspace.eperson.service.RegistrationDataService;
import org.dspace.orcid.OrcidToken;
import org.dspace.orcid.client.OrcidClient;
import org.dspace.orcid.client.OrcidConfiguration;
@@ -47,11 +50,15 @@
* ORCID authentication for DSpace.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
- *
*/
public class OrcidAuthenticationBean implements AuthenticationMethod {
+
+ public static final String ORCID_DEFAULT_FIRSTNAME = "Unnamed";
+ public static final String ORCID_DEFAULT_LASTNAME = ORCID_DEFAULT_FIRSTNAME;
public static final String ORCID_AUTH_ATTRIBUTE = "orcid-authentication";
+ public static final String ORCID_REGISTRATION_TOKEN = "orcid-registration-token";
+ public static final String ORCID_DEFAULT_REGISTRATION_URL = "/external-login/{0}";
private final static Logger LOGGER = LoggerFactory.getLogger(OrcidAuthenticationBean.class);
@@ -78,6 +85,9 @@ public class OrcidAuthenticationBean implements AuthenticationMethod {
@Autowired
private OrcidTokenService orcidTokenService;
+ @Autowired
+ private RegistrationDataService registrationDataService;
+
@Override
public int authenticate(Context context, String username, String password, String realm, HttpServletRequest request)
throws SQLException {
@@ -184,7 +194,7 @@ private int authenticateWithOrcid(Context context, String code, HttpServletReque
return ePerson.canLogIn() ? logInEPerson(context, token, ePerson) : BAD_ARGS;
}
- return canSelfRegister() ? registerNewEPerson(context, person, token) : NO_SUCH_USER;
+ return canSelfRegister() ? createRegistrationData(context, request, person, token) : NO_SUCH_USER;
}
@@ -212,48 +222,59 @@ private ResearcherProfile findProfile(Context context, EPerson ePerson) throws S
}
}
- private int registerNewEPerson(Context context, Person person, OrcidTokenResponseDTO token) throws SQLException {
+ private int createRegistrationData(
+ Context context, HttpServletRequest request, Person person, OrcidTokenResponseDTO token
+ ) throws SQLException {
try {
context.turnOffAuthorisationSystem();
- String email = getEmail(person)
- .orElseThrow(() -> new IllegalStateException("The email is configured private on orcid"));
-
- String orcid = token.getOrcid();
-
- EPerson eperson = ePersonService.create(context);
+ RegistrationData registrationData =
+ this.registrationDataService.create(context, token.getOrcid(), RegistrationTypeEnum.ORCID);
- eperson.setNetid(orcid);
+ registrationData.setEmail(getEmail(person).orElse(null));
+ setOrcidMetadataOnRegistration(context, registrationData, person, token);
- eperson.setEmail(email);
+ registrationDataService.update(context, registrationData);
- Optional firstName = getFirstName(person);
- if (firstName.isPresent()) {
- eperson.setFirstName(context, firstName.get());
- }
-
- Optional lastName = getLastName(person);
- if (lastName.isPresent()) {
- eperson.setLastName(context, lastName.get());
- }
- eperson.setCanLogIn(true);
- eperson.setSelfRegistered(true);
-
- setOrcidMetadataOnEPerson(context, eperson, token);
-
- ePersonService.update(context, eperson);
- context.setCurrentUser(eperson);
+ request.setAttribute(ORCID_REGISTRATION_TOKEN, registrationData.getToken());
+ context.commit();
context.dispatchEvents();
- return SUCCESS;
-
} catch (Exception ex) {
LOGGER.error("An error occurs registering a new EPerson from ORCID", ex);
context.rollback();
- return NO_SUCH_USER;
} finally {
context.restoreAuthSystemState();
+ return NO_SUCH_USER;
+ }
+ }
+
+ private void setOrcidMetadataOnRegistration(
+ Context context, RegistrationData registration, Person person, OrcidTokenResponseDTO token
+ ) throws SQLException, AuthorizeException {
+ String orcid = token.getOrcid();
+
+ setRegistrationMetadata(context, registration, "eperson.firstname", getFirstName(person));
+ setRegistrationMetadata(context, registration, "eperson.lastname", getLastName(person));
+ registrationDataService.setRegistrationMetadataValue(context, registration, "eperson", "orcid", null, orcid);
+
+ for (String scope : token.getScopeAsArray()) {
+ registrationDataService.addMetadata(context, registration, "eperson", "orcid", "scope", scope);
+ }
+ }
+
+ private void setRegistrationMetadata(
+ Context context, RegistrationData registration, String metadataString, String value) {
+ String[] split = metadataString.split("\\.");
+ String qualifier = split.length > 2 ? split[2] : null;
+ try {
+ registrationDataService.setRegistrationMetadataValue(
+ context, registration, split[0], split[1], qualifier, value
+ );
+ } catch (SQLException | AuthorizeException ex) {
+ LOGGER.error("An error occurs setting metadata", ex);
+ throw new RuntimeException(ex);
}
}
@@ -296,16 +317,20 @@ private Optional getEmail(Person person) {
return Optional.ofNullable(emails.get(0).getEmail());
}
- private Optional getFirstName(Person person) {
+ private String getFirstName(Person person) {
return Optional.ofNullable(person.getName())
- .map(name -> name.getGivenNames())
- .map(givenNames -> givenNames.getContent());
+ .map(name -> name.getGivenNames())
+ .map(givenNames -> givenNames.getContent())
+ .filter(StringUtils::isNotBlank)
+ .orElse(ORCID_DEFAULT_FIRSTNAME);
}
- private Optional getLastName(Person person) {
+ private String getLastName(Person person) {
return Optional.ofNullable(person.getName())
- .map(name -> name.getFamilyName())
- .map(givenNames -> givenNames.getContent());
+ .map(name -> name.getFamilyName())
+ .map(givenNames -> givenNames.getContent())
+ .filter(StringUtils::isNotBlank)
+ .orElse(ORCID_DEFAULT_LASTNAME);
}
private boolean canSelfRegister() {
diff --git a/dspace-api/src/main/java/org/dspace/authority/CrisConsumer.java b/dspace-api/src/main/java/org/dspace/authority/CrisConsumer.java
index eec4412c0c98..a83cc8692e31 100644
--- a/dspace-api/src/main/java/org/dspace/authority/CrisConsumer.java
+++ b/dspace-api/src/main/java/org/dspace/authority/CrisConsumer.java
@@ -193,7 +193,7 @@ private boolean isMetadataSkippable(MetadataValue metadata) {
return true;
}
- if (isBlank(authority) && isMetadataWithEmptyAuthoritySkippable(metadata)) {
+ if (isBlank(authority) && (isBlank(metadata.getValue()) || isMetadataWithEmptyAuthoritySkippable(metadata))) {
return true;
}
@@ -255,7 +255,7 @@ private String getFieldKey(MetadataValue metadata) {
private Item buildRelatedItem(Context context, Item item, Collection collection, MetadataValue metadata,
String entityType, String crisSourceId) throws Exception {
- WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, false);
+ WorkspaceItem workspaceItem = workspaceItemService.create(context, collection, useOfTemplate(metadata));
Item relatedItem = workspaceItem.getItem();
itemService.addMetadata(context, relatedItem, CRIS.getName(), "sourceId", null, null, crisSourceId);
if (!hasEntityType(relatedItem, entityType)) {
@@ -299,6 +299,17 @@ private boolean isSubmissionEnabled(MetadataValue value) {
}
}
+ private boolean useOfTemplate(MetadataValue value) {
+
+ String useOfTemplateByMetadata = "cris.import.submission.enabled.entity."
+ + getFieldKey(value) + ".use-template";
+ if (configurationService.hasProperty(useOfTemplateByMetadata)) {
+ return configurationService.getBooleanProperty(useOfTemplateByMetadata);
+ }
+
+ return configurationService.getBooleanProperty("cris.import.submission.enabled.entity.use-template");
+ }
+
private void fillRelatedItem(Context context, MetadataValue metadata, Item relatedItem, boolean alreadyPresent)
throws SQLException {
diff --git a/dspace-api/src/main/java/org/dspace/authority/filler/ExternalDataProviderImportFiller.java b/dspace-api/src/main/java/org/dspace/authority/filler/ExternalDataProviderImportFiller.java
index ef218c76fb34..7a7d10e63499 100644
--- a/dspace-api/src/main/java/org/dspace/authority/filler/ExternalDataProviderImportFiller.java
+++ b/dspace-api/src/main/java/org/dspace/authority/filler/ExternalDataProviderImportFiller.java
@@ -7,7 +7,6 @@
*/
package org.dspace.authority.filler;
-import static org.apache.commons.collections.CollectionUtils.isEmpty;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.removeStart;
import static org.apache.commons.lang3.StringUtils.startsWith;
@@ -110,7 +109,11 @@ private void enrichItemWithExternalData(Context context, Item item, ExternalData
}
private boolean notAlreadyPresent(Item item, MetadataValueDTO value) {
- return isEmpty(itemService.getMetadata(item, value.getSchema(), value.getElement(), value.getQualifier(), ANY));
+ List metadataValues = itemService.getMetadata(item, value.getSchema(),
+ value.getElement(), value.getQualifier(), ANY);
+
+ return metadataValues.stream().noneMatch(metadataValue ->
+ metadataValue.getValue().equals(value.getValue()));
}
private boolean isTitleNotSet(Item item) {
diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
index 014de4671c8b..5eef69af7398 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
@@ -47,6 +47,7 @@
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.indexobject.IndexableCollection;
import org.dspace.discovery.indexobject.IndexableCommunity;
+import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
@@ -676,60 +677,6 @@ public ResourcePolicy findByTypeGroupAction(Context c, DSpaceObject dso, Group g
}
}
- /**
- * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically
- * at the groups that
- * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to
- * anonymous.
- *
- * @param context The relevant DSpace Context.
- * @param embargoDate embargo end date
- * @param reason embargo reason
- * @param dso DSpace object
- * @param owningCollection collection to get group policies from
- * @throws SQLException if database error
- * @throws AuthorizeException if authorization error
- */
- @Override
- public void generateAutomaticPolicies(Context context, Date embargoDate,
- String reason, DSpaceObject dso, Collection owningCollection)
- throws SQLException, AuthorizeException {
-
- if (embargoDate != null || (embargoDate == null && dso instanceof Bitstream)) {
-
- List authorizedGroups = getAuthorizedGroups(context, owningCollection, Constants.DEFAULT_ITEM_READ);
-
- removeAllPoliciesByDSOAndType(context, dso, ResourcePolicy.TYPE_CUSTOM);
-
- // look for anonymous
- boolean isAnonymousInPlace = false;
- for (Group g : authorizedGroups) {
- if (StringUtils.equals(g.getName(), Group.ANONYMOUS)) {
- isAnonymousInPlace = true;
- }
- }
- if (!isAnonymousInPlace) {
- // add policies for all the groups
- for (Group g : authorizedGroups) {
- ResourcePolicy rp = createOrModifyPolicy(null, context, null, g, null, embargoDate, Constants.READ,
- reason, dso);
- if (rp != null) {
- resourcePolicyService.update(context, rp);
- }
- }
-
- } else {
- // add policy just for anonymous
- ResourcePolicy rp = createOrModifyPolicy(null, context, null,
- groupService.findByName(context, Group.ANONYMOUS), null,
- embargoDate, Constants.READ, reason, dso);
- if (rp != null) {
- resourcePolicyService.update(context, rp);
- }
- }
- }
- }
-
@Override
public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson,
int type, String rpType) throws SQLException, AuthorizeException {
@@ -831,6 +778,19 @@ public boolean isCollectionAdmin(Context context) throws SQLException {
return performCheck(context, "search.resourcetype:" + IndexableCollection.TYPE);
}
+ /**
+ * Checks that the context's current user is an item admin in the site by querying the solr database.
+ *
+ * @param context context with the current user
+ * @return true if the current user is an item admin in the site
+ * false when this is not the case, or an exception occurred
+ * @throws java.sql.SQLException passed through.
+ */
+ @Override
+ public boolean isItemAdmin(Context context) throws SQLException {
+ return performCheck(context, "search.resourcetype:" + IndexableItem.TYPE);
+ }
+
/**
* Checks that the context's current user is a community or collection admin in the site.
*
diff --git a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java
index 954bb9699038..c781400bae45 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicy.java
@@ -41,9 +41,16 @@
@Entity
@Table(name = "resourcepolicy")
public class ResourcePolicy implements ReloadableEntity {
+ /** This policy was set on submission, to give the submitter access. */
public static String TYPE_SUBMISSION = "TYPE_SUBMISSION";
+
+ /** This policy was set to allow access by a workflow group. */
public static String TYPE_WORKFLOW = "TYPE_WORKFLOW";
+
+ /** This policy was explicitly set on this object. */
public static String TYPE_CUSTOM = "TYPE_CUSTOM";
+
+ /** This policy was copied from the containing object's default policies. */
public static String TYPE_INHERITED = "TYPE_INHERITED";
@Id
@@ -93,7 +100,7 @@ public class ResourcePolicy implements ReloadableEntity {
private String rptype;
@Lob
- @Type(type = "org.dspace.storage.rdbms.hibernate.DatabaseAwareLobType")
+ @Type(type = "org.hibernate.type.TextType")
@Column(name = "rpdescription")
private String rpdescription;
diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java b/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java
index d707bf200b4e..87bf459bcbeb 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/dao/ResourcePolicyDAO.java
@@ -40,6 +40,9 @@ public List findByDsoAndType(Context context, DSpaceObject dSpac
public List findByDSoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException;
+ public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dSpaceObject, String type, int action)
+ throws SQLException;
+
public List findByDSoAndActionAndType(Context c, DSpaceObject o, int actionId, String type)
throws SQLException;
@@ -64,9 +67,6 @@ public List findByEPersonGroupTypeIdAction(Context context, EPer
public void deleteByDsoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException;
- public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dSpaceObject, String type, int action)
- throws SQLException;
-
public void deleteByDsoAndType(Context context, DSpaceObject dSpaceObject, String type) throws SQLException;
public void deleteByGroup(Context context, Group group) throws SQLException;
diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java
index ee79933361d0..3c002459ff18 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java
@@ -125,6 +125,19 @@ public List findByDSoAndActionAndType(Context context, DSpaceObj
return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1);
}
+ @Override
+ public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dso, String type, int actionId)
+ throws SQLException {
+ String queryString = "delete from ResourcePolicy where dSpaceObject.id = :dsoId "
+ + "AND rptype = :rptype AND actionId= :actionId";
+ Query query = createQuery(context, queryString);
+ query.setParameter("dsoId", dso.getID());
+ query.setParameter("rptype", type);
+ query.setParameter("actionId", actionId);
+ query.executeUpdate();
+
+ }
+
@Override
public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action)
throws SQLException {
@@ -203,19 +216,6 @@ public void deleteByDsoAndType(Context context, DSpaceObject dso, String type) t
query.executeUpdate();
}
- @Override
- public void deleteByDsoAndTypeAndAction(Context context, DSpaceObject dso, String type, int actionId)
- throws SQLException {
- String queryString = "delete from ResourcePolicy where dSpaceObject.id = :dsoId "
- + "AND rptype = :rptype AND actionId= :actionId";
- Query query = createQuery(context, queryString);
- query.setParameter("dsoId", dso.getID());
- query.setParameter("rptype", type);
- query.setParameter("actionId", actionId);
- query.executeUpdate();
-
- }
-
@Override
public void deleteByGroup(Context context, Group group) throws SQLException {
String queryString = "delete from ResourcePolicy where epersonGroup= :epersonGroup";
diff --git a/dspace-api/src/main/java/org/dspace/authorize/package-info.java b/dspace-api/src/main/java/org/dspace/authorize/package-info.java
new file mode 100644
index 000000000000..f36c39cfe351
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/authorize/package-info.java
@@ -0,0 +1,67 @@
+/**
+ * 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/
+ */
+
+/**
+ * Represents permissions for access to DSpace content.
+ *
+ * Philosophy
+ * DSpace's authorization system follows the classical "police state"
+ * philosophy of security - the user can do nothing, unless it is
+ * specifically allowed. Those permissions are spelled out with
+ * {@link ResourcePolicy} objects, stored in the {@code resourcepolicy} table
+ * in the database.
+ *
+ * Policies are attached to Content
+ * Resource Policies get assigned to all of the content objects in
+ * DSpace - collections, communities, items, bundles, and bitstreams.
+ * (Currently they are not attached to non-content objects such as
+ * {@code EPerson} or {@code Group}. But they could be, hence the name
+ * {@code ResourcePolicy} instead of {@code ContentPolicy}.)
+ *
+ * Policies are tuples
+ * Authorization is based on evaluating the tuple of (object, action, actor),
+ * such as (ITEM, READ, EPerson John Smith) to check if the {@code EPerson}
+ * "John Smith" can read an item. {@code ResourcePolicy} objects are pretty
+ * simple, describing a single instance of (object, action, actor). If
+ * multiple actors are desired, such as groups 10, 11, and 12 are allowed to
+ * READ Item 13, you simply create a {@code ResourcePolicy} for each group.
+ *
+ * Built-in groups
+ * The install process should create two built-in groups - {@code Anonymous}
+ * for anonymous/public access, and {@code Administrators} for administrators.
+ * Group {@code Anonymous} allows anyone access, even if not authenticated.
+ * Group {@code Administrators}' members have super-user rights,
+ * and are allowed to do any action to any object.
+ *
+ * Policy types
+ * Policies have a "type" used to distinguish policies which are applied for
+ * specific purposes.
+ *
+ * CUSTOM
+ * These are created and assigned explicitly by users.
+ * INHERITED
+ * These are copied from a containing object's default policies.
+ * SUBMISSION
+ * These are applied during submission to give the submitter access while
+ * composing a submission.
+ * WORKFLOW
+ * These are automatically applied during workflow, to give curators
+ * access to submissions in their curation queues. They usually have an
+ * automatically-created workflow group as the actor.
+ *
+ * Start and End dates
+ * A policy may have a start date and/or an end date. The policy is
+ * considered not valid before the start date or after the end date. No date
+ * means do not apply the related test. For example, embargo until a given
+ * date can be expressed by a READ policy with a given start date, and a
+ * limited-time offer by a READ policy with a given end date.
+ *
+ * @author dstuve
+ * @author mwood
+ */
+package org.dspace.authorize;
diff --git a/dspace-api/src/main/java/org/dspace/authorize/package.html b/dspace-api/src/main/java/org/dspace/authorize/package.html
deleted file mode 100644
index 66ce0f824773..000000000000
--- a/dspace-api/src/main/java/org/dspace/authorize/package.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-Handles permissions for DSpace content.
-
-
-Philosophy
-DSpace's authorization system follows the classical "police state"
-philosophy of security - the user can do nothing, unless it is
-specifically allowed. Those permissions are spelled out with
-ResourcePolicy objects, stored in the resourcepolicy table in the
-database.
-
-
-Policies are attached to Content
-Policies are attached to Content
-Resource Policies get assigned to all of the content objects in
-DSpace - collections, communities, items, bundles, and bitstreams.
-(Currently they are not attached to non-content objects such as EPerson
-or Group. But they could be, hence the name ResourcePolicy instead of
-ContentPolicy.)
-
-
-Policies are tuples
-Authorization is based on evaluating the tuple of (object, action, who),
-such as (ITEM, READ, EPerson John Smith) to check if the EPerson "John Smith"
-can read an item. ResourcePolicy objects are pretty simple, describing a single instance of
-(object, action, who). If multiple who's are desired, such as Groups 10, 11, and
-12 are allowed to READ Item 13, you simply create a ResourcePolicy for each
-group.
-
-
-Special Groups
-The install process should create two special groups - group 0, for
-anonymous/public access, and group 1 for administrators.
-Group 0 (public/anonymous) allows anyone access, even if they are not
-authenticated. Group 1's (admin) members have super-user rights, and
-are allowed to do any action to any object.
-
-
-Unused ResourcePolicy attributes
-ResourcePolicies have a few attributes that are currently unused,
-but are included with the intent that they will be used someday.
-One is start and end dates, for when policies will be active, so that
-permissions for content can change over time. The other is the EPerson -
-policies could apply to only a single EPerson, but for ease of
-administration currently a Group is the recommended unit to use to
-describe 'who'.
-
-
-
-
diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
index 43ae51544c9b..3db676d88b2b 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
@@ -489,24 +489,6 @@ public boolean isAnIdenticalPolicyAlreadyInPlace(Context c, DSpaceObject o, Grou
public ResourcePolicy findByTypeGroupAction(Context c, DSpaceObject dso, Group group, int action)
throws SQLException;
-
- /**
- * Generate Policies policies READ for the date in input adding reason. New policies are assigned automatically
- * at the groups that
- * have right on the collection. E.g., if the anonymous can access the collection policies are assigned to
- * anonymous.
- *
- * @param context current context
- * @param embargoDate date
- * @param reason reason
- * @param dso DSpaceObject
- * @param owningCollection collection
- * @throws SQLException if database error
- * @throws AuthorizeException if authorization error
- */
- public void generateAutomaticPolicies(Context context, Date embargoDate, String reason, DSpaceObject dso,
- Collection owningCollection) throws SQLException, AuthorizeException;
-
public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Group group, EPerson eperson,
int type, String rpType) throws SQLException, AuthorizeException;
@@ -551,6 +533,15 @@ void switchPoliciesAction(Context context, DSpaceObject dso, int fromAction, int
*/
boolean isCollectionAdmin(Context context) throws SQLException;
+ /**
+ * Checks that the context's current user is an item admin in the site by querying the solr database.
+ *
+ * @param context context with the current user
+ * @return true if the current user is an item admin in the site
+ * false when this is not the case, or an exception occurred
+ */
+ boolean isItemAdmin(Context context) throws SQLException;
+
/**
* Checks that the context's current user is a community or collection admin in the site.
*
@@ -646,7 +637,7 @@ long countAdminAuthorizedCollection(Context context, String query)
/**
* Replace all the policies in the target object with exactly the same policies that exist in the source object
- *
+ *
* @param context DSpace Context
* @param source source of policies
* @param dest destination of inherited policies
diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
index beb3c34662df..662b14b18b2e 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
@@ -56,12 +56,19 @@ public List find(Context c, EPerson e, List groups, int a
throws SQLException;
/**
- * Look for ResourcePolicies by DSpaceObject, Group, and action, ignoring IDs with a specific PolicyID.
- * This method can be used to detect duplicate ResourcePolicies.
+ * Look for ResourcePolicies by DSpaceObject, Group, and action, ignoring
+ * IDs with a specific PolicyID. This method can be used to detect duplicate
+ * ResourcePolicies.
*
- * @param notPolicyID ResourcePolicies with this ID will be ignored while looking out for equal ResourcePolicies.
- * @return List of resource policies for the same DSpaceObject, group and action but other policyID.
- * @throws SQLException
+ * @param context current DSpace session.
+ * @param dso find policies for this object.
+ * @param group find policies referring to this group.
+ * @param action find policies for this action.
+ * @param notPolicyID ResourcePolicies with this ID will be ignored while
+ * looking out for equal ResourcePolicies.
+ * @return List of resource policies for the same DSpaceObject, group and
+ * action but other policyID.
+ * @throws SQLException passed through.
*/
public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group,
int action, int notPolicyID)
@@ -71,6 +78,16 @@ public List findByTypeGroupActionExceptId(Context context, DSpac
public boolean isDateValid(ResourcePolicy resourcePolicy);
+ /**
+ * Create and persist a copy of a given ResourcePolicy, with an empty
+ * dSpaceObject field.
+ *
+ * @param context current DSpace session.
+ * @param resourcePolicy the policy to be copied.
+ * @return the copy.
+ * @throws SQLException passed through.
+ * @throws AuthorizeException passed through.
+ */
public ResourcePolicy clone(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException;
public void removeAllPolicies(Context c, DSpaceObject o) throws SQLException, AuthorizeException;
@@ -123,6 +140,7 @@ public List findExceptRpType(Context c, DSpaceObject o, int acti
* @param ePerson ePerson whose policies want to find
* @param offset the position of the first result to return
* @param limit paging limit
+ * @return some of the policies referring to {@code ePerson}.
* @throws SQLException if database error
*/
public List findByEPerson(Context context, EPerson ePerson, int offset, int limit)
diff --git a/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java b/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java
index 14e439d5908c..5d5f2ccb755e 100644
--- a/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java
+++ b/dspace-api/src/main/java/org/dspace/browse/BrowseIndex.java
@@ -22,11 +22,13 @@
* This class holds all the information about a specifically configured
* BrowseIndex. It is responsible for parsing the configuration, understanding
* about what sort options are available, and what the names of the database
- * tables that hold all the information are actually called.
+ * tables that hold all the information are actually called. Hierarchical browse
+ * indexes also contain information about the vocabulary they're using, see:
+ * {@link org.dspace.content.authority.DSpaceControlledVocabularyIndex}
*
* @author Richard Jones
*/
-public final class BrowseIndex {
+public class BrowseIndex {
/** the configuration number, as specified in the config */
/**
* used for single metadata browse tables for generating the table name
@@ -99,10 +101,10 @@ private BrowseIndex() {
/**
* Constructor for creating generic / internal index objects
- *
+ *
* @param baseName The base of the table name
*/
- private BrowseIndex(String baseName) {
+ protected BrowseIndex(String baseName) {
this(baseName, "item");
}
@@ -735,7 +737,7 @@ public static BrowseIndex getBrowseIndex(SortOption so) throws BrowseException {
/**
* Get the internally defined browse index for archived items.
- *
+ *
* @param displayType
*
* @return browse index
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
index c9c140fb0b5b..20c43fc37298 100644
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
+++ b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
@@ -18,6 +18,7 @@
import org.dspace.core.Context;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.web.ContextUtil;
/**
* This class provides a standard interface to all item counting
@@ -49,9 +50,20 @@ public class ItemCounter {
*/
private Context context;
+ /**
+ * This field is used to hold singular instance of a class.
+ * Singleton pattern is used but this class should be
+ * refactored to modern DSpace approach (injectible service).
+ */
+
+ private static ItemCounter instance;
+
protected ItemService itemService;
protected ConfigurationService configurationService;
+ private boolean showStrengths;
+ private boolean useCache;
+
/**
* Construct a new item counter which will use the given DSpace Context
*
@@ -63,21 +75,42 @@ public ItemCounter(Context context) throws ItemCountException {
this.dao = ItemCountDAOFactory.getInstance(this.context);
this.itemService = ContentServiceFactory.getInstance().getItemService();
this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
+ this.showStrengths = configurationService.getBooleanProperty("webui.strengths.show", false);
+ this.useCache = configurationService.getBooleanProperty("webui.strengths.cache", true);
}
/**
- * Get the count of the items in the given container. If the configuration
- * value webui.strengths.cache is equal to 'true' this will return the
- * cached value if it exists. If it is equal to 'false' it will count
- * the number of items in the container in real time.
+ * Get the singular instance of a class.
+ * It creates a new instance at the first usage of this method.
+ *
+ * @return instance af a class
+ * @throws ItemCountException when error occurs
+ */
+ public static ItemCounter getInstance() throws ItemCountException {
+ if (instance == null) {
+ instance = new ItemCounter(ContextUtil.obtainCurrentRequestContext());
+ }
+ return instance;
+ }
+
+ /**
+ * Get the count of the items in the given container. If the configuration
+ * value webui.strengths.show is equal to 'true' this method will return all
+ * archived items. If the configuration value webui.strengths.show is equal to
+ * 'false' this method will return -1.
+ * If the configuration value webui.strengths.cache
+ * is equal to 'true' this will return the cached value if it exists.
+ * If it is equal to 'false' it will count the number of items
+ * in the container in real time.
*
* @param dso DSpaceObject
* @return count
* @throws ItemCountException when error occurs
*/
public int getCount(DSpaceObject dso) throws ItemCountException {
- boolean useCache = configurationService.getBooleanProperty(
- "webui.strengths.cache", true);
+ if (!showStrengths) {
+ return -1;
+ }
if (useCache) {
return dao.getCount(dso);
diff --git a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java
index 0194be59f3a7..3676133a89f9 100644
--- a/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java
+++ b/dspace-api/src/main/java/org/dspace/browse/SolrBrowseDAO.java
@@ -264,7 +264,7 @@ private void addLocationScopeFilter(DiscoverQuery query) {
}
private void addDefaultFilterQueries(DiscoverQuery query) {
- DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(container);
+ DiscoveryConfiguration discoveryConfiguration = SearchUtils.getDiscoveryConfiguration(context, container);
discoveryConfiguration.getDefaultFilterQueries().forEach(query::addFilterQueries);
}
diff --git a/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java b/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java
index 6b16d51bfe1e..a12ac3b98a2e 100644
--- a/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java
+++ b/dspace-api/src/main/java/org/dspace/checker/CheckerCommand.java
@@ -245,7 +245,7 @@ protected void processBitstream(MostRecentChecksum info) throws SQLException {
info.setProcessStartDate(new Date());
try {
- Map checksumMap = bitstreamStorageService.computeChecksum(context, info.getBitstream());
+ Map checksumMap = bitstreamStorageService.computeChecksum(context, info.getBitstream());
if (MapUtils.isNotEmpty(checksumMap)) {
info.setBitstreamFound(true);
if (checksumMap.containsKey("checksum")) {
@@ -255,10 +255,16 @@ protected void processBitstream(MostRecentChecksum info) throws SQLException {
if (checksumMap.containsKey("checksum_algorithm")) {
info.setChecksumAlgorithm(checksumMap.get("checksum_algorithm").toString());
}
+
+ // compare new checksum to previous checksum
+ info.setChecksumResult(compareChecksums(info.getExpectedChecksum(), info.getCurrentChecksum()));
+
+ } else {
+ info.setCurrentChecksum("");
+ info.setChecksumResult(getChecksumResultByCode(ChecksumResultCode.BITSTREAM_NOT_FOUND));
+ info.setToBeProcessed(false);
}
- // compare new checksum to previous checksum
- info.setChecksumResult(compareChecksums(info.getExpectedChecksum(), info.getCurrentChecksum()));
} catch (IOException e) {
// bitstream located, but file missing from asset store
info.setChecksumResult(getChecksumResultByCode(ChecksumResultCode.BITSTREAM_NOT_FOUND));
diff --git a/dspace-api/src/main/java/org/dspace/cli/DSpaceSkipUnknownArgumentsParser.java b/dspace-api/src/main/java/org/dspace/cli/DSpaceSkipUnknownArgumentsParser.java
new file mode 100644
index 000000000000..afd74a588d17
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/cli/DSpaceSkipUnknownArgumentsParser.java
@@ -0,0 +1,77 @@
+/**
+ * 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.cli;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/**
+ * Extended version of the DefaultParser. This parser skip/ignore unknown arguments.
+ */
+public class DSpaceSkipUnknownArgumentsParser extends DefaultParser {
+
+
+ @Override
+ public CommandLine parse(Options options, String[] arguments) throws ParseException {
+ return super.parse(options, getOnlyKnownArguments(options, arguments));
+ }
+
+ @Override
+ public CommandLine parse(Options options, String[] arguments, Properties properties) throws ParseException {
+ return super.parse(options, getOnlyKnownArguments(options, arguments), properties);
+ }
+
+ /**
+ * Parse the arguments according to the specified options and properties.
+ * @param options the specified Options
+ * @param arguments the command line arguments
+ * @param stopAtNonOption can be ignored - an unrecognized argument is ignored, an unrecognized argument doesn't
+ * stop the parsing and doesn't trigger a ParseException
+ *
+ * @return the list of atomic option and value tokens
+ * @throws ParseException if there are any problems encountered while parsing the command line tokens.
+ */
+ @Override
+ public CommandLine parse(Options options, String[] arguments, boolean stopAtNonOption) throws ParseException {
+ return super.parse(options, getOnlyKnownArguments(options, arguments), stopAtNonOption);
+ }
+
+ /**
+ * Parse the arguments according to the specified options and properties.
+ * @param options the specified Options
+ * @param arguments the command line arguments
+ * @param properties command line option name-value pairs
+ * @param stopAtNonOption can be ignored - an unrecognized argument is ignored, an unrecognized argument doesn't
+ * stop the parsing and doesn't trigger a ParseException
+ *
+ * @return the list of atomic option and value tokens
+ * @throws ParseException if there are any problems encountered while parsing the command line tokens.
+ */
+ @Override
+ public CommandLine parse(Options options, String[] arguments, Properties properties, boolean stopAtNonOption)
+ throws ParseException {
+ return super.parse(options, getOnlyKnownArguments(options, arguments), properties, stopAtNonOption);
+ }
+
+
+ private String[] getOnlyKnownArguments(Options options, String[] arguments) {
+ List knownArguments = new ArrayList<>();
+ for (String arg : arguments) {
+ if (options.hasOption(arg)) {
+ knownArguments.add(arg);
+ }
+ }
+ return knownArguments.toArray(new String[0]);
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
index f2a8680ee58d..9eb9145f277b 100644
--- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
@@ -7,12 +7,15 @@
*/
package org.dspace.content;
+import static org.apache.commons.lang.StringUtils.startsWith;
+
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Spliterators;
import java.util.UUID;
import java.util.regex.Pattern;
@@ -413,7 +416,7 @@ public Bitstream getFirstBitstream(Item item, String bundleName) throws SQLExcep
@Override
public Bitstream getThumbnail(Context context, Bitstream bitstream) throws SQLException {
- Pattern pattern = Pattern.compile("^" + bitstream.getName() + ".([^.]+)$");
+ Pattern pattern = getBitstreamNamePattern(bitstream);
for (Bundle bundle : bitstream.getBundles()) {
for (Item item : bundle.getItems()) {
@@ -443,6 +446,13 @@ public Bitstream getThumbnail(Context context, Bitstream bitstream) throws SQLEx
return null;
}
+ protected Pattern getBitstreamNamePattern(Bitstream bitstream) {
+ if (bitstream.getName() != null) {
+ return Pattern.compile("^" + Pattern.quote(bitstream.getName()) + ".([^.]+)$");
+ }
+ return Pattern.compile("^" + bitstream.getName() + ".([^.]+)$");
+ }
+
@Override
public BitstreamFormat getFormat(Context context, Bitstream bitstream) throws SQLException {
if (bitstream.getBitstreamFormat() == null) {
@@ -606,4 +616,63 @@ private Stream streamOf(Iterator iterator) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}
+ @Override
+ public boolean isOriginalBitstream(DSpaceObject dso) throws SQLException {
+
+ if (dso.getType() != Constants.BITSTREAM) {
+ return false;
+ }
+
+ Bitstream bitstream = (Bitstream) dso;
+
+ return bitstream.getBundles().stream()
+ .anyMatch(bundle -> "ORIGINAL".equals(bundle.getName()));
+
+ }
+
+ @Override
+ public void updateThumbnailResourcePolicies(Context context, Bitstream bitstream) throws SQLException {
+ getThumbnail(bitstream)
+ .ifPresent(thumbnail -> replacePolicies(context, bitstream, thumbnail));
+ }
+
+ private void replacePolicies(Context context, Bitstream bitstream, Bitstream thumbnail) {
+ try {
+ authorizeService.replaceAllPolicies(context, bitstream, thumbnail);
+ } catch (SQLException | AuthorizeException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Optional getThumbnail(Bitstream bitstream) throws SQLException {
+ return getItem(bitstream)
+ .flatMap(item -> getThumbnail(item, bitstream.getName()));
+ }
+
+ private Optional- getItem(Bitstream bitstream) throws SQLException {
+ return bitstream.getBundles().stream()
+ .flatMap(bundle -> bundle.getItems().stream())
+ .findFirst();
+ }
+
+ private Optional
getThumbnail(Item item, String name) {
+ List bundles = getThumbnailBundles(item);
+ if (CollectionUtils.isEmpty(bundles)) {
+ return Optional.empty();
+ }
+
+ return bundles.stream()
+ .flatMap(bundle -> bundle.getBitstreams().stream())
+ .filter(bitstream -> startsWith(bitstream.getName(), name))
+ .findFirst();
+ }
+
+ private List getThumbnailBundles(Item item) {
+ try {
+ return itemService.getBundles(item, "THUMBNAIL");
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
index 485f1d645130..20c43e4bfc73 100644
--- a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
@@ -8,6 +8,7 @@
package org.dspace.content;
import static org.dspace.core.Constants.ADD;
+import static org.dspace.core.Constants.READ;
import static org.dspace.core.Constants.REMOVE;
import static org.dspace.core.Constants.WRITE;
@@ -34,6 +35,7 @@
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
+import org.dspace.eperson.Group;
import org.dspace.event.Event;
import org.springframework.beans.factory.annotation.Autowired;
@@ -74,14 +76,14 @@ public Bundle find(Context context, UUID id) throws SQLException {
if (bundle == null) {
if (log.isDebugEnabled()) {
log.debug(LogHelper.getHeader(context, "find_bundle",
- "not_found,bundle_id=" + id));
+ "not_found,bundle_id=" + id));
}
return null;
} else {
if (log.isDebugEnabled()) {
log.debug(LogHelper.getHeader(context, "find_bundle",
- "bundle_id=" + id));
+ "bundle_id=" + id));
}
return bundle;
@@ -106,7 +108,7 @@ public Bundle create(Context context, Item item, String name) throws SQLExceptio
log.info(LogHelper.getHeader(context, "create_bundle", "bundle_id="
- + bundle.getID()));
+ + bundle.getID()));
// if we ever use the identifier service for bundles, we should
// create the bundle before we create the Event and should add all
@@ -132,12 +134,12 @@ public Bitstream getBitstreamByName(Bundle bundle, String name) {
@Override
public void addBitstream(Context context, Bundle bundle, Bitstream bitstream)
- throws SQLException, AuthorizeException {
+ throws SQLException, AuthorizeException {
// Check authorisation
authorizeService.authorizeAction(context, bundle, Constants.ADD);
log.info(LogHelper.getHeader(context, "add_bitstream", "bundle_id="
- + bundle.getID() + ",bitstream_id=" + bitstream.getID()));
+ + bundle.getID() + ",bitstream_id=" + bitstream.getID()));
// First check that the bitstream isn't already in the list
List bitstreams = bundle.getBitstreams();
@@ -167,28 +169,61 @@ public void addBitstream(Context context, Bundle bundle, Bitstream bitstream)
context.addEvent(new Event(Event.ADD, Constants.BUNDLE, bundle.getID(),
- Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()),
- getIdentifiers(context, bundle)));
+ Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()),
+ getIdentifiers(context, bundle)));
// copy authorization policies from bundle to bitstream
// FIXME: multiple inclusion is affected by this...
authorizeService.inheritPolicies(context, bundle, bitstream);
+ // The next logic is a bit overly cautious but ensures that if there are any future start dates
+ // on the item or bitstream read policies, that we'll skip inheriting anything from the owning collection
+ // just in case. In practice, the item install process would overwrite these anyway but it may satisfy
+ // some other bitstream creation methods and integration tests
+ boolean isEmbargoed = false;
+ for (ResourcePolicy resourcePolicy : authorizeService.getPoliciesActionFilter(context, owningItem, READ)) {
+ if (!resourcePolicyService.isDateValid(resourcePolicy)) {
+ isEmbargoed = true;
+ break;
+ }
+ }
+ if (owningItem != null && !isEmbargoed) {
+ // Resolve owning collection
+ Collection owningCollection = owningItem.getOwningCollection();
+ if (owningCollection != null) {
+ // Get DEFAULT_BITSTREAM_READ policy from the collection
+ List defaultBitstreamReadGroups =
+ authorizeService.getAuthorizedGroups(context, owningCollection,
+ Constants.DEFAULT_BITSTREAM_READ);
+ log.info(defaultBitstreamReadGroups.size());
+ // If this collection is configured with a DEFAULT_BITSTREAM_READ group, overwrite the READ policy
+ // inherited from the bundle with this policy.
+ if (!defaultBitstreamReadGroups.isEmpty()) {
+ // Remove read policies from the bitstream
+ authorizeService.removePoliciesActionFilter(context, bitstream, Constants.READ);
+ for (Group defaultBitstreamReadGroup : defaultBitstreamReadGroups) {
+ // Inherit this policy as READ, directly from the collection roles
+ authorizeService.addPolicy(context, bitstream,
+ Constants.READ, defaultBitstreamReadGroup, ResourcePolicy.TYPE_INHERITED);
+ }
+ }
+ }
+ }
bitstreamService.update(context, bitstream);
}
@Override
public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream)
- throws AuthorizeException, SQLException, IOException {
+ throws AuthorizeException, SQLException, IOException {
// Check authorisation
authorizeService.authorizeAction(context, bundle, Constants.REMOVE);
log.info(LogHelper.getHeader(context, "remove_bitstream",
- "bundle_id=" + bundle.getID() + ",bitstream_id=" + bitstream.getID()));
+ "bundle_id=" + bundle.getID() + ",bitstream_id=" + bitstream.getID()));
context.addEvent(new Event(Event.REMOVE, Constants.BUNDLE, bundle.getID(),
- Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()),
- getIdentifiers(context, bundle)));
+ Constants.BITSTREAM, bitstream.getID(), String.valueOf(bitstream.getSequenceID()),
+ getIdentifiers(context, bundle)));
//Ensure that the last modified from the item is triggered !
Item owningItem = (Item) getParentObject(context, bundle);
@@ -221,9 +256,9 @@ public void removeBitstream(Context context, Bundle bundle, Bitstream bitstream)
@Override
public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Collection collection)
- throws SQLException, AuthorizeException {
+ throws SQLException, AuthorizeException {
List policies = authorizeService.getPoliciesActionFilter(context, collection,
- Constants.DEFAULT_BITSTREAM_READ);
+ Constants.DEFAULT_BITSTREAM_READ);
// change the action to just READ
// just don't call update on the resourcepolicies!!!
@@ -231,7 +266,7 @@ public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Col
if (!i.hasNext()) {
throw new java.sql.SQLException("Collection " + collection.getID()
- + " has no default bitstream READ policies");
+ + " has no default bitstream READ policies");
}
List newPolicies = new ArrayList();
@@ -246,7 +281,7 @@ public void inheritCollectionDefaultPolicies(Context context, Bundle bundle, Col
@Override
public void replaceAllBitstreamPolicies(Context context, Bundle bundle, List newpolicies)
- throws SQLException, AuthorizeException {
+ throws SQLException, AuthorizeException {
List bitstreams = bundle.getBitstreams();
if (CollectionUtils.isNotEmpty(bitstreams)) {
for (Bitstream bs : bitstreams) {
@@ -368,16 +403,16 @@ public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws
if (bitstream == null) {
//This should never occur but just in case
log.warn(LogHelper.getHeader(context, "Invalid bitstream id while changing bitstream order",
- "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId));
+ "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId));
continue;
}
// If we have a Bitstream not in the current list, log a warning & exit immediately
if (!currentBitstreams.contains(bitstream)) {
log.warn(LogHelper.getHeader(context,
- "Encountered a bitstream not in this bundle while changing bitstream " +
- "order. Bitstream order will not be changed.",
- "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId));
+ "Encountered a bitstream not in this bundle while changing bitstream " +
+ "order. Bitstream order will not be changed.",
+ "Bundle: " + bundle.getID() + ", bitstream id: " + bitstreamId));
return;
}
updatedBitstreams.add(bitstream);
@@ -386,9 +421,9 @@ public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws
// If our lists are different sizes, exit immediately
if (updatedBitstreams.size() != currentBitstreams.size()) {
log.warn(LogHelper.getHeader(context,
- "Size of old list and new list do not match. Bitstream order will not be " +
- "changed.",
- "Bundle: " + bundle.getID()));
+ "Size of old list and new list do not match. Bitstream order will not be " +
+ "changed.",
+ "Bundle: " + bundle.getID()));
return;
}
@@ -434,7 +469,7 @@ public DSpaceObject getAdminObject(Context context, Bundle bundle, int action) t
} else if (AuthorizeConfiguration.canCollectionAdminPerformBitstreamDeletion()) {
adminObject = collection;
} else if (AuthorizeConfiguration
- .canCommunityAdminPerformBitstreamDeletion()) {
+ .canCommunityAdminPerformBitstreamDeletion()) {
adminObject = community;
}
break;
@@ -442,10 +477,10 @@ public DSpaceObject getAdminObject(Context context, Bundle bundle, int action) t
if (AuthorizeConfiguration.canItemAdminPerformBitstreamCreation()) {
adminObject = item;
} else if (AuthorizeConfiguration
- .canCollectionAdminPerformBitstreamCreation()) {
+ .canCollectionAdminPerformBitstreamCreation()) {
adminObject = collection;
} else if (AuthorizeConfiguration
- .canCommunityAdminPerformBitstreamCreation()) {
+ .canCommunityAdminPerformBitstreamCreation()) {
adminObject = community;
}
break;
@@ -477,7 +512,7 @@ public void update(Context context, Bundle bundle) throws SQLException, Authoriz
// Check authorisation
//AuthorizeManager.authorizeAction(ourContext, this, Constants.WRITE);
log.info(LogHelper.getHeader(context, "update_bundle", "bundle_id="
- + bundle.getID()));
+ + bundle.getID()));
super.update(context, bundle);
bundleDAO.save(context, bundle);
@@ -485,10 +520,10 @@ public void update(Context context, Bundle bundle) throws SQLException, Authoriz
if (bundle.isModified() || bundle.isMetadataModified()) {
if (bundle.isMetadataModified()) {
context.addEvent(new Event(Event.MODIFY_METADATA, bundle.getType(), bundle.getID(), bundle.getDetails(),
- getIdentifiers(context, bundle)));
+ getIdentifiers(context, bundle)));
}
context.addEvent(new Event(Event.MODIFY, Constants.BUNDLE, bundle.getID(),
- null, getIdentifiers(context, bundle)));
+ null, getIdentifiers(context, bundle)));
bundle.clearModified();
bundle.clearDetails();
}
@@ -497,12 +532,12 @@ public void update(Context context, Bundle bundle) throws SQLException, Authoriz
@Override
public void delete(Context context, Bundle bundle) throws SQLException, AuthorizeException, IOException {
log.info(LogHelper.getHeader(context, "delete_bundle", "bundle_id="
- + bundle.getID()));
+ + bundle.getID()));
authorizeService.authorizeAction(context, bundle, Constants.DELETE);
context.addEvent(new Event(Event.DELETE, Constants.BUNDLE, bundle.getID(),
- bundle.getName(), getIdentifiers(context, bundle)));
+ bundle.getName(), getIdentifiers(context, bundle)));
// Remove bitstreams
List bitstreams = bundle.getBitstreams();
diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java
index 7dadde72c90a..dbe2d35efe1e 100644
--- a/dspace-api/src/main/java/org/dspace/content/Collection.java
+++ b/dspace-api/src/main/java/org/dspace/content/Collection.java
@@ -29,6 +29,7 @@
import javax.persistence.Transient;
import org.dspace.authorize.AuthorizeException;
+import org.dspace.browse.ItemCountException;
import org.dspace.content.comparator.NameAscendingComparator;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
@@ -341,4 +342,17 @@ private CollectionService getCollectionService() {
return collectionService;
}
+ /**
+ * return count of the collection items
+ *
+ * @return int
+ */
+ public int countArchivedItems() {
+ try {
+ return collectionService.countArchivedItems(this);
+ } catch (ItemCountException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
index 367c7a5d34b1..36523e7cf946 100644
--- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
@@ -35,6 +35,8 @@
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
+import org.dspace.browse.ItemCountException;
+import org.dspace.browse.ItemCounter;
import org.dspace.content.dao.CollectionDAO;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CollectionService;
@@ -1217,4 +1219,35 @@ public int countCollectionsAdministeredByEntityType(String query, String entityT
discoverQuery, query, entityType).getTotalSearchResults();
}
+ @Override
+ @SuppressWarnings("rawtypes")
+ public List findAllCollectionsByEntityType(Context context, String entityType)
+ throws SearchServiceException {
+ List collectionList = new ArrayList<>();
+
+ DiscoverQuery discoverQuery = new DiscoverQuery();
+ discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
+ discoverQuery.addFilterQueries("dspace.entity.type:" + entityType);
+
+ DiscoverResult discoverResult = searchService.search(context, discoverQuery);
+ List solrIndexableObjects = discoverResult.getIndexableObjects();
+
+ for (IndexableObject solrCollection : solrIndexableObjects) {
+ Collection c = ((IndexableCollection) solrCollection).getIndexedObject();
+ collectionList.add(c);
+ }
+ return collectionList;
+ }
+
+ /**
+ * Returns total collection archived items
+ *
+ * @param collection Collection
+ * @return total collection archived items
+ * @throws ItemCountException
+ */
+ @Override
+ public int countArchivedItems(Collection collection) throws ItemCountException {
+ return ItemCounter.getInstance().getCount(collection);
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java
index fa99da33091a..dd6d978936df 100644
--- a/dspace-api/src/main/java/org/dspace/content/Community.java
+++ b/dspace-api/src/main/java/org/dspace/content/Community.java
@@ -25,6 +25,7 @@
import javax.persistence.Transient;
import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.dspace.browse.ItemCountException;
import org.dspace.content.comparator.NameAscendingComparator;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
@@ -264,4 +265,16 @@ private CommunityService getCommunityService() {
return communityService;
}
+ /**
+ * return count of the community items
+ *
+ * @return int
+ */
+ public int countArchivedItems() {
+ try {
+ return communityService.countArchivedItems(this);
+ } catch (ItemCountException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
index b4053a724f32..821c86dcb228 100644
--- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
@@ -25,6 +25,8 @@
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.browse.ItemCountException;
+import org.dspace.browse.ItemCounter;
import org.dspace.content.dao.CommunityDAO;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CollectionService;
@@ -82,7 +84,6 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp
protected CommunityServiceImpl() {
super();
-
}
@Override
@@ -712,4 +713,16 @@ public Community findByLegacyId(Context context, int id) throws SQLException {
public int countTotal(Context context) throws SQLException {
return communityDAO.countRows(context);
}
+
+ /**
+ * Returns total community archived items
+ *
+ * @param community Community
+ * @return total community archived items
+ * @throws ItemCountException
+ */
+ @Override
+ public int countArchivedItems(Community community) throws ItemCountException {
+ return ItemCounter.getInstance().getCount(community);
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
index 3ad03377cb27..6944758086ec 100644
--- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
@@ -79,7 +79,9 @@
import org.dspace.event.Event;
import org.dspace.harvest.HarvestedItem;
import org.dspace.harvest.service.HarvestedItemService;
+import org.dspace.identifier.DOI;
import org.dspace.identifier.IdentifierException;
+import org.dspace.identifier.service.DOIService;
import org.dspace.identifier.service.IdentifierService;
import org.dspace.layout.CrisLayoutBox;
import org.dspace.layout.CrisLayoutField;
@@ -146,6 +148,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl- implements It
@Autowired(required = true)
protected IdentifierService identifierService;
@Autowired(required = true)
+ protected DOIService doiService;
+ @Autowired(required = true)
protected VersioningService versioningService;
@Autowired(required = true)
protected HarvestedItemService harvestedItemService;
@@ -298,9 +302,7 @@ private List
getThumbnailFields(List crisLayoutT
* @param context
* @param item
* @param bundle
- * @param metadata
* @param value
- * @param requireOriginal
* @throws SQLException
* @return Bitstream
*/
@@ -962,6 +964,16 @@ protected void rawDelete(Context context, Item item) throws AuthorizeException,
// Remove any Handle
handleService.unbindHandle(context, item);
+ // Delete a DOI if linked to the item.
+ // If no DOI consumer or provider is configured, but a DOI remains linked to this item's uuid,
+ // hibernate will throw a foreign constraint exception.
+ // Here we use the DOI service directly as it is able to manage DOIs even without any configured
+ // consumer or provider.
+ DOI doi = doiService.findDOIByDSpaceObject(context, item);
+ if (doi != null) {
+ doi.setDSpaceObject(null);
+ }
+
// remove version attached to the item
removeVersion(context, item);
@@ -1196,16 +1208,23 @@ public void inheritCollectionDefaultPolicies(Context context, Item item, Collect
@Override
public void adjustBundleBitstreamPolicies(Context context, Item item, Collection collection)
throws SQLException, AuthorizeException {
- List defaultCollectionPolicies = authorizeService
- .getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ);
+ // Bundles should inherit from DEFAULT_ITEM_READ so that if the item is readable, the files
+ // can be listed (even if they are themselves not readable as per DEFAULT_BITSTREAM_READ or other
+ // policies or embargos applied
+ List defaultCollectionBundlePolicies = authorizeService
+ .getPoliciesActionFilter(context, collection, Constants.DEFAULT_ITEM_READ);
+ // Bitstreams should inherit from DEFAULT_BITSTREAM_READ
+ List defaultCollectionBitstreamPolicies = authorizeService
+ .getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ);
List defaultItemPolicies = authorizeService.findPoliciesByDSOAndType(context, item,
ResourcePolicy.TYPE_CUSTOM);
- if (defaultCollectionPolicies.size() < 1) {
+ if (defaultCollectionBitstreamPolicies.size() < 1) {
throw new SQLException("Collection " + collection.getID()
+ " (" + collection.getHandle() + ")"
+ " has no default bitstream READ policies");
}
+ // TODO: should we also throw an exception if no DEFAULT_ITEM_READ?
// remove all policies from bundles, add new ones
// Remove bundles
@@ -1216,18 +1235,44 @@ public void adjustBundleBitstreamPolicies(Context context, Item item, Collection
authorizeService.removeAllPoliciesByDSOAndType(context, mybundle, ResourcePolicy.TYPE_SUBMISSION);
authorizeService.removeAllPoliciesByDSOAndType(context, mybundle, ResourcePolicy.TYPE_WORKFLOW);
addCustomPoliciesNotInPlace(context, mybundle, defaultItemPolicies);
- addDefaultPoliciesNotInPlace(context, mybundle, defaultCollectionPolicies);
+ addDefaultPoliciesNotInPlace(context, mybundle, defaultCollectionBundlePolicies);
for (Bitstream bitstream : mybundle.getBitstreams()) {
// if come from InstallItem: remove all submission/workflow policies
- authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_SUBMISSION);
- authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW);
- addCustomPoliciesNotInPlace(context, bitstream, defaultItemPolicies);
- addDefaultPoliciesNotInPlace(context, bitstream, defaultCollectionPolicies);
+ removeAllPoliciesAndAddDefault(context, bitstream, defaultItemPolicies,
+ defaultCollectionBitstreamPolicies);
}
}
}
+ @Override
+ public void adjustBitstreamPolicies(Context context, Item item, Collection collection , Bitstream bitstream)
+ throws SQLException, AuthorizeException {
+ List defaultCollectionPolicies = authorizeService
+ .getPoliciesActionFilter(context, collection, Constants.DEFAULT_BITSTREAM_READ);
+
+ List defaultItemPolicies = authorizeService.findPoliciesByDSOAndType(context, item,
+ ResourcePolicy.TYPE_CUSTOM);
+ if (defaultCollectionPolicies.size() < 1) {
+ throw new SQLException("Collection " + collection.getID()
+ + " (" + collection.getHandle() + ")"
+ + " has no default bitstream READ policies");
+ }
+
+ // remove all policies from bitstream, add new ones
+ removeAllPoliciesAndAddDefault(context, bitstream, defaultItemPolicies, defaultCollectionPolicies);
+ }
+
+ private void removeAllPoliciesAndAddDefault(Context context, Bitstream bitstream,
+ List defaultItemPolicies,
+ List defaultCollectionPolicies)
+ throws SQLException, AuthorizeException {
+ authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_SUBMISSION);
+ authorizeService.removeAllPoliciesByDSOAndType(context, bitstream, ResourcePolicy.TYPE_WORKFLOW);
+ addCustomPoliciesNotInPlace(context, bitstream, defaultItemPolicies);
+ addDefaultPoliciesNotInPlace(context, bitstream, defaultCollectionPolicies);
+ }
+
@Override
public void adjustItemPolicies(Context context, Item item, Collection collection)
throws SQLException, AuthorizeException {
@@ -1444,9 +1489,18 @@ public boolean isInProgressSubmission(Context context, Item item) throws SQLExce
*/
- @Override
+ /**
+ * Add the default policies, which have not been already added to the given DSpace object
+ *
+ * @param context The relevant DSpace Context.
+ * @param dso The DSpace Object to add policies to
+ * @param defaultCollectionPolicies list of policies
+ * @throws SQLException An exception that provides information on a database access error or other errors.
+ * @throws AuthorizeException Exception indicating the current user of the context does not have permission
+ * to perform a particular action.
+ */
public void addDefaultPoliciesNotInPlace(Context context, DSpaceObject dso,
- List defaultCollectionPolicies) throws SQLException, AuthorizeException {
+ List defaultCollectionPolicies) throws SQLException, AuthorizeException {
boolean appendMode = configurationService
.getBooleanProperty("core.authorization.installitem.inheritance-read.append-mode", false);
for (ResourcePolicy defaultPolicy : defaultCollectionPolicies) {
@@ -2138,4 +2192,12 @@ public boolean isLatestVersion(Context context, Item item) throws SQLException {
}
+ @Override
+ public void addResourcePolicy(Context context, Item item, int actionID, EPerson eperson)
+ throws SQLException, AuthorizeException {
+ ResourcePolicy resourcePolicy =
+ this.authorizeService.createResourcePolicy(context, item, null, eperson, actionID, null);
+ item.getResourcePolicies().add(resourcePolicy);
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java
index fa45ed15e007..7babfce3145b 100644
--- a/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java
+++ b/dspace-api/src/main/java/org/dspace/content/MetadataSchemaEnum.java
@@ -18,7 +18,8 @@ public enum MetadataSchemaEnum {
EPERSON("eperson"),
RELATION("relation"),
CRIS("cris"),
- OAIRECERIF("oairecerif");
+ OAIRECERIF("oairecerif"),
+ PERSON("person");
/**
* The String representation of the MetadataSchemaEnum
diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataValue.java b/dspace-api/src/main/java/org/dspace/content/MetadataValue.java
index 639cec0e0c30..923b5575fa46 100644
--- a/dspace-api/src/main/java/org/dspace/content/MetadataValue.java
+++ b/dspace-api/src/main/java/org/dspace/content/MetadataValue.java
@@ -61,7 +61,7 @@ public class MetadataValue implements ReloadableEntity {
* The value of the field
*/
@Lob
- @Type(type = "org.dspace.storage.rdbms.hibernate.DatabaseAwareLobType")
+ @Type(type = "org.hibernate.type.TextType")
@Column(name = "text_value")
private String value;
diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataServiceImpl.java
index daf9a34378ac..9e0c72258e56 100644
--- a/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/RelationshipMetadataServiceImpl.java
@@ -110,7 +110,8 @@ protected List findLatestForDiscoveryMetadataValues(
// on the left item as a storage/performance improvement.
// As a consequence, when searching for related items (using discovery)
// on the pages of the right items you won't be able to find the left item.
- if (relationshipType.getTilted() != RIGHT && itemEntityType.equals(relationshipType.getLeftType())) {
+ if (relationshipType.getTilted() != RIGHT
+ && Objects.equals(relationshipType.getLeftType(), itemEntityType)) {
String element = relationshipType.getLeftwardType();
List data = relationshipService
.findByLatestItemAndRelationshipType(context, item, relationshipType, true);
diff --git a/dspace-api/src/main/java/org/dspace/content/RelationshipPlacesIndexingServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/RelationshipPlacesIndexingServiceImpl.java
index 1ed14b4fbe1f..f29e209d7790 100644
--- a/dspace-api/src/main/java/org/dspace/content/RelationshipPlacesIndexingServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/RelationshipPlacesIndexingServiceImpl.java
@@ -55,7 +55,9 @@ public void updateRelationReferences(final Context context, final Relationship r
if (singleDirectionRelationship("right", relationship.getRelationshipType())) {
times = relation.getLeftPlace() - relation.getRightPlace();
}
- rightItemsIdsToAdd.addAll(Collections.nCopies(times, relation.getRightItem().getID().toString()));
+ if (times > 0) {
+ rightItemsIdsToAdd.addAll(Collections.nCopies(times, relation.getRightItem().getID().toString()));
+ }
}
if (!rightItemsIdsToAdd.isEmpty()) {
@@ -79,7 +81,9 @@ public void updateRelationReferences(final Context context, final Relationship r
if (singleDirectionRelationship("left", relationship.getRelationshipType())) {
times = relation.getRightPlace() - relation.getLeftPlace();
}
- leftItemsIdsToAdd.addAll(Collections.nCopies(times, relation.getLeftItem().getID().toString()));
+ if (times > 0) {
+ leftItemsIdsToAdd.addAll(Collections.nCopies(times, relation.getLeftItem().getID().toString()));
+ }
}
if (!leftItemsIdsToAdd.isEmpty()) {
@@ -102,7 +106,9 @@ private void addRightItemsReferences(final Context context, final Relationship r
if (singleDirectionRelationship("right", relationship.getRelationshipType())) {
times = leftItemRelation.getLeftPlace() - leftItemRelation.getRightPlace();
}
- rightItemsToAdd.addAll(Collections.nCopies(times, leftItemRelation.getRightItem().getID().toString()));
+ if (times > 0) {
+ rightItemsToAdd.addAll(Collections.nCopies(times, leftItemRelation.getRightItem().getID().toString()));
+ }
}
if (!rightItemsToAdd.isEmpty()) {
indexingService.updateRelationForItem(leftItem.getID().toString(),
@@ -122,7 +128,9 @@ private void addLeftItemsReferences(final Context context, final Relationship re
if (singleDirectionRelationship("left", relationship.getRelationshipType())) {
times = leftItemRelation.getRightPlace() - leftItemRelation.getLeftPlace();
}
- rightItemsToAdd.addAll(Collections.nCopies(times, leftItemRelation.getLeftItem().getID().toString()));
+ if (times > 0) {
+ rightItemsToAdd.addAll(Collections.nCopies(times, leftItemRelation.getLeftItem().getID().toString()));
+ }
}
if (!rightItemsToAdd.isEmpty()) {
indexingService.updateRelationForItem(rightItem.getID().toString(),
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java
index 6e0800457397..b0b84a0d2dcf 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/ChoiceAuthorityServiceImpl.java
@@ -7,6 +7,7 @@
*/
package org.dspace.content.authority;
+import static java.lang.Integer.MAX_VALUE;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
@@ -37,6 +38,8 @@
import org.dspace.core.Constants;
import org.dspace.core.Utils;
import org.dspace.core.service.PluginService;
+import org.dspace.discovery.configuration.DiscoveryConfigurationService;
+import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.services.ConfigurationService;
import org.dspace.submit.model.UploadConfiguration;
import org.dspace.submit.model.UploadConfigurationService;
@@ -93,6 +96,9 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
protected Map>> authoritiesFormDefinitions =
new HashMap>>();
+ // Map of vocabulary authorities to and their index info equivalent
+ protected Map vocabularyIndexMap = new HashMap<>();
+
// the item submission reader
private SubmissionConfigReader itemSubmissionConfigReader;
@@ -106,6 +112,8 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
protected AuthorityServiceUtils authorityServiceUtils;
@Autowired(required = true)
protected ItemService itemService;
+ @Autowired
+ private DiscoveryConfigurationService searchConfigurationService;
final static String CHOICES_PLUGIN_PREFIX = "choices.plugin.";
final static String CHOICES_PRESENTATION_PREFIX = "choices.presentation.";
@@ -343,16 +351,26 @@ private void loadChoiceAuthorityConfigurations() {
*/
private void autoRegisterChoiceAuthorityFromInputReader() {
try {
- List submissionConfigs = itemSubmissionConfigReader
- .getAllSubmissionConfigs(Integer.MAX_VALUE, 0);
+ List submissionConfigs = itemSubmissionConfigReader.getAllSubmissionConfigs(MAX_VALUE, 0);
DCInputsReader dcInputsReader = new DCInputsReader();
// loop over all the defined item submission configuration
for (SubmissionConfig subCfg : submissionConfigs) {
String submissionName = subCfg.getSubmissionName();
List inputsBySubmissionName = dcInputsReader.getInputsBySubmissionName(submissionName);
- autoRegisterChoiceAuthorityFromSubmissionForms(Constants.ITEM, submissionName,
- inputsBySubmissionName);
+ List inputsByGroupOfAllSteps = new ArrayList();
+ try {
+ List inputsByGroup = dcInputsReader.getInputsByGroup(submissionName);
+ inputsByGroupOfAllSteps.addAll(inputsByGroup);
+ for (DCInputSet step : inputsBySubmissionName) {
+ List inputsByGroupOfStep = dcInputsReader.getInputsByGroup(step.getFormName());
+ inputsByGroupOfAllSteps.addAll(inputsByGroupOfStep);
+ }
+ } catch (DCInputsReaderException e) {
+ log.warn("Cannot load the groups of the submission: " + submissionName, e);
+ }
+ inputsBySubmissionName.addAll(inputsByGroupOfAllSteps);
+ autoRegisterChoiceAuthorityFromSubmissionForms(Constants.ITEM, submissionName, inputsBySubmissionName);
}
// loop over all the defined bitstream metadata submission configuration
for (UploadConfiguration uploadCfg : uploadConfigurationService.getMap().values()) {
@@ -363,8 +381,7 @@ private void autoRegisterChoiceAuthorityFromInputReader() {
}
} catch (DCInputsReaderException e) {
// the system is in an illegal state as the submission definition is not valid
- throw new IllegalStateException("Error reading the item submission configuration: " + e.getMessage(),
- e);
+ throw new IllegalStateException("Error reading the item submission configuration: " + e.getMessage(), e);
}
}
@@ -690,4 +707,50 @@ private boolean isLinkableToAnEntityWithEntityType(ChoiceAuthority choiceAuthori
return choiceAuthority instanceof LinkableEntityAuthority
&& entityType.equals(((LinkableEntityAuthority) choiceAuthority).getLinkedEntityType());
}
+
+ @Override
+ public DSpaceControlledVocabularyIndex getVocabularyIndex(String nameVocab) {
+ if (this.vocabularyIndexMap.containsKey(nameVocab)) {
+ return this.vocabularyIndexMap.get(nameVocab);
+ } else {
+ init();
+ ChoiceAuthority source = this.getChoiceAuthorityByAuthorityName(nameVocab);
+ if (source != null && source instanceof DSpaceControlledVocabulary) {
+ Set metadataFields = new HashSet<>();
+ Map> formsToFields = this.authoritiesFormDefinitions.get(nameVocab);
+ for (Map.Entry> formToField : formsToFields.entrySet()) {
+ metadataFields.addAll(formToField.getValue().stream().map(value ->
+ StringUtils.replace(value, "_", "."))
+ .collect(Collectors.toList()));
+ }
+ DiscoverySearchFilterFacet matchingFacet = null;
+ for (DiscoverySearchFilterFacet facetConfig : searchConfigurationService.getAllFacetsConfig()) {
+ boolean coversAllFieldsFromVocab = true;
+ for (String fieldFromVocab: metadataFields) {
+ boolean coversFieldFromVocab = false;
+ for (String facetMdField: facetConfig.getMetadataFields()) {
+ if (facetMdField.startsWith(fieldFromVocab)) {
+ coversFieldFromVocab = true;
+ break;
+ }
+ }
+ if (!coversFieldFromVocab) {
+ coversAllFieldsFromVocab = false;
+ break;
+ }
+ }
+ if (coversAllFieldsFromVocab) {
+ matchingFacet = facetConfig;
+ break;
+ }
+ }
+ DSpaceControlledVocabularyIndex vocabularyIndex =
+ new DSpaceControlledVocabularyIndex((DSpaceControlledVocabulary) source, metadataFields,
+ matchingFacet);
+ this.vocabularyIndexMap.put(nameVocab, vocabularyIndex);
+ return vocabularyIndex;
+ }
+ return null;
+ }
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
index 9695f9c32552..ca9f42f13a3d 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
@@ -48,6 +48,8 @@
* fields.
*/
public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority {
+ public static final String UNKNOWN_KEY = "UNKNOWN KEY ";
+
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(DCInputAuthority.class);
/**
@@ -92,7 +94,7 @@ public static String[] getPluginNames() {
initPluginNames();
}
- return (String[]) ArrayUtils.clone(pluginNames);
+ return ArrayUtils.clone(pluginNames);
}
private static synchronized void initPluginNames() {
@@ -205,17 +207,17 @@ public String getLabel(String key, String locale) {
String[] labelsLocale = labels.get(locale);
int pos = -1;
// search in the values to return the label
- for (int i = 0; i < valuesLocale.length; i++) {
+ for (int i = 0; valuesLocale != null && i < valuesLocale.length; i++) {
if (valuesLocale[i].equals(key)) {
pos = i;
break;
}
}
- if (pos != -1) {
+ if (pos != -1 && labelsLocale != null) {
// return the label in the same position where we found the value
return labelsLocale[pos];
} else {
- return "UNKNOWN KEY " + key;
+ return UNKNOWN_KEY + key;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabularyIndex.java b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabularyIndex.java
new file mode 100644
index 000000000000..bf8194dbd53b
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabularyIndex.java
@@ -0,0 +1,47 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.content.authority;
+
+import java.util.Set;
+
+import org.dspace.browse.BrowseIndex;
+import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
+
+/**
+ * Helper class to transform a {@link org.dspace.content.authority.DSpaceControlledVocabulary} into a
+ * {@code BrowseIndexRest}
+ * cached by {@link org.dspace.content.authority.service.ChoiceAuthorityService#getVocabularyIndex(String)}
+ *
+ * @author Marie Verdonck (Atmire) on 04/05/2023
+ */
+public class DSpaceControlledVocabularyIndex extends BrowseIndex {
+
+ protected DSpaceControlledVocabulary vocabulary;
+ protected Set metadataFields;
+ protected DiscoverySearchFilterFacet facetConfig;
+
+ public DSpaceControlledVocabularyIndex(DSpaceControlledVocabulary controlledVocabulary, Set metadataFields,
+ DiscoverySearchFilterFacet facetConfig) {
+ super(controlledVocabulary.vocabularyName);
+ this.vocabulary = controlledVocabulary;
+ this.metadataFields = metadataFields;
+ this.facetConfig = facetConfig;
+ }
+
+ public DSpaceControlledVocabulary getVocabulary() {
+ return vocabulary;
+ }
+
+ public Set getMetadataFields() {
+ return this.metadataFields;
+ }
+
+ public DiscoverySearchFilterFacet getFacetConfig() {
+ return this.facetConfig;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/ItemAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/ItemAuthority.java
index 6ec39db9764f..173ea83f62ad 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/ItemAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/ItemAuthority.java
@@ -42,6 +42,7 @@
import org.dspace.util.ItemAuthorityUtils;
import org.dspace.util.UUIDUtils;
import org.dspace.utils.DSpace;
+import org.dspace.web.ContextUtil;
/**
* Sample authority to link a dspace item with another (i.e a publication with
@@ -58,7 +59,7 @@ public class ItemAuthority implements ChoiceAuthority, LinkableEntityAuthority {
/** the name assigned to the specific instance by the PluginService, @see {@link NameAwarePlugin} **/
private String authorityName;
- private DSpace dspace = new DSpace();
+ protected DSpace dspace = new DSpace();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
@@ -181,9 +182,8 @@ private List getChoiceListFromQueryResults(SolrDocumentList results, Str
public String getLabel(String key, String locale) {
String title = key;
if (key != null) {
- Context context = null;
+ Context context = getContext();
try {
- context = new Context();
DSpaceObject dso = itemService.find(context, UUIDUtils.fromString(key));
if (dso != null) {
title = dso.getName();
@@ -292,4 +292,9 @@ private boolean hasValidExternalSource(String sourceIdentifier) {
return false;
}
+ private Context getContext() {
+ Context context = ContextUtil.obtainCurrentRequestContext();
+ return context != null ? context : new Context();
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/OrcidAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/OrcidAuthority.java
index 4dfe09cdec64..8978c1f90fcc 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/OrcidAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/OrcidAuthority.java
@@ -43,9 +43,9 @@ public class OrcidAuthority extends ItemAuthority {
private static final Logger LOGGER = LoggerFactory.getLogger(OrcidAuthority.class);
- public static final String ORCID_EXTRA = "data-person_identifier_orcid";
+ public static final String DEFAULT_ORCID_KEY = "person_identifier_orcid";
- public static final String INSTITUTION_EXTRA = "institution-affiliation-name";
+ public static final String DEFAULT_INSTITUTION_KEY = "institution-affiliation-name";
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
@@ -131,11 +131,24 @@ private String composeAuthorityValue(String orcid) {
private Map composeExtras(ExpandedResult result) {
Map extras = new HashMap<>();
- extras.put(ORCID_EXTRA, result.getOrcidId());
-
+ String orcidIdKey = getOrcidIdKey();
+ String orcidId = result.getOrcidId();
+ if (StringUtils.isNotBlank(orcidId)) {
+ if (useOrcidIDAsData()) {
+ extras.put("data-" + orcidIdKey, orcidId);
+ }
+ if (useOrcidIDForDisplaying()) {
+ extras.put(orcidIdKey, orcidId);
+ }
+ }
+ String institutionKey = getInstitutionKey();
String[] institutionNames = result.getInstitutionNames();
- if (ArrayUtils.isNotEmpty(institutionNames)) {
- extras.put(INSTITUTION_EXTRA, String.join(", ", institutionNames));
+
+ if (ArrayUtils.isNotEmpty(institutionNames) && useInstitutionAsData()) {
+ extras.put("data-" + institutionKey, String.join(", ", institutionNames));
+ }
+ if (ArrayUtils.isNotEmpty(institutionNames) && useInstitutionForDisplaying()) {
+ extras.put(institutionKey, String.join(", ", institutionNames));
}
return extras;
@@ -165,4 +178,41 @@ public static void setAccessToken(String accessToken) {
OrcidAuthority.accessToken = accessToken;
}
+ public String getOrcidIdKey() {
+ return configurationService.getProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".orcid-id.key",
+ DEFAULT_ORCID_KEY);
+ }
+
+ public String getInstitutionKey() {
+ return configurationService.getProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".institution.key",
+ DEFAULT_INSTITUTION_KEY);
+ }
+
+ public boolean useInstitutionAsData() {
+ return configurationService
+ .getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".institution.as-data", true);
+ }
+
+ public boolean useInstitutionForDisplaying() {
+ return configurationService
+ .getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".institution.display", true);
+ }
+
+ public boolean useOrcidIDAsData() {
+ return configurationService
+ .getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".orcid-id.as-data", true);
+ }
+
+ public boolean useOrcidIDForDisplaying() {
+ return configurationService
+ .getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + ".orcid-id.display", true);
+
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/RorOrgUnitAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/RorOrgUnitAuthority.java
new file mode 100644
index 000000000000..de2271901819
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/content/authority/RorOrgUnitAuthority.java
@@ -0,0 +1,152 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+
+package org.dspace.content.authority;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.StringUtils;
+import org.dspace.content.authority.factory.ItemAuthorityServiceFactory;
+import org.dspace.importer.external.datamodel.ImportRecord;
+import org.dspace.importer.external.exception.MetadataSourceException;
+import org.dspace.importer.external.metadatamapping.MetadatumDTO;
+import org.dspace.importer.external.ror.service.RorImportMetadataSourceServiceImpl;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.utils.DSpace;
+
+public class RorOrgUnitAuthority extends ItemAuthority {
+
+ private final RorImportMetadataSourceServiceImpl rorImportMetadataSource = new DSpace().getServiceManager()
+ .getServicesByType(RorImportMetadataSourceServiceImpl.class).get(0);
+
+ private final ItemAuthorityServiceFactory itemAuthorityServiceFactory =
+ dspace.getServiceManager().getServiceByName("itemAuthorityServiceFactory", ItemAuthorityServiceFactory.class);
+ private final ConfigurationService configurationService =
+ DSpaceServicesFactory.getInstance().getConfigurationService();
+
+ private String authorityName;
+
+ @Override
+ public Choices getMatches(String text, int start, int limit, String locale) {
+
+ super.setPluginInstanceName(authorityName);
+ Choices solrChoices = super.getMatches(text, start, limit, locale);
+
+ try {
+ return solrChoices.values.length == 0 ? getRORApiMatches(text, start, limit) : solrChoices;
+ } catch (MetadataSourceException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Choices getRORApiMatches(String text, int start, int limit) throws MetadataSourceException {
+ Choice[] rorApiChoices = getChoiceFromRORQueryResults(rorImportMetadataSource.getRecords(text, 0, 0))
+ .toArray(new Choice[0]);
+
+ int confidenceValue = itemAuthorityServiceFactory.getInstance(authorityName)
+ .getConfidenceForChoices(rorApiChoices);
+
+ return new Choices(rorApiChoices, start, rorApiChoices.length, confidenceValue,
+ rorApiChoices.length > (start + limit), 0);
+ }
+
+ private List getChoiceFromRORQueryResults(Collection orgUnits) {
+ return orgUnits
+ .stream()
+ .map(orgUnit -> new Choice(composeAuthorityValue(getIdentifier(orgUnit)), getName(orgUnit),
+ getName(orgUnit), buildExtras(orgUnit)))
+ .collect(Collectors.toList());
+ }
+
+ private String getIdentifier(ImportRecord orgUnit) {
+ return orgUnit.getValue("organization", "identifier", "ror").stream()
+ .findFirst()
+ .map(metadata -> metadata.getValue())
+ .orElse(null);
+ }
+
+ private String getName(ImportRecord orgUnit) {
+ return orgUnit.getValue("dc", "title", null).stream()
+ .findFirst()
+ .map(metadata -> metadata.getValue())
+ .orElse(null);
+ }
+
+ private Map buildExtras(ImportRecord orgUnit) {
+
+ Map extras = new LinkedHashMap();
+
+ addExtra(extras, getIdentifier(orgUnit), "id");
+
+ orgUnit.getSingleValue("dc", "type", null)
+ .ifPresent(type -> addExtra(extras, type, "type"));
+
+ String acronym = orgUnit.getValue("oairecerif", "acronym", null).stream()
+ .map(MetadatumDTO::getValue)
+ .collect(Collectors.joining(", "));
+
+ if (StringUtils.isNotBlank(acronym)) {
+ addExtra(extras, acronym, "acronym");
+ }
+
+ return extras;
+ }
+
+ private void addExtra(Map extras, String value, String extraType) {
+
+ String key = getKey(extraType);
+
+ if (useAsData(extraType)) {
+ extras.put("data-" + key, value);
+ }
+ if (useForDisplaying(extraType)) {
+ extras.put(key, value);
+ }
+
+ }
+
+ private boolean useForDisplaying(String extraType) {
+ return configurationService.getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + "." + extraType + ".display", true);
+ }
+
+ private boolean useAsData(String extraType) {
+ return configurationService.getBooleanProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + "." + extraType + ".as-data", true);
+ }
+
+ private String getKey(String extraType) {
+ return configurationService.getProperty("cris.OrcidAuthority."
+ + getPluginInstanceName() + "." + extraType + ".key", "ror_orgunit_" + extraType);
+ }
+
+ private String composeAuthorityValue(String rorId) {
+ String prefix = configurationService.getProperty("ror.authority.prefix", "will be referenced::ROR-ID::");
+ return prefix + rorId;
+ }
+
+ @Override
+ public String getLinkedEntityType() {
+ return configurationService.getProperty("cris.ItemAuthority." + authorityName + ".entityType");
+ }
+
+ @Override
+ public void setPluginInstanceName(String name) {
+ authorityName = name;
+ }
+
+ @Override
+ public String getPluginInstanceName() {
+ return authorityName;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SherpaAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/SherpaAuthority.java
index 44bd406ce43c..54d8f3325ceb 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/SherpaAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/SherpaAuthority.java
@@ -173,9 +173,4 @@ private boolean isLocalItemChoicesEnabled() {
return configurationService.getBooleanProperty("cris." + this.authorityName + ".local-item-choices-enabled");
}
- @Override
- public Map getExternalSource() {
- return Map.of();
- }
-
}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java
index 497fa08f2faf..123626cd0965 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/SolrAuthority.java
@@ -200,8 +200,8 @@ protected void addExternalResults(String text, ArrayList choices, List findByCommunity(Context context, Community community)
query.setParameter("community", community);
- return iterate(query);
+ return iterate(context, query, Bitstream.class);
}
@Override
@@ -99,7 +99,7 @@ public Iterator findByCollection(Context context, Collection collecti
query.setParameter("collection", collection);
- return iterate(query);
+ return iterate(context, query, Bitstream.class);
}
@Override
@@ -111,7 +111,7 @@ public Iterator findByItem(Context context, Item item) throws SQLExce
query.setParameter("item", item);
- return iterate(query);
+ return iterate(context, query, Bitstream.class);
}
@Override
@@ -151,14 +151,14 @@ public Iterator findShowableByItem(Context context, UUID itemId, Stri
query.setParameter("itemId", itemId);
query.setParameter("bundleName", bundleName);
- return iterate(query);
+ return iterate(context, query, Bitstream.class);
}
@Override
public Iterator findByStoreNumber(Context context, Integer storeNumber) throws SQLException {
Query query = createQuery(context, "select b from Bitstream b where b.storeNumber = :storeNumber");
query.setParameter("storeNumber", storeNumber);
- return iterate(query);
+ return iterate(context, query, Bitstream.class);
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
index 378084ee8c43..443268cbbb7a 100644
--- a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
@@ -58,7 +58,7 @@ protected ItemDAOImpl() {
public Iterator- findAll(Context context, boolean archived) throws SQLException {
Query query = createQuery(context, "FROM Item WHERE inArchive=:in_archive ORDER BY id");
query.setParameter("in_archive", archived);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -67,7 +67,7 @@ public Iterator
- findAll(Context context, boolean archived, int limit, int
query.setParameter("in_archive", archived);
query.setFirstResult(offset);
query.setMaxResults(limit);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@@ -77,7 +77,7 @@ public Iterator
- findAll(Context context, boolean archived, boolean withdra
"FROM Item WHERE inArchive=:in_archive or withdrawn=:withdrawn ORDER BY id");
query.setParameter("in_archive", archived);
query.setParameter("withdrawn", withdrawn);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -91,7 +91,7 @@ public Iterator
- findAllRegularItems(Context context) throws SQLException {
"WHERE i.inArchive=true or i.withdrawn=true or (i.inArchive=false and v.id IS NOT NULL) " +
"ORDER BY i.id"
);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -115,7 +115,7 @@ public Iterator
- findAll(Context context, boolean archived,
if (lastModified != null) {
query.setParameter("last_modified", lastModified, TemporalType.TIMESTAMP);
}
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -124,7 +124,7 @@ public Iterator
- findBySubmitter(Context context, EPerson eperson) throws S
"FROM Item WHERE inArchive=:in_archive and submitter=:submitter ORDER BY id");
query.setParameter("in_archive", true);
query.setParameter("submitter", eperson);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -135,7 +135,7 @@ public Iterator
- findBySubmitter(Context context, EPerson eperson, boolean
}
Query query = createQuery(context, "FROM Item WHERE submitter=:submitter ORDER BY id");
query.setParameter("submitter", eperson);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -154,7 +154,7 @@ public Iterator
- findBySubmitter(Context context, EPerson eperson, Metadata
hibernateQuery.setParameter("in_archive", true);
hibernateQuery.setParameter("submitter", eperson);
hibernateQuery.setMaxResults(limit);
- return iterate(hibernateQuery);
+ return iterate(context, hibernateQuery, Item.class);
}
@Override
@@ -172,7 +172,7 @@ public Iterator
- findByMetadataField(Context context, MetadataField metadat
if (value != null) {
query.setParameter("text_value", value);
}
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -189,7 +189,7 @@ public Iterator
- findByMetadataField(Context context, MetadataField metadat
if (value != null) {
query.setParameter("text_value", value);
}
- return iterate(query);
+ return iterate(context, query, Item.class);
}
enum OP {
@@ -316,7 +316,7 @@ public Iterator
- findByAuthorityValue(Context context, MetadataField metada
query.setParameter("in_archive", inArchive);
query.setParameter("metadata_field", metadataField);
query.setParameter("authority", authority);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -333,7 +333,7 @@ public Iterator
- findArchivedByCollection(Context context, Collection colle
if (limit != null) {
query.setMaxResults(limit);
}
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -371,7 +371,7 @@ public Iterator
- findAllByCollection(Context context, Collection collection
"select i from Item i join i.collections c WHERE :collection IN c ORDER BY i.id");
query.setParameter("collection", collection);
- return iterate(query);
+ return iterate(context, query, Item.class);
}
@Override
@@ -388,7 +388,7 @@ public Iterator