Merge branch 'main' into fix-issue-10536_relation-field-requiredissue-main

This commit is contained in:
abhinav
2025-05-19 18:11:13 +02:00
210 changed files with 6988 additions and 7049 deletions

View File

@@ -13,6 +13,7 @@ updates:
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
time: "02:00"
# Allow up to 10 open PRs for dependencies # Allow up to 10 open PRs for dependencies
open-pull-requests-limit: 10 open-pull-requests-limit: 10
# Group together some upgrades in a single PR # Group together some upgrades in a single PR

View File

@@ -86,17 +86,16 @@ jobs:
matrix: matrix:
# Architectures / Platforms for which we will build Docker images # Architectures / Platforms for which we will build Docker images
arch: [ 'linux/amd64', 'linux/arm64' ] arch: [ 'linux/amd64', 'linux/arm64' ]
os: [ ubuntu-latest ]
isPr: isPr:
- ${{ github.event_name == 'pull_request' }} - ${{ github.event_name == 'pull_request' }}
# If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work. # If this is a PR, we ONLY build for AMD64. For PRs we only do a sanity check test to ensure Docker builds work.
# The below exclude therefore ensures we do NOT build ARM64 for PRs. # The below exclude therefore ensures we do NOT build ARM64 for PRs.
exclude: exclude:
- isPr: true - isPr: true
os: ubuntu-latest
arch: linux/arm64 arch: linux/arm64
runs-on: ${{ matrix.os }} # If ARM64, then use the Ubuntu ARM64 runner. Otherwise, use the Ubuntu AMD64 runner
runs-on: ${{ matrix.arch == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps: steps:
# This step converts the slashes in the "arch" matrix values above into dashes & saves to env.ARCH_NAME # This step converts the slashes in the "arch" matrix values above into dashes & saves to env.ARCH_NAME
@@ -122,10 +121,6 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
# https://github.com/docker/setup-qemu-action
- name: Set up QEMU emulation to build for multiple architectures
uses: docker/setup-qemu-action@v3
# https://github.com/docker/setup-buildx-action # https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx - name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3

View File

@@ -21,67 +21,67 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Apache Software License, Version 2.0: Apache Software License, Version 2.0:
* Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net) * Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net)
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.12.261 - https://aws.amazon.com/sdkforjava) * AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.12.781 - https://aws.amazon.com/sdkforjava)
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.12.261 - https://aws.amazon.com/sdkforjava) * AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.12.781 - https://aws.amazon.com/sdkforjava)
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.261 - https://aws.amazon.com/sdkforjava) * AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.781 - https://aws.amazon.com/sdkforjava)
* JMES Path Query library (com.amazonaws:jmespath-java:1.12.261 - https://aws.amazon.com/sdkforjava) * JMES Path Query library (com.amazonaws:jmespath-java:1.12.781 - https://aws.amazon.com/sdkforjava)
* Titanium JSON-LD 1.1 (JRE11) (com.apicatalog:titanium-json-ld:1.3.2 - https://github.com/filip26/titanium-json-ld) * Titanium JSON-LD 1.1 (JRE11) (com.apicatalog:titanium-json-ld:1.3.2 - https://github.com/filip26/titanium-json-ld)
* HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc) * HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc)
* com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.19.0 - https://drewnoakes.com/code/exif/) * com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.19.0 - https://drewnoakes.com/code/exif/)
* parso (com.epam:parso:2.0.14 - https://github.com/epam/parso) * parso (com.epam:parso:2.0.14 - https://github.com/epam/parso)
* ClassMate (com.fasterxml:classmate:1.6.0 - https://github.com/FasterXML/java-classmate) * Internet Time Utility (com.ethlo.time:itu:1.7.0 - https://github.com/ethlo/itu)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.16.0 - https://github.com/FasterXML/jackson) * ClassMate (com.fasterxml:classmate:1.5.1 - https://github.com/FasterXML/java-classmate)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.16.0 - https://github.com/FasterXML/jackson-core) * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.18.2 - https://github.com/FasterXML/jackson)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.16.0 - https://github.com/FasterXML/jackson) * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.18.2 - https://github.com/FasterXML/jackson-core)
* Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.6 - http://github.com/FasterXML/jackson-dataformats-binary) * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.18.2 - https://github.com/FasterXML/jackson)
* Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.17.2 - https://github.com/FasterXML/jackson-dataformats-binary)
* Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2 - https://github.com/FasterXML/jackson-dataformats-binary) * Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2 - https://github.com/FasterXML/jackson-dataformats-binary)
* Jackson-dataformat-TOML (com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2 - https://github.com/FasterXML/jackson-dataformats-text) * Jackson-dataformat-TOML (com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2 - https://github.com/FasterXML/jackson-dataformats-text)
* Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.2 - https://github.com/FasterXML/jackson-dataformats-text) * Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.2 - https://github.com/FasterXML/jackson-dataformats-text)
* Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.15.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.2 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8)
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) * Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
* Jackson Jakarta-RS: base (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-base) * Jackson Jakarta-RS: base (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-base)
* Jackson Jakarta-RS: JSON (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-json-provider) * Jackson Jakarta-RS: JSON (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-json-provider)
* Jackson module: Jakarta XML Bind Annotations (jakarta.xml.bind) (com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.16.2 - https://github.com/FasterXML/jackson-modules-base) * Jackson module: Jakarta XML Bind Annotations (jakarta.xml.bind) (com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.16.2 - https://github.com/FasterXML/jackson-modules-base)
* Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.15.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names) * Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.18.2 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names)
* Java UUID Generator (com.fasterxml.uuid:java-uuid-generator:4.0.1 - https://github.com/cowtowncoder/java-uuid-generator) * Java UUID Generator (com.fasterxml.uuid:java-uuid-generator:4.1.0 - https://github.com/cowtowncoder/java-uuid-generator)
* Woodstox (com.fasterxml.woodstox:woodstox-core:6.5.1 - https://github.com/FasterXML/woodstox) * Woodstox (com.fasterxml.woodstox:woodstox-core:6.5.1 - https://github.com/FasterXML/woodstox)
* zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.16 - https://github.com/flipkart-incubator/zjsonpatch/) * zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.16 - https://github.com/flipkart-incubator/zjsonpatch/)
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.3 - https://github.com/ben-manes/caffeine) * Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.3 - https://github.com/ben-manes/caffeine)
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:3.1.6 - https://github.com/ben-manes/caffeine) * Caffeine cache (com.github.ben-manes.caffeine:caffeine:3.1.8 - https://github.com/ben-manes/caffeine)
* JSON.simple (com.github.cliftonlabs:json-simple:3.0.2 - https://cliftonlabs.github.io/json-simple/)
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf) * btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
* jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils) * jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
* jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils) * jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
* json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
* json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core) * json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
* json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator) * json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
* msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple) * msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
* uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template) * uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
* JCIP Annotations under Apache License (com.github.stephenc.jcip:jcip-annotations:1.0-1 - http://stephenc.github.com/jcip-annotations) * JCIP Annotations under Apache License (com.github.stephenc.jcip:jcip-annotations:1.0-1 - http://stephenc.github.com/jcip-annotations)
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.23.0 - https://github.com/google/google-api-java-client/google-api-client)
* Google Analytics API v3-rev145-1.23.0 (com.google.apis:google-api-services-analytics:v3-rev145-1.23.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/) * FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
* Gson (com.google.code.gson:gson:2.10.1 - https://github.com/google/gson/gson) * Gson (com.google.code.gson:gson:2.12.1 - https://github.com/google/gson)
* error-prone annotations (com.google.errorprone:error_prone_annotations:2.10.0 - https://errorprone.info/error_prone_annotations) * error-prone annotations (com.google.errorprone:error_prone_annotations:2.36.0 - https://errorprone.info/error_prone_annotations)
* Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess) * Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
* Guava: Google Core Libraries for Java (com.google.guava:guava:32.0.0-jre - https://github.com/google/guava) * Guava: Google Core Libraries for Java (com.google.guava:guava:32.1.3-jre - https://github.com/google/guava)
* Guava: Google Core Libraries for Java (JDK5 Backport) (com.google.guava:guava-jdk5:17.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
* Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture) * Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
* Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.23.0 - https://github.com/google/google-http-java-client/google-http-client) * Google Guice - Core Library (com.google.inject:guice:7.0.0 - https://github.com/google/guice/guice)
* GSON extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-gson:1.41.7 - https://github.com/googleapis/google-http-java-client/google-http-client-gson) * Google Guice - Extensions - AssistedInject (com.google.inject.extensions:guice-assistedinject:7.0.0 - https://github.com/google/guice/extensions-parent/guice-assistedinject)
* Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.23.0 - https://github.com/google/google-http-java-client/google-http-client-jackson2)
* J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/) * J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
* J2ObjC Annotations (com.google.j2objc:j2objc-annotations:2.8 - https://github.com/google/j2objc/) * J2ObjC Annotations (com.google.j2objc:j2objc-annotations:2.8 - https://github.com/google/j2objc/)
* Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.33.3 - https://github.com/googleapis/google-oauth-java-client/google-oauth-client)
* ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - http://code.google.com/p/concurrentlinkedhashmap) * ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - http://code.google.com/p/concurrentlinkedhashmap)
* libphonenumber (com.googlecode.libphonenumber:libphonenumber:8.11.1 - https://github.com/google/libphonenumber/) * libphonenumber (com.googlecode.libphonenumber:libphonenumber:8.11.1 - https://github.com/google/libphonenumber/)
* Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.5 - https://jackcess.sourceforge.io) * Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.8 - https://jackcess.sourceforge.io)
* Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.2 - http://jackcessencrypt.sf.net) * Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.2 - http://jackcessencrypt.sf.net)
* json-path (com.jayway.jsonpath:json-path:2.9.0 - https://github.com/jayway/JsonPath) * json-path (com.jayway.jsonpath:json-path:2.9.0 - https://github.com/jayway/JsonPath)
* json-path-assert (com.jayway.jsonpath:json-path-assert:2.9.0 - https://github.com/jayway/JsonPath) * json-path-assert (com.jayway.jsonpath:json-path-assert:2.9.0 - https://github.com/jayway/JsonPath)
* Disruptor Framework (com.lmax:disruptor:3.4.2 - http://lmax-exchange.github.com/disruptor) * Disruptor Framework (com.lmax:disruptor:3.4.2 - http://lmax-exchange.github.com/disruptor)
* MaxMind DB Reader (com.maxmind.db:maxmind-db:2.1.0 - http://dev.maxmind.com/) * MaxMind DB Reader (com.maxmind.db:maxmind-db:2.1.0 - http://dev.maxmind.com/)
* MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.17.0 - https://dev.maxmind.com/geoip?lang=en) * MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.17.0 - https://dev.maxmind.com/geoip?lang=en)
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:9.37.3 - https://bitbucket.org/connect2id/nimbus-jose-jwt) * JsonSchemaValidator (com.networknt:json-schema-validator:1.0.76 - https://github.com/networknt/json-schema-validator)
* opencsv (com.opencsv:opencsv:5.9 - http://opencsv.sf.net) * Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:9.28 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:9.48 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
* opencsv (com.opencsv:opencsv:5.10 - http://opencsv.sf.net)
* java-libpst (com.pff:java-libpst:0.9.3 - https://github.com/rjohnsondev/java-libpst) * java-libpst (com.pff:java-libpst:0.9.3 - https://github.com/rjohnsondev/java-libpst)
* rome (com.rometools:rome:1.19.0 - http://rometools.com/rome) * rome (com.rometools:rome:1.19.0 - http://rometools.com/rome)
* rome-modules (com.rometools:rome-modules:1.19.0 - http://rometools.com/rome-modules) * rome-modules (com.rometools:rome-modules:1.19.0 - http://rometools.com/rome-modules)
@@ -98,102 +98,111 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* scala-logging (com.typesafe.scala-logging:scala-logging_2.13:3.9.2 - https://github.com/lightbend/scala-logging) * scala-logging (com.typesafe.scala-logging:scala-logging_2.13:3.9.2 - https://github.com/lightbend/scala-logging)
* JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk) * JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk)
* SparseBitSet (com.zaxxer:SparseBitSet:1.3 - https://github.com/brettwooldridge/SparseBitSet) * SparseBitSet (com.zaxxer:SparseBitSet:1.3 - https://github.com/brettwooldridge/SparseBitSet)
* Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.4 - https://commons.apache.org/proper/commons-beanutils/) * Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.10.1 - https://commons.apache.org/proper/commons-beanutils)
* Apache Commons CLI (commons-cli:commons-cli:1.6.0 - https://commons.apache.org/proper/commons-cli/) * Apache Commons CLI (commons-cli:commons-cli:1.9.0 - https://commons.apache.org/proper/commons-cli/)
* Apache Commons Codec (commons-codec:commons-codec:1.16.0 - https://commons.apache.org/proper/commons-codec/) * Apache Commons Codec (commons-codec:commons-codec:1.18.0 - https://commons.apache.org/proper/commons-codec/)
* Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/) * Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/)
* Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/) * Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/)
* Apache Commons IO (commons-io:commons-io:2.15.1 - https://commons.apache.org/proper/commons-io/) * Apache Commons IO (commons-io:commons-io:2.18.0 - https://commons.apache.org/proper/commons-io/)
* Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/) * Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/)
* Apache Commons Logging (commons-logging:commons-logging:1.3.0 - https://commons.apache.org/proper/commons-logging/) * Apache Commons Logging (commons-logging:commons-logging:1.3.5 - https://commons.apache.org/proper/commons-logging/)
* Apache Commons Validator (commons-validator:commons-validator:1.7 - http://commons.apache.org/proper/commons-validator/) * Apache Commons Validator (commons-validator:commons-validator:1.9.0 - http://commons.apache.org/proper/commons-validator/)
* GeoJson POJOs for Jackson (de.grundid.opendatalab:geojson-jackson:1.14 - https://github.com/opendatalab-de/geojson-jackson) * GeoJson POJOs for Jackson (de.grundid.opendatalab:geojson-jackson:1.14 - https://github.com/opendatalab-de/geojson-jackson)
* broker-client (eu.openaire:broker-client:1.1.2 - http://api.openaire.eu/broker/broker-client) * broker-client (eu.openaire:broker-client:1.1.2 - http://api.openaire.eu/broker/broker-client)
* OpenAIRE Funders Model (eu.openaire:funders-model:2.0.0 - https://api.openaire.eu) * OpenAIRE Funders Model (eu.openaire:funders-model:2.0.0 - https://api.openaire.eu)
* Metrics Core (io.dropwizard.metrics:metrics-core:4.1.5 - https://metrics.dropwizard.io/metrics-core) * Metrics Core (io.dropwizard.metrics:metrics-core:4.1.5 - https://metrics.dropwizard.io/metrics-core)
* Metrics Core (io.dropwizard.metrics:metrics-core:4.2.25 - https://metrics.dropwizard.io/metrics-core)
* Graphite Integration for Metrics (io.dropwizard.metrics:metrics-graphite:4.1.5 - https://metrics.dropwizard.io/metrics-graphite) * Graphite Integration for Metrics (io.dropwizard.metrics:metrics-graphite:4.1.5 - https://metrics.dropwizard.io/metrics-graphite)
* Metrics Integration for Jetty 9.3 and higher (io.dropwizard.metrics:metrics-jetty9:4.1.5 - https://metrics.dropwizard.io/metrics-jetty9) * Metrics Integration for Jetty 9.3 and higher (io.dropwizard.metrics:metrics-jetty9:4.1.5 - https://metrics.dropwizard.io/metrics-jetty9)
* Metrics Integration with JMX (io.dropwizard.metrics:metrics-jmx:4.1.5 - https://metrics.dropwizard.io/metrics-jmx) * Metrics Integration with JMX (io.dropwizard.metrics:metrics-jmx:4.1.5 - https://metrics.dropwizard.io/metrics-jmx)
* JVM Integration for Metrics (io.dropwizard.metrics:metrics-jvm:4.1.5 - https://metrics.dropwizard.io/metrics-jvm) * JVM Integration for Metrics (io.dropwizard.metrics:metrics-jvm:4.1.5 - https://metrics.dropwizard.io/metrics-jvm)
* SWORD v2 Common Server Library (forked) (io.gdcc:sword2-server:2.0.0 - https://github.com/gdcc/sword2-server) * SWORD v2 Common Server Library (forked) (io.gdcc:sword2-server:2.0.0 - https://github.com/gdcc/sword2-server)
* micrometer-commons (io.micrometer:micrometer-commons:1.12.6 - https://github.com/micrometer-metrics/micrometer) * micrometer-commons (io.micrometer:micrometer-commons:1.14.5 - https://github.com/micrometer-metrics/micrometer)
* micrometer-core (io.micrometer:micrometer-core:1.12.6 - https://github.com/micrometer-metrics/micrometer) * micrometer-core (io.micrometer:micrometer-core:1.14.4 - https://github.com/micrometer-metrics/micrometer)
* micrometer-jakarta9 (io.micrometer:micrometer-jakarta9:1.12.6 - https://github.com/micrometer-metrics/micrometer) * micrometer-jakarta9 (io.micrometer:micrometer-jakarta9:1.14.4 - https://github.com/micrometer-metrics/micrometer)
* micrometer-observation (io.micrometer:micrometer-observation:1.12.6 - https://github.com/micrometer-metrics/micrometer) * micrometer-observation (io.micrometer:micrometer-observation:1.14.5 - https://github.com/micrometer-metrics/micrometer)
* Netty/Buffer (io.netty:netty-buffer:4.1.106.Final - https://netty.io/netty-buffer/)
* Netty/Buffer (io.netty:netty-buffer:4.1.99.Final - https://netty.io/netty-buffer/) * Netty/Buffer (io.netty:netty-buffer:4.1.99.Final - https://netty.io/netty-buffer/)
* Netty/Codec (io.netty:netty-codec:4.1.106.Final - https://netty.io/netty-codec/)
* Netty/Codec (io.netty:netty-codec:4.1.99.Final - https://netty.io/netty-codec/) * Netty/Codec (io.netty:netty-codec:4.1.99.Final - https://netty.io/netty-codec/)
* Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.53.Final - https://netty.io/netty-codec-http/) * Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.86.Final - https://netty.io/netty-codec-http/)
* Netty/Codec/Socks (io.netty:netty-codec-socks:4.1.53.Final - https://netty.io/netty-codec-socks/) * Netty/Codec/HTTP2 (io.netty:netty-codec-http2:4.1.86.Final - https://netty.io/netty-codec-http2/)
* Netty/Common (io.netty:netty-common:4.1.106.Final - https://netty.io/netty-common/) * Netty/Codec/Socks (io.netty:netty-codec-socks:4.1.86.Final - https://netty.io/netty-codec-socks/)
* Netty/Common (io.netty:netty-common:4.1.99.Final - https://netty.io/netty-common/) * Netty/Common (io.netty:netty-common:4.1.99.Final - https://netty.io/netty-common/)
* Netty/Handler (io.netty:netty-handler:4.1.106.Final - https://netty.io/netty-handler/)
* Netty/Handler (io.netty:netty-handler:4.1.99.Final - https://netty.io/netty-handler/) * Netty/Handler (io.netty:netty-handler:4.1.99.Final - https://netty.io/netty-handler/)
* Netty/Handler/Proxy (io.netty:netty-handler-proxy:4.1.53.Final - https://netty.io/netty-handler-proxy/) * Netty/Handler/Proxy (io.netty:netty-handler-proxy:4.1.86.Final - https://netty.io/netty-handler-proxy/)
* Netty/Resolver (io.netty:netty-resolver:4.1.99.Final - https://netty.io/netty-resolver/) * Netty/Resolver (io.netty:netty-resolver:4.1.99.Final - https://netty.io/netty-resolver/)
* Netty/Transport (io.netty:netty-transport:4.1.106.Final - https://netty.io/netty-transport/) * Netty/TomcatNative [BoringSSL - Static] (io.netty:netty-tcnative-boringssl-static:2.0.56.Final - https://github.com/netty/netty-tcnative/netty-tcnative-boringssl-static/)
* Netty/TomcatNative [OpenSSL - Classes] (io.netty:netty-tcnative-classes:2.0.56.Final - https://github.com/netty/netty-tcnative/netty-tcnative-classes/)
* Netty/Transport (io.netty:netty-transport:4.1.99.Final - https://netty.io/netty-transport/) * Netty/Transport (io.netty:netty-transport:4.1.99.Final - https://netty.io/netty-transport/)
* Netty/Transport/Classes/Epoll (io.netty:netty-transport-classes-epoll:4.1.99.Final - https://netty.io/netty-transport-classes-epoll/)
* Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.99.Final - https://netty.io/netty-transport-native-epoll/) * Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.99.Final - https://netty.io/netty-transport-native-epoll/)
* Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.106.Final - https://netty.io/netty-transport-native-unix-common/)
* Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.99.Final - https://netty.io/netty-transport-native-unix-common/) * Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.99.Final - https://netty.io/netty-transport-native-unix-common/)
* OpenTracing API (io.opentracing:opentracing-api:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-api) * OpenTracing API (io.opentracing:opentracing-api:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-api)
* OpenTracing-noop (io.opentracing:opentracing-noop:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-noop) * OpenTracing-noop (io.opentracing:opentracing-noop:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-noop)
* OpenTracing-util (io.opentracing:opentracing-util:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-util) * OpenTracing-util (io.opentracing:opentracing-util:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-util)
* Prometheus Java Simpleclient (io.prometheus:simpleclient:0.16.0 - http://github.com/prometheus/client_java/simpleclient)
* Prometheus Java Simpleclient Common (io.prometheus:simpleclient_common:0.16.0 - http://github.com/prometheus/client_java/simpleclient_common)
* Prometheus Java Simpleclient Httpserver (io.prometheus:simpleclient_httpserver:0.16.0 - http://github.com/prometheus/client_java/simpleclient_httpserver)
* Prometheus Java Span Context Supplier - Common (io.prometheus:simpleclient_tracer_common:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_common)
* Prometheus Java Span Context Supplier - OpenTelemetry (io.prometheus:simpleclient_tracer_otel:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_otel)
* Prometheus Java Span Context Supplier - OpenTelemetry Agent (io.prometheus:simpleclient_tracer_otel_agent:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_otel_agent)
* Google S2 geometry library (io.sgr:s2-geometry-library-java:1.0.0 - https://github.com/sgr-io/s2-geometry-library-java) * Google S2 geometry library (io.sgr:s2-geometry-library-java:1.0.0 - https://github.com/sgr-io/s2-geometry-library-java)
* Jandex: Core (io.smallrye:jandex:3.1.2 - https://smallrye.io) * Jandex: Core (io.smallrye:jandex:3.1.2 - https://smallrye.io)
* swagger-annotations (io.swagger:swagger-annotations:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations) * swagger-annotations (io.swagger:swagger-annotations:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
* swagger-compat-spec-parser (io.swagger:swagger-compat-spec-parser:1.0.52 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-compat-spec-parser) * swagger-compat-spec-parser (io.swagger:swagger-compat-spec-parser:1.0.64 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-compat-spec-parser)
* swagger-core (io.swagger:swagger-core:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-core) * swagger-core (io.swagger:swagger-core:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
* swagger-models (io.swagger:swagger-models:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-models) * swagger-models (io.swagger:swagger-models:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
* swagger-parser (io.swagger:swagger-parser:1.0.52 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser) * swagger-parser (io.swagger:swagger-parser:1.0.64 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
* swagger-annotations (io.swagger.core.v3:swagger-annotations:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations) * swagger-annotations (io.swagger.core.v3:swagger-annotations:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
* swagger-annotations-jakarta (io.swagger.core.v3:swagger-annotations-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations-jakarta) * swagger-annotations-jakarta (io.swagger.core.v3:swagger-annotations-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations-jakarta)
* swagger-core (io.swagger.core.v3:swagger-core:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-core) * swagger-core (io.swagger.core.v3:swagger-core:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
* swagger-core-jakarta (io.swagger.core.v3:swagger-core-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-core-jakarta) * swagger-core-jakarta (io.swagger.core.v3:swagger-core-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-core-jakarta)
* swagger-integration-jakarta (io.swagger.core.v3:swagger-integration-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-integration-jakarta) * swagger-integration-jakarta (io.swagger.core.v3:swagger-integration-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-integration-jakarta)
* swagger-jaxrs2-jakarta (io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-jaxrs2-jakarta) * swagger-jaxrs2-jakarta (io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-jaxrs2-jakarta)
* swagger-models (io.swagger.core.v3:swagger-models:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-models) * swagger-models (io.swagger.core.v3:swagger-models:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
* swagger-models-jakarta (io.swagger.core.v3:swagger-models-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-models-jakarta) * swagger-models-jakarta (io.swagger.core.v3:swagger-models-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-models-jakarta)
* swagger-parser (io.swagger.parser.v3:swagger-parser:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser) * swagger-parser (io.swagger.parser.v3:swagger-parser:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
* swagger-parser (io.swagger.parser.v3:swagger-parser-core:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-core) * swagger-parser (io.swagger.parser.v3:swagger-parser-core:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-core)
* swagger-parser-v2-converter (io.swagger.parser.v3:swagger-parser-v2-converter:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v2-converter) * swagger-parser-v2-converter (io.swagger.parser.v3:swagger-parser-v2-converter:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v2-converter)
* swagger-parser-v3 (io.swagger.parser.v3:swagger-parser-v3:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v3) * swagger-parser-v3 (io.swagger.parser.v3:swagger-parser-v3:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v3)
* Jakarta Dependency Injection (jakarta.inject:jakarta.inject-api:2.0.1 - https://github.com/eclipse-ee4j/injection-api) * Jakarta Dependency Injection (jakarta.inject:jakarta.inject-api:2.0.1 - https://github.com/eclipse-ee4j/injection-api)
* Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:3.0.2 - https://beanvalidation.org) * Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:3.0.2 - https://beanvalidation.org)
* JSR107 API and SPI (javax.cache:cache-api:1.1.1 - https://github.com/jsr107/jsr107spec) * JSR107 API and SPI (javax.cache:cache-api:1.1.1 - https://github.com/jsr107/jsr107spec)
* javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
* Bean Validation API (javax.validation:validation-api:1.1.0.Final - http://beanvalidation.org)
* jdbm (jdbm:jdbm:1.0 - no url defined) * jdbm (jdbm:jdbm:1.0 - no url defined)
* Joda-Time (joda-time:joda-time:2.12.5 - https://www.joda.org/joda-time/) * Joda-Time (joda-time:joda-time:2.12.7 - https://www.joda.org/joda-time/)
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy) * Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy)
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.14.11 - https://bytebuddy.net/byte-buddy)
* Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.11.13 - https://bytebuddy.net/byte-buddy-agent) * Byte Buddy agent (net.bytebuddy:byte-buddy-agent:1.11.13 - https://bytebuddy.net/byte-buddy-agent)
* eigenbase-properties (net.hydromatic:eigenbase-properties:1.1.5 - http://github.com/julianhyde/eigenbase-properties) * eigenbase-properties (net.hydromatic:eigenbase-properties:1.1.5 - http://github.com/julianhyde/eigenbase-properties)
* json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.19.0 - https://github.com/lukas-krecan/JsonUnit/json-unit-core) * json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.36.0 - https://github.com/lukas-krecan/JsonUnit/json-unit-core)
* "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/) * "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/)
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.0 - https://urielch.github.io/) * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.0 - https://urielch.github.io/)
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.2 - https://urielch.github.io/)
* JSON Small and Fast Parser (net.minidev:json-smart:2.5.0 - https://urielch.github.io/) * JSON Small and Fast Parser (net.minidev:json-smart:2.5.0 - https://urielch.github.io/)
* JSON Small and Fast Parser (net.minidev:json-smart:2.5.2 - https://urielch.github.io/)
* java-support (net.shibboleth.utilities:java-support:8.4.2 - http://shibboleth.net/java-support/)
* OGNL - Object Graph Navigation Library (ognl:ognl:3.3.4 - https://github.com/jkuhnert/ognl/)
* Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core) * Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core)
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org) * I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org)
* Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser) * Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser)
* Apache Ant Core (org.apache.ant:ant:1.10.14 - https://ant.apache.org/) * Apache Ant Core (org.apache.ant:ant:1.10.15 - https://ant.apache.org/)
* Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.14 - https://ant.apache.org/) * Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.15 - https://ant.apache.org/)
* Apache Commons BCEL (org.apache.bcel:bcel:6.7.0 - https://commons.apache.org/proper/commons-bcel) * Apache Commons BCEL (org.apache.bcel:bcel:6.10.0 - https://commons.apache.org/proper/commons-bcel)
* Calcite Core (org.apache.calcite:calcite-core:1.35.0 - https://calcite.apache.org) * Calcite Core (org.apache.calcite:calcite-core:1.35.0 - https://calcite.apache.org)
* Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.35.0 - https://calcite.apache.org) * Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.35.0 - https://calcite.apache.org)
* Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.23.0 - https://calcite.apache.org/avatica) * Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.23.0 - https://calcite.apache.org/avatica)
* Apache Calcite Avatica Metrics (org.apache.calcite.avatica:avatica-metrics:1.23.0 - https://calcite.apache.org/avatica) * Apache Calcite Avatica Metrics (org.apache.calcite.avatica:avatica-metrics:1.23.0 - https://calcite.apache.org/avatica)
* Apache Commons Collections (org.apache.commons:commons-collections4:4.4 - https://commons.apache.org/proper/commons-collections/) * Apache Commons Collections (org.apache.commons:commons-collections4:4.4 - https://commons.apache.org/proper/commons-collections/)
* Apache Commons Compress (org.apache.commons:commons-compress:1.26.0 - https://commons.apache.org/proper/commons-compress/) * Apache Commons Compress (org.apache.commons:commons-compress:1.27.1 - https://commons.apache.org/proper/commons-compress/)
* Apache Commons Configuration (org.apache.commons:commons-configuration2:2.10.1 - https://commons.apache.org/proper/commons-configuration/) * Apache Commons Configuration (org.apache.commons:commons-configuration2:2.11.0 - https://commons.apache.org/proper/commons-configuration/)
* Apache Commons CSV (org.apache.commons:commons-csv:1.10.0 - https://commons.apache.org/proper/commons-csv/) * Apache Commons CSV (org.apache.commons:commons-csv:1.13.0 - https://commons.apache.org/proper/commons-csv/)
* Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.11.0 - https://commons.apache.org/dbcp/) * Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.13.0 - https://commons.apache.org/proper/commons-dbcp/)
* Apache Commons Digester (org.apache.commons:commons-digester3:3.2 - http://commons.apache.org/digester/)
* Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/) * Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/)
* Apache Commons Exec (org.apache.commons:commons-exec:1.4.0 - https://commons.apache.org/proper/commons-exec/) * Apache Commons Exec (org.apache.commons:commons-exec:1.4.0 - https://commons.apache.org/proper/commons-exec/)
* Apache Commons Lang (org.apache.commons:commons-lang3:3.14.0 - https://commons.apache.org/proper/commons-lang/) * Apache Commons Lang (org.apache.commons:commons-lang3:3.17.0 - https://commons.apache.org/proper/commons-lang/)
* Apache Commons Math (org.apache.commons:commons-math3:3.6.1 - http://commons.apache.org/proper/commons-math/) * Apache Commons Math (org.apache.commons:commons-math3:3.6.1 - http://commons.apache.org/proper/commons-math/)
* Apache Commons Pool (org.apache.commons:commons-pool2:2.12.0 - https://commons.apache.org/proper/commons-pool/) * Apache Commons Pool (org.apache.commons:commons-pool2:2.12.1 - https://commons.apache.org/proper/commons-pool/)
* Apache Commons Text (org.apache.commons:commons-text:1.10.0 - https://commons.apache.org/proper/commons-text) * Apache Commons Text (org.apache.commons:commons-text:1.13.0 - https://commons.apache.org/proper/commons-text)
* Curator Client (org.apache.curator:curator-client:2.13.0 - http://curator.apache.org/curator-client) * Curator Client (org.apache.curator:curator-client:2.13.0 - http://curator.apache.org/curator-client)
* Curator Framework (org.apache.curator:curator-framework:2.13.0 - http://curator.apache.org/curator-framework) * Curator Framework (org.apache.curator:curator-framework:2.13.0 - http://curator.apache.org/curator-framework)
* Curator Recipes (org.apache.curator:curator-recipes:2.13.0 - http://curator.apache.org/curator-recipes) * Curator Recipes (org.apache.curator:curator-recipes:2.13.0 - http://curator.apache.org/curator-recipes)
@@ -207,120 +216,130 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.16 - http://hc.apache.org/httpcomponents-core-ga) * Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.16 - http://hc.apache.org/httpcomponents-core-ga)
* Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.14 - http://hc.apache.org/httpcomponents-client-ga) * Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.14 - http://hc.apache.org/httpcomponents-client-ga)
* Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.1.3 - https://hc.apache.org/httpcomponents-client-5.0.x/5.1.3/httpclient5/) * Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.1.3 - https://hc.apache.org/httpcomponents-client-5.0.x/5.1.3/httpclient5/)
* Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.3.1 - https://hc.apache.org/httpcomponents-client-5.0.x/5.3.1/httpclient5/) * Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.4.2 - https://hc.apache.org/httpcomponents-client-5.4.x/5.4.2/httpclient5/)
* Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5/) * Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5/)
* Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.2.4 - https://hc.apache.org/httpcomponents-core-5.2.x/5.2.4/httpcore5/) * Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.3.3 - https://hc.apache.org/httpcomponents-core-5.3.x/5.3.3/httpcore5/)
* Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5-h2/) * Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5-h2/)
* Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.2.4 - https://hc.apache.org/httpcomponents-core-5.2.x/5.2.4/httpcore5-h2/) * Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.3.3 - https://hc.apache.org/httpcomponents-core-5.3.x/5.3.3/httpcore5-h2/)
* Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.10 - http://james.apache.org/mime4j/apache-mime4j-core) * Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.12 - http://james.apache.org/mime4j/apache-mime4j-core)
* Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.11 - http://james.apache.org/mime4j/apache-mime4j-dom) * Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.12 - http://james.apache.org/mime4j/apache-mime4j-dom)
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:4.9.0 - https://jena.apache.org/apache-jena-libs/) * jclouds blobstore core (org.apache.jclouds:jclouds-blobstore:2.6.0 - https://jclouds.apache.org/jclouds-blobstore/)
* Apache Jena - ARQ (org.apache.jena:jena-arq:4.9.0 - https://jena.apache.org/jena-arq/) * jclouds Components Core (org.apache.jclouds:jclouds-core:2.6.0 - https://jclouds.apache.org/jclouds-core/)
* Apache Jena - Base (org.apache.jena:jena-base:4.9.0 - https://jena.apache.org/jena-base/) * jclouds filesystem core (org.apache.jclouds.api:filesystem:2.6.0 - https://jclouds.apache.org/filesystem/)
* Apache Jena - Core (org.apache.jena:jena-core:4.9.0 - https://jena.apache.org/jena-core/) * jclouds s3 api (org.apache.jclouds.api:s3:2.6.0 - https://jclouds.apache.org/s3/)
* Apache Jena - DBOE Base (org.apache.jena:jena-dboe-base:4.9.0 - https://jena.apache.org/jena-dboe-base/) * jclouds sts api (org.apache.jclouds.api:sts:2.6.0 - https://jclouds.apache.org/sts/)
* Apache Jena - DBOE Indexes (org.apache.jena:jena-dboe-index:4.9.0 - https://jena.apache.org/jena-dboe-index/) * jclouds Amazon Simple Storage Service (S3) provider (org.apache.jclouds.provider:aws-s3:2.6.0 - https://jclouds.apache.org/aws-s3/)
* Apache Jena - DBOE Storage (org.apache.jena:jena-dboe-storage:4.9.0 - https://jena.apache.org/jena-dboe-storage/) * Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:4.10.0 - https://jena.apache.org/apache-jena-libs/)
* Apache Jena - DBOE Transactional Datastructures (org.apache.jena:jena-dboe-trans-data:4.9.0 - https://jena.apache.org/jena-dboe-trans-data/) * Apache Jena - ARQ (org.apache.jena:jena-arq:4.10.0 - https://jena.apache.org/jena-arq/)
* Apache Jena - DBOE Transactions (org.apache.jena:jena-dboe-transaction:4.9.0 - https://jena.apache.org/jena-dboe-transaction/) * Apache Jena - Base (org.apache.jena:jena-base:4.10.0 - https://jena.apache.org/jena-base/)
* Apache Jena - IRI (org.apache.jena:jena-iri:4.9.0 - https://jena.apache.org/jena-iri/) * Apache Jena - Core (org.apache.jena:jena-core:4.10.0 - https://jena.apache.org/jena-core/)
* Apache Jena - RDF Connection (org.apache.jena:jena-rdfconnection:4.9.0 - https://jena.apache.org/jena-rdfconnection/) * Apache Jena - DBOE Base (org.apache.jena:jena-dboe-base:4.10.0 - https://jena.apache.org/jena-dboe-base/)
* Apache Jena - RDF Patch (org.apache.jena:jena-rdfpatch:4.9.0 - https://jena.apache.org/jena-rdfpatch/) * Apache Jena - DBOE Indexes (org.apache.jena:jena-dboe-index:4.10.0 - https://jena.apache.org/jena-dboe-index/)
* Apache Jena - SHACL (org.apache.jena:jena-shacl:4.9.0 - https://jena.apache.org/jena-shacl/) * Apache Jena - DBOE Storage (org.apache.jena:jena-dboe-storage:4.10.0 - https://jena.apache.org/jena-dboe-storage/)
* Apache Jena - ShEx (org.apache.jena:jena-shex:4.9.0 - https://jena.apache.org/jena-shex/) * Apache Jena - DBOE Transactional Datastructures (org.apache.jena:jena-dboe-trans-data:4.10.0 - https://jena.apache.org/jena-dboe-trans-data/)
* Apache Jena - TDB1 (Native Triple Store) (org.apache.jena:jena-tdb:4.9.0 - https://jena.apache.org/jena-tdb/) * Apache Jena - DBOE Transactions (org.apache.jena:jena-dboe-transaction:4.10.0 - https://jena.apache.org/jena-dboe-transaction/)
* Apache Jena - TDB2 (Native Triple Store) (org.apache.jena:jena-tdb2:4.9.0 - https://jena.apache.org/jena-tdb2/) * Apache Jena - IRI (org.apache.jena:jena-iri:4.10.0 - https://jena.apache.org/jena-iri/)
* Apache Jena - RDF Connection (org.apache.jena:jena-rdfconnection:4.10.0 - https://jena.apache.org/jena-rdfconnection/)
* Apache Jena - RDF Patch (org.apache.jena:jena-rdfpatch:4.10.0 - https://jena.apache.org/jena-rdfpatch/)
* Apache Jena - SHACL (org.apache.jena:jena-shacl:4.10.0 - https://jena.apache.org/jena-shacl/)
* Apache Jena - ShEx (org.apache.jena:jena-shex:4.10.0 - https://jena.apache.org/jena-shex/)
* Apache Jena - TDB1 (Native Triple Store) (org.apache.jena:jena-tdb:4.10.0 - https://jena.apache.org/jena-tdb/)
* Apache Jena - TDB2 (Native Triple Store) (org.apache.jena:jena-tdb2:4.10.0 - https://jena.apache.org/jena-tdb2/)
* Kerby-kerb core (org.apache.kerby:kerb-core:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-core) * Kerby-kerb core (org.apache.kerby:kerb-core:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-core)
* Kerby-kerb Util (org.apache.kerby:kerb-util:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-util) * Kerby-kerb Util (org.apache.kerby:kerb-util:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-util)
* Kerby ASN1 Project (org.apache.kerby:kerby-asn1:1.0.1 - http://directory.apache.org/kerby/kerby-common/kerby-asn1) * Kerby ASN1 Project (org.apache.kerby:kerby-asn1:1.0.1 - http://directory.apache.org/kerby/kerby-common/kerby-asn1)
* Kerby PKIX Project (org.apache.kerby:kerby-pkix:1.0.1 - http://directory.apache.org/kerby/kerby-pkix) * Kerby PKIX Project (org.apache.kerby:kerby-pkix:1.0.1 - http://directory.apache.org/kerby/kerby-pkix)
* Apache Log4j 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-1.2-api/) * Apache Log4j 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-1.2-api/)
* Apache Log4j API (org.apache.logging.log4j:log4j-api:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-api/) * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-api/)
* Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-core/) * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-core/)
* Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-jul/) * Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-jul/)
* Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/) * Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/)
* Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j-impl/) * Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/)
* Apache Log4j SLF4J 2.0 Binding (org.apache.logging.log4j:log4j-slf4j2-impl:2.21.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j2-impl/) * SLF4J 2 Provider for Log4j API (org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j2-impl/)
* Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-web/) * Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-web/)
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common) * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common)
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu) * Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji) * Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
* Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori) * Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori)
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic) * Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn) * Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel) * Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
* Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs) * Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs)
* Lucene Classification (org.apache.lucene:lucene-classification:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-classification) * Lucene Classification (org.apache.lucene:lucene-classification:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-classification)
* Lucene codecs (org.apache.lucene:lucene-codecs:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-codecs) * Lucene codecs (org.apache.lucene:lucene-codecs:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-codecs)
* Lucene Core (org.apache.lucene:lucene-core:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-core) * Lucene Core (org.apache.lucene:lucene-core:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-core)
* Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-expressions) * Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-expressions)
* Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-grouping) * Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-grouping)
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-highlighter) * Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-highlighter)
* Lucene Join (org.apache.lucene:lucene-join:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-join) * Lucene Join (org.apache.lucene:lucene-join:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-join)
* Lucene Memory (org.apache.lucene:lucene-memory:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-memory) * Lucene Memory (org.apache.lucene:lucene-memory:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-memory)
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-misc) * Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-misc)
* Lucene Queries (org.apache.lucene:lucene-queries:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-queries) * Lucene Queries (org.apache.lucene:lucene-queries:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-queries)
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-queryparser) * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-queryparser)
* Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-sandbox) * Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-sandbox)
* Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras) * Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras)
* Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-spatial3d) * Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-spatial3d)
* Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-suggest) * Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-suggest)
* Apache FontBox (org.apache.pdfbox:fontbox:2.0.31 - http://pdfbox.apache.org/) * Apache FontBox (org.apache.pdfbox:fontbox:2.0.33 - http://pdfbox.apache.org/)
* PDFBox JBIG2 ImageIO plugin (org.apache.pdfbox:jbig2-imageio:3.0.4 - https://www.apache.org/jbig2-imageio/) * PDFBox JBIG2 ImageIO plugin (org.apache.pdfbox:jbig2-imageio:3.0.4 - https://www.apache.org/jbig2-imageio/)
* Apache JempBox (org.apache.pdfbox:jempbox:1.8.17 - http://www.apache.org/pdfbox-parent/jempbox/) * Apache JempBox (org.apache.pdfbox:jempbox:1.8.17 - http://www.apache.org/pdfbox-parent/jempbox/)
* Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.31 - https://www.apache.org/pdfbox-parent/pdfbox/) * Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.33 - https://www.apache.org/pdfbox-parent/pdfbox/)
* Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.31 - https://www.apache.org/pdfbox-parent/pdfbox-tools/) * Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.33 - https://www.apache.org/pdfbox-parent/pdfbox-tools/)
* Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.31 - https://www.apache.org/pdfbox-parent/xmpbox/) * Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.33 - https://www.apache.org/pdfbox-parent/xmpbox/)
* Apache POI - Common (org.apache.poi:poi:5.2.5 - https://poi.apache.org/) * Apache POI - Common (org.apache.poi:poi:5.4.0 - https://poi.apache.org/)
* Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.2.5 - https://poi.apache.org/) * Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.4.0 - https://poi.apache.org/)
* Apache POI (org.apache.poi:poi-ooxml-lite:5.2.5 - https://poi.apache.org/) * Apache POI (org.apache.poi:poi-ooxml-lite:5.4.0 - https://poi.apache.org/)
* Apache POI (org.apache.poi:poi-scratchpad:5.2.5 - https://poi.apache.org/) * Apache POI (org.apache.poi:poi-scratchpad:5.4.0 - https://poi.apache.org/)
* Apache Solr Core (org.apache.solr:solr-core:8.11.3 - https://lucene.apache.org/solr-parent/solr-core) * Apache XML Security for Java (org.apache.santuario:xmlsec:2.3.4 - https://santuario.apache.org/)
* Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.3 - https://lucene.apache.org/solr-parent/solr-solrj) * Apache Solr Core (org.apache.solr:solr-core:8.11.4 - https://lucene.apache.org/solr-parent/solr-core)
* Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.4 - https://lucene.apache.org/solr-parent/solr-solrj)
* Apache Standard Taglib Implementation (org.apache.taglibs:taglibs-standard-impl:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-impl) * Apache Standard Taglib Implementation (org.apache.taglibs:taglibs-standard-impl:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-impl)
* Apache Standard Taglib Specification API (org.apache.taglibs:taglibs-standard-spec:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-spec) * Apache Standard Taglib Specification API (org.apache.taglibs:taglibs-standard-spec:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-spec)
* Apache Thrift (org.apache.thrift:libthrift:0.18.1 - http://thrift.apache.org) * Apache Thrift (org.apache.thrift:libthrift:0.19.0 - http://thrift.apache.org)
* Apache Tika core (org.apache.tika:tika-core:2.9.2 - https://tika.apache.org/) * Apache Tika core (org.apache.tika:tika-core:2.9.3 - https://tika.apache.org/)
* Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.9.2 - https://tika.apache.org/tika-parser-apple-module/) * Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.9.3 - https://tika.apache.org/tika-parser-apple-module/)
* Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.9.2 - https://tika.apache.org/tika-parser-audiovideo-module/) * Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.9.3 - https://tika.apache.org/tika-parser-audiovideo-module/)
* Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.9.2 - https://tika.apache.org/tika-parser-cad-module/) * Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.9.3 - https://tika.apache.org/tika-parser-cad-module/)
* Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.9.2 - https://tika.apache.org/tika-parser-code-module/) * Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.9.3 - https://tika.apache.org/tika-parser-code-module/)
* Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.9.2 - https://tika.apache.org/tika-parser-crypto-module/) * Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.9.3 - https://tika.apache.org/tika-parser-crypto-module/)
* Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.9.2 - https://tika.apache.org/tika-parser-digest-commons/) * Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.9.3 - https://tika.apache.org/tika-parser-digest-commons/)
* Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.9.2 - https://tika.apache.org/tika-parser-font-module/) * Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.9.3 - https://tika.apache.org/tika-parser-font-module/)
* Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.9.2 - https://tika.apache.org/tika-parser-html-module/) * Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.9.3 - https://tika.apache.org/tika-parser-html-module/)
* Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.9.2 - https://tika.apache.org/tika-parser-image-module/) * Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.9.3 - https://tika.apache.org/tika-parser-image-module/)
* Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.9.2 - https://tika.apache.org/tika-parser-mail-commons/) * Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.9.3 - https://tika.apache.org/tika-parser-mail-commons/)
* Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.9.2 - https://tika.apache.org/tika-parser-mail-module/) * Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.9.3 - https://tika.apache.org/tika-parser-mail-module/)
* Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.9.2 - https://tika.apache.org/tika-parser-microsoft-module/) * Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.9.3 - https://tika.apache.org/tika-parser-microsoft-module/)
* Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.9.2 - https://tika.apache.org/tika-parser-miscoffice-module/) * Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.9.3 - https://tika.apache.org/tika-parser-miscoffice-module/)
* Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.9.2 - https://tika.apache.org/tika-parser-news-module/) * Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.9.3 - https://tika.apache.org/tika-parser-news-module/)
* Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.9.2 - https://tika.apache.org/tika-parser-ocr-module/) * Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.9.3 - https://tika.apache.org/tika-parser-ocr-module/)
* Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.9.2 - https://tika.apache.org/tika-parser-pdf-module/) * Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.9.3 - https://tika.apache.org/tika-parser-pdf-module/)
* Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.9.2 - https://tika.apache.org/tika-parser-pkg-module/) * Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.9.3 - https://tika.apache.org/tika-parser-pkg-module/)
* Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.9.2 - https://tika.apache.org/tika-parser-text-module/) * Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.9.3 - https://tika.apache.org/tika-parser-text-module/)
* Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.9.2 - https://tika.apache.org/tika-parser-webarchive-module/) * Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.9.3 - https://tika.apache.org/tika-parser-webarchive-module/)
* Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.9.2 - https://tika.apache.org/tika-parser-xml-module/) * Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.9.3 - https://tika.apache.org/tika-parser-xml-module/)
* Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.9.2 - https://tika.apache.org/tika-parser-xmp-commons/) * Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.9.3 - https://tika.apache.org/tika-parser-xmp-commons/)
* Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.9.2 - https://tika.apache.org/tika-parser-zip-commons/) * Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.9.3 - https://tika.apache.org/tika-parser-zip-commons/)
* Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.9.2 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/) * Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.9.3 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/)
* tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:10.1.24 - https://tomcat.apache.org/) * tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:10.1.36 - https://tomcat.apache.org/)
* tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:10.1.24 - https://tomcat.apache.org/) * tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:10.1.36 - https://tomcat.apache.org/)
* tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:10.1.24 - https://tomcat.apache.org/) * tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:10.1.36 - https://tomcat.apache.org/)
* Apache Velocity - Engine (org.apache.velocity:velocity-engine-core:2.3 - http://velocity.apache.org/engine/devel/velocity-engine-core/) * Apache Velocity - Engine (org.apache.velocity:velocity-engine-core:2.4.1 - http://velocity.apache.org/engine/devel/velocity-engine-core/)
* Apache Velocity - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.2 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/) * Apache Velocity - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.3 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/)
* Apache Velocity Tools - Generic tools (org.apache.velocity.tools:velocity-tools-generic:3.1 - https://velocity.apache.org/tools/devel/velocity-tools-generic/)
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/) * Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/)
* Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/) * Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/)
* XmlBeans (org.apache.xmlbeans:xmlbeans:5.2.0 - https://xmlbeans.apache.org/) * XmlBeans (org.apache.xmlbeans:xmlbeans:5.3.0 - https://xmlbeans.apache.org/)
* Apache ZooKeeper - Server (org.apache.zookeeper:zookeeper:3.6.2 - http://zookeeper.apache.org/zookeeper) * Apache ZooKeeper - Server (org.apache.zookeeper:zookeeper:3.6.2 - http://zookeeper.apache.org/zookeeper)
* Apache ZooKeeper - Jute (org.apache.zookeeper:zookeeper-jute:3.6.2 - http://zookeeper.apache.org/zookeeper-jute) * Apache ZooKeeper - Jute (org.apache.zookeeper:zookeeper-jute:3.6.2 - http://zookeeper.apache.org/zookeeper-jute)
* org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.2 - https://github.com/apiguardian-team/apiguardian) * org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.2 - https://github.com/apiguardian-team/apiguardian)
* AssertJ Core (org.assertj:assertj-core:3.24.2 - https://assertj.github.io/doc/#assertj-core) * AssertJ Core (org.assertj:assertj-core:3.26.3 - https://assertj.github.io/doc/#assertj-core)
* Evo Inflector (org.atteo:evo-inflector:1.3 - http://atteo.org/static/evo-inflector) * Evo Inflector (org.atteo:evo-inflector:1.3 - http://atteo.org/static/evo-inflector)
* Awaitility (org.awaitility:awaitility:4.2.1 - http://awaitility.org) * attoparser (org.attoparser:attoparser:2.0.7.RELEASE - https://www.attoparser.org)
* Awaitility (org.awaitility:awaitility:4.2.2 - http://awaitility.org)
* jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/) * jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/)
* TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/) * TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/)
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.6 - http://woodstox.codehaus.org) * Woodstox (org.codehaus.woodstox:wstx-asl:3.2.6 - http://woodstox.codehaus.org)
* Cryptacular Library (org.cryptacular:cryptacular:1.2.5 - http://www.cryptacular.org)
* jems (org.dmfs:jems:1.18 - https://github.com/dmfs/jems) * jems (org.dmfs:jems:1.18 - https://github.com/dmfs/jems)
* rfc3986-uri (org.dmfs:rfc3986-uri:0.8.1 - https://github.com/dmfs/uri-toolkit) * rfc3986-uri (org.dmfs:rfc3986-uri:0.8.1 - https://github.com/dmfs/uri-toolkit)
* Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty)
@@ -335,124 +354,130 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client) * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation) * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
* Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy) * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.57.v20241219 - https://jetty.org/jetty-deploy/)
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http) * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.57.v20241219 - https://jetty.org/jetty-http/)
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io) * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.57.v20241219 - https://jetty.org/jetty-io/)
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx) * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx)
* Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite) * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security) * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-security) * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.57.v20241219 - https://jetty.org/jetty-security/)
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server) * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.57.v20241219 - https://jetty.org/jetty-server/)
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet) * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.57.v20241219 - https://jetty.org/jetty-servlet/)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets) * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets)
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util) * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.57.v20241219 - https://jetty.org/jetty-util/)
* Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax) * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.57.v20241219 - https://jetty.org/jetty-util-ajax/)
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp) * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.57.v20241219 - https://jetty.org/jetty-webapp/)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml) * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml) * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.57.v20241219 - https://jetty.org/jetty-xml/)
* Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api) * Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api)
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client) * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client)
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common) * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.57.v20241219 - https://jetty.org/http2-parent/http2-common/)
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack) * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack)
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas) * Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
* Ehcache (org.ehcache:ehcache:3.10.8 - http://ehcache.org) * Ehcache (org.ehcache:ehcache:3.10.8 - http://ehcache.org)
* flyway-core (org.flywaydb:flyway-core:10.10.0 - https://flywaydb.org/flyway-core) * flyway-core (org.flywaydb:flyway-core:10.22.0 - https://flywaydb.org/flyway-core)
* flyway-database-postgresql (org.flywaydb:flyway-database-postgresql:10.10.0 - https://flywaydb.org/flyway-database-postgresql) * flyway-database-postgresql (org.flywaydb:flyway-database-postgresql:10.22.0 - https://flywaydb.org/flyway-database-postgresql)
* Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.8 - https://github.com/Gagravarr/VorbisJava) * Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.8 - https://github.com/Gagravarr/VorbisJava)
* Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.8 - https://github.com/Gagravarr/VorbisJava) * Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.8 - https://github.com/Gagravarr/VorbisJava)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:8.0.1.Final - http://hibernate.org/validator/hibernate-validator) * Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:8.0.1.Final - http://hibernate.org/validator/hibernate-validator)
* Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:8.0.1.Final - http://hibernate.org/validator/hibernate-validator-cdi) * Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:8.0.1.Final - http://hibernate.org/validator/hibernate-validator-cdi)
* org.immutables.value-annotations (org.immutables:value-annotations:2.9.2 - http://immutables.org/value-annotations) * org.immutables.value-annotations (org.immutables:value-annotations:2.9.2 - http://immutables.org/value-annotations)
* leveldb (org.iq80.leveldb:leveldb:0.12 - http://github.com/dain/leveldb/leveldb) * leveldb (org.iq80.leveldb:leveldb:0.12 - http://github.com/dain/leveldb/leveldb)
* leveldb-api (org.iq80.leveldb:leveldb-api:0.12 - http://github.com/dain/leveldb/leveldb-api) * leveldb-api (org.iq80.leveldb:leveldb-api:0.12 - http://github.com/dain/leveldb/leveldb-api)
* Javassist (org.javassist:javassist:3.29.2-GA - http://www.javassist.org/) * Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.3.Final - http://www.jboss.org) * JBoss Logging 3 (org.jboss.logging:jboss-logging:3.6.1.Final - http://www.jboss.org)
* JDOM (org.jdom:jdom2:2.0.6.1 - http://www.jdom.org) * JDOM (org.jdom:jdom2:2.0.6.1 - http://www.jdom.org)
* jtwig-core (org.jtwig:jtwig-core:5.87.0.RELEASE - http://jtwig.org)
* jtwig-reflection (org.jtwig:jtwig-reflection:5.87.0.RELEASE - http://jtwig.org)
* jtwig-spring (org.jtwig:jtwig-spring:5.87.0.RELEASE - http://jtwig.org)
* jtwig-spring-boot-starter (org.jtwig:jtwig-spring-boot-starter:5.87.0.RELEASE - http://jtwig.org)
* jtwig-web (org.jtwig:jtwig-web:5.87.0.RELEASE - http://jtwig.org)
* Proj4J (org.locationtech.proj4j:proj4j:1.1.5 - https://github.com/locationtech/proj4j) * Proj4J (org.locationtech.proj4j:proj4j:1.1.5 - https://github.com/locationtech/proj4j)
* Spatial4J (org.locationtech.spatial4j:spatial4j:0.7 - https://projects.eclipse.org/projects/locationtech.spatial4j) * Spatial4J (org.locationtech.spatial4j:spatial4j:0.7 - https://projects.eclipse.org/projects/locationtech.spatial4j)
* MockServer Java Client (org.mock-server:mockserver-client-java:5.11.2 - http://www.mock-server.com) * MockServer Java Client (org.mock-server:mockserver-client-java:5.15.0 - https://www.mock-server.com)
* MockServer Core (org.mock-server:mockserver-core:5.11.2 - http://www.mock-server.com) * MockServer Core (org.mock-server:mockserver-core:5.15.0 - https://www.mock-server.com)
* MockServer JUnit 4 Integration (org.mock-server:mockserver-junit-rule:5.11.2 - http://www.mock-server.com) * MockServer JUnit 4 Integration (org.mock-server:mockserver-junit-rule:5.15.0 - https://www.mock-server.com)
* MockServer & Proxy Netty (org.mock-server:mockserver-netty:5.11.2 - http://www.mock-server.com) * MockServer & Proxy Netty (org.mock-server:mockserver-netty:5.15.0 - https://www.mock-server.com)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty) * jwarc (org.netpreserve:jwarc:0.31.1 - https://github.com/iipc/jwarc)
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester)
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
* Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api)
* jwarc (org.netpreserve:jwarc:0.29.0 - https://github.com/iipc/jwarc)
* Objenesis (org.objenesis:objenesis:3.2 - http://objenesis.org/objenesis) * Objenesis (org.objenesis:objenesis:3.2 - http://objenesis.org/objenesis)
* parboiled-core (org.parboiled:parboiled-core:1.3.1 - http://parboiled.org) * OpenSAML :: Core (org.opensaml:opensaml-core:4.3.2 - http://shibboleth.net/opensaml-core/)
* parboiled-java (org.parboiled:parboiled-java:1.3.1 - http://parboiled.org) * OpenSAML :: Messaging API (org.opensaml:opensaml-messaging-api:4.3.2 - http://shibboleth.net/opensaml-messaging-api/)
* org.roaringbitmap:RoaringBitmap (org.roaringbitmap:RoaringBitmap:0.9.45 - https://github.com/RoaringBitmap/RoaringBitmap) * OpenSAML :: Profile API (org.opensaml:opensaml-profile-api:4.3.2 - http://shibboleth.net/opensaml-profile-api/)
* org.roaringbitmap:shims (org.roaringbitmap:shims:0.9.45 - https://github.com/RoaringBitmap/RoaringBitmap) * OpenSAML :: SAML Provider API (org.opensaml:opensaml-saml-api:4.3.2 - http://shibboleth.net/opensaml-saml-api/)
* OpenSAML :: SAML Provider Implementations (org.opensaml:opensaml-saml-impl:4.3.2 - http://shibboleth.net/opensaml-saml-impl/)
* OpenSAML :: Security API (org.opensaml:opensaml-security-api:4.3.2 - http://shibboleth.net/opensaml-security-api/)
* OpenSAML :: Security Implementation (org.opensaml:opensaml-security-impl:4.3.2 - http://shibboleth.net/opensaml-security-impl/)
* OpenSAML :: SOAP Provider API (org.opensaml:opensaml-soap-api:4.3.2 - http://shibboleth.net/opensaml-soap-api/)
* OpenSAML :: SOAP Provider Implementations (org.opensaml:opensaml-soap-impl:4.3.2 - http://shibboleth.net/opensaml-soap-impl/)
* OpenSAML :: Storage API (org.opensaml:opensaml-storage-api:4.3.2 - http://shibboleth.net/opensaml-storage-api/)
* OpenSAML :: XML Security API (org.opensaml:opensaml-xmlsec-api:4.3.2 - http://shibboleth.net/opensaml-xmlsec-api/)
* OpenSAML :: XML Security Implementation (org.opensaml:opensaml-xmlsec-impl:4.3.2 - http://shibboleth.net/opensaml-xmlsec-impl/)
* parboiled-core (org.parboiled:parboiled-core:1.1.7 - http://parboiled.org)
* parboiled-java (org.parboiled:parboiled-java:1.1.7 - http://parboiled.org)
* org.roaringbitmap:RoaringBitmap (org.roaringbitmap:RoaringBitmap:1.0.0 - https://github.com/RoaringBitmap/RoaringBitmap)
* RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/) * RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/)
* Scala Library (org.scala-lang:scala-library:2.13.11 - https://www.scala-lang.org/) * Scala Library (org.scala-lang:scala-library:2.13.2 - https://www.scala-lang.org/)
* Scala Compiler (org.scala-lang:scala-reflect:2.13.0 - https://www.scala-lang.org/) * Scala Compiler (org.scala-lang:scala-reflect:2.13.0 - https://www.scala-lang.org/)
* scala-collection-compat (org.scala-lang.modules:scala-collection-compat_2.13:2.1.6 - http://www.scala-lang.org/) * scala-collection-compat (org.scala-lang.modules:scala-collection-compat_2.13:2.1.6 - http://www.scala-lang.org/)
* scala-java8-compat (org.scala-lang.modules:scala-java8-compat_2.13:0.9.0 - http://www.scala-lang.org/) * scala-java8-compat (org.scala-lang.modules:scala-java8-compat_2.13:0.9.0 - http://www.scala-lang.org/)
* scala-parser-combinators (org.scala-lang.modules:scala-parser-combinators_2.13:1.1.2 - http://www.scala-lang.org/) * scala-parser-combinators (org.scala-lang.modules:scala-parser-combinators_2.13:1.1.2 - http://www.scala-lang.org/)
* scala-xml (org.scala-lang.modules:scala-xml_2.13:1.3.0 - http://www.scala-lang.org/) * scala-xml (org.scala-lang.modules:scala-xml_2.13:1.3.0 - http://www.scala-lang.org/)
* JSONassert (org.skyscreamer:jsonassert:1.5.1 - https://github.com/skyscreamer/JSONassert) * JSONassert (org.skyscreamer:jsonassert:1.5.3 - https://github.com/skyscreamer/JSONassert)
* JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:2.0.11 - http://www.slf4j.org) * JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:2.0.16 - http://www.slf4j.org)
* Spring AOP (org.springframework:spring-aop:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring AOP (org.springframework:spring-aop:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Beans (org.springframework:spring-beans:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Beans (org.springframework:spring-beans:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Context (org.springframework:spring-context:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Context (org.springframework:spring-context:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Context Support (org.springframework:spring-context-support:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Context Support (org.springframework:spring-context-support:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Core (org.springframework:spring-core:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Core (org.springframework:spring-core:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Expression Language (SpEL) (org.springframework:spring-expression:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Expression Language (SpEL) (org.springframework:spring-expression:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Commons Logging Bridge (org.springframework:spring-jcl:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Commons Logging Bridge (org.springframework:spring-jcl:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring JDBC (org.springframework:spring-jdbc:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring JDBC (org.springframework:spring-jdbc:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Object/Relational Mapping (org.springframework:spring-orm:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Object/Relational Mapping (org.springframework:spring-orm:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring TestContext Framework (org.springframework:spring-test:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring TestContext Framework (org.springframework:spring-test:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Transaction (org.springframework:spring-tx:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Transaction (org.springframework:spring-tx:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Web (org.springframework:spring-web:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Web (org.springframework:spring-web:6.2.4 - https://github.com/spring-projects/spring-framework)
* Spring Web MVC (org.springframework:spring-webmvc:6.1.8 - https://github.com/spring-projects/spring-framework) * Spring Web MVC (org.springframework:spring-webmvc:6.2.4 - https://github.com/spring-projects/spring-framework)
* spring-boot (org.springframework.boot:spring-boot:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot (org.springframework.boot:spring-boot:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-actuator (org.springframework.boot:spring-boot-actuator:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-actuator (org.springframework.boot:spring-boot-actuator:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:3.4.3 - https://spring.io/projects/spring-boot)
* Spring Boot Configuration Processor (org.springframework.boot:spring-boot-configuration-processor:2.0.0.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-tools/spring-boot-configuration-processor) * Spring Boot Configuration Processor (org.springframework.boot:spring-boot-configuration-processor:2.0.0.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-tools/spring-boot-configuration-processor)
* spring-boot-starter (org.springframework.boot:spring-boot-starter:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter (org.springframework.boot:spring-boot-starter:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-test (org.springframework.boot:spring-boot-test:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-test (org.springframework.boot:spring-boot-test:3.4.3 - https://spring.io/projects/spring-boot)
* spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:3.2.6 - https://spring.io/projects/spring-boot) * spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:3.4.3 - https://spring.io/projects/spring-boot)
* Spring Data Core (org.springframework.data:spring-data-commons:3.2.6 - https://spring.io/projects/spring-data) * Spring Data Core (org.springframework.data:spring-data-commons:3.4.3 - https://spring.io/projects/spring-data)
* Spring Data REST - Core (org.springframework.data:spring-data-rest-core:4.2.6 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core) * Spring Data REST - Core (org.springframework.data:spring-data-rest-core:4.4.3 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core)
* Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:4.2.6 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc) * Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:4.4.3 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
* Spring HATEOAS (org.springframework.hateoas:spring-hateoas:2.2.2 - https://github.com/spring-projects/spring-hateoas) * Spring HATEOAS (org.springframework.hateoas:spring-hateoas:2.4.1 - https://github.com/spring-projects/spring-hateoas)
* Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:3.0.0 - https://github.com/spring-projects/spring-plugin/spring-plugin-core) * Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:3.0.0 - https://github.com/spring-projects/spring-plugin/spring-plugin-core)
* spring-security-config (org.springframework.security:spring-security-config:6.2.4 - https://spring.io/projects/spring-security) * spring-security-config (org.springframework.security:spring-security-config:6.4.3 - https://spring.io/projects/spring-security)
* spring-security-core (org.springframework.security:spring-security-core:6.2.4 - https://spring.io/projects/spring-security) * spring-security-core (org.springframework.security:spring-security-core:6.4.4 - https://spring.io/projects/spring-security)
* spring-security-crypto (org.springframework.security:spring-security-crypto:6.2.4 - https://spring.io/projects/spring-security) * spring-security-crypto (org.springframework.security:spring-security-crypto:6.4.4 - https://spring.io/projects/spring-security)
* spring-security-test (org.springframework.security:spring-security-test:6.2.4 - https://spring.io/projects/spring-security) * spring-security-saml2-service-provider (org.springframework.security:spring-security-saml2-service-provider:6.4.4 - https://spring.io/projects/spring-security)
* spring-security-web (org.springframework.security:spring-security-web:6.2.4 - https://spring.io/projects/spring-security) * spring-security-test (org.springframework.security:spring-security-test:6.4.4 - https://spring.io/projects/spring-security)
* spring-security-web (org.springframework.security:spring-security-web:6.4.4 - https://spring.io/projects/spring-security)
* thymeleaf (org.thymeleaf:thymeleaf:3.1.3.RELEASE - http://www.thymeleaf.org/thymeleaf-lib/thymeleaf)
* unbescape (org.unbescape:unbescape:1.1.6.RELEASE - http://www.unbescape.org)
* snappy-java (org.xerial.snappy:snappy-java:1.1.10.1 - https://github.com/xerial/snappy-java) * snappy-java (org.xerial.snappy:snappy-java:1.1.10.1 - https://github.com/xerial/snappy-java)
* xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/) * xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/)
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.10.0 - https://www.xmlunit.org/) * org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.10.0 - https://www.xmlunit.org/)
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.9.1 - https://www.xmlunit.org/) * org.xmlunit:xmlunit-placeholders (org.xmlunit:xmlunit-placeholders:2.9.1 - https://www.xmlunit.org/xmlunit-placeholders/)
* org.xmlunit:xmlunit-placeholders (org.xmlunit:xmlunit-placeholders:2.8.0 - https://www.xmlunit.org/xmlunit-placeholders/) * SnakeYAML (org.yaml:snakeyaml:2.3 - https://bitbucket.org/snakeyaml/snakeyaml)
* SnakeYAML (org.yaml:snakeyaml:2.2 - https://bitbucket.org/snakeyaml/snakeyaml)
* software.amazon.ion:ion-java (software.amazon.ion:ion-java:1.0.2 - https://github.com/amznlabs/ion-java/)
* Xerces2-j (xerces:xercesImpl:2.12.2 - https://xerces.apache.org/xerces2-j/) * Xerces2-j (xerces:xercesImpl:2.12.2 - https://xerces.apache.org/xerces2-j/)
BSD License: BSD License:
@@ -463,27 +488,32 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.13.4 - http://github.com/jsonld-java/jsonld-java/jsonld-java/) * JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.13.4 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
* curvesapi (com.github.virtuald:curvesapi:1.08 - https://github.com/virtuald/curvesapi) * curvesapi (com.github.virtuald:curvesapi:1.08 - https://github.com/virtuald/curvesapi)
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.15.0 - https://developers.google.com/protocol-buffers/protobuf-java/) * Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.15.0 - https://developers.google.com/protocol-buffers/protobuf-java/)
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.23.3 - https://developers.google.com/protocol-buffers/protobuf-java/) * Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.24.3 - https://developers.google.com/protocol-buffers/protobuf-java/)
* JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/) * JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/)
* dnsjava (dnsjava:dnsjava:2.1.9 - http://www.dnsjava.org) * jmustache (com.samskivert:jmustache:1.15 - http://github.com/samskivert/jmustache)
* dnsjava (dnsjava:dnsjava:3.6.3 - https://github.com/dnsjava/dnsjava)
* jaxen (jaxen:jaxen:2.0.0 - http://www.cafeconleche.org/jaxen/jaxen) * jaxen (jaxen:jaxen:2.0.0 - http://www.cafeconleche.org/jaxen/jaxen)
* ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.13.1 - https://www.antlr.org/antlr4-runtime/) * ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.13.2 - https://www.antlr.org/antlr4-runtime/)
* commons-compiler (org.codehaus.janino:commons-compiler:3.1.8 - http://janino-compiler.github.io/commons-compiler/) * commons-compiler (org.codehaus.janino:commons-compiler:3.1.8 - http://janino-compiler.github.io/commons-compiler/)
* janino (org.codehaus.janino:janino:3.1.8 - http://janino-compiler.github.io/janino/) * janino (org.codehaus.janino:janino:3.1.8 - http://janino-compiler.github.io/janino/)
* Stax2 API (org.codehaus.woodstox:stax2-api:4.2.1 - http://github.com/FasterXML/stax2-api) * Stax2 API (org.codehaus.woodstox:stax2-api:4.2.1 - http://github.com/FasterXML/stax2-api)
* Hamcrest Date (org.exparity:hamcrest-date:2.0.8 - https://github.com/exparity/hamcrest-date) * Hamcrest Date (org.exparity:hamcrest-date:2.0.8 - https://github.com/exparity/hamcrest-date)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/) * Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/)
* Hamcrest Core (org.hamcrest:hamcrest-core:2.2 - http://hamcrest.org/JavaHamcrest/) * Hamcrest Core (org.hamcrest:hamcrest-core:2.2 - http://hamcrest.org/JavaHamcrest/)
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/) * HdrHistogram (org.hdrhistogram:HdrHistogram:2.2.2 - http://hdrhistogram.github.io/HdrHistogram/)
* JBibTeX (org.jbibtex:jbibtex:1.0.20 - http://www.jbibtex.org) * JBibTeX (org.jbibtex:jbibtex:1.0.20 - http://www.jbibtex.org)
* asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/) * asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/)
* asm-analysis (org.ow2.asm:asm-analysis:8.0.1 - http://asm.ow2.io/) * asm-analysis (org.ow2.asm:asm-analysis:8.0.1 - http://asm.ow2.io/)
* asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/) * asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/)
* asm-tree (org.ow2.asm:asm-tree:8.0.1 - http://asm.ow2.io/) * asm-tree (org.ow2.asm:asm-tree:8.0.1 - http://asm.ow2.io/)
* asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/) * ASM Util (org.ow2.asm:asm-util:5.0.3 - http://asm.objectweb.org/asm-util/)
* PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.3 - https://jdbc.postgresql.org) * PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.5 - https://jdbc.postgresql.org)
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections) * Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections)
* JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio) * JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio)
* XZ for Java (org.tukaani:xz:1.10 - https://tukaani.org/xz/java.html)
* XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/) * XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/)
CC0: CC0:
@@ -497,7 +527,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:2.3.1 - http://jaxb.java.net/jaxb-bundles/jaxb-impl) * Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:2.3.1 - http://jaxb.java.net/jaxb-bundles/jaxb-impl)
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca) * Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca)
* Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api) * Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api)
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.0.0 - https://projects.eclipse.org/projects/ee4j.servlet) * Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.1.0 - https://projects.eclipse.org/projects/ee4j.servlet)
* jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta) * jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta)
* JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/) * JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/)
* javax.annotation API (javax.annotation:javax.annotation-api:1.3 - http://jcp.org/en/jsr/detail?id=250) * javax.annotation API (javax.annotation:javax.annotation-api:1.3 - http://jcp.org/en/jsr/detail?id=250)
@@ -506,13 +536,13 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* jaxb-api (javax.xml.bind:jaxb-api:2.3.1 - https://github.com/javaee/jaxb-spec/jaxb-api) * jaxb-api (javax.xml.bind:jaxb-api:2.3.1 - https://github.com/javaee/jaxb-spec/jaxb-api)
* JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight) * JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight)
* Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail) * Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail)
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api) * HK2 API module (org.glassfish.hk2:hk2-api:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator) * ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils) * HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
* OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator) * OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator)
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged) * aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
Cordra (Version 2) License Agreement: Cordra (Version 2) License Agreement:
@@ -536,8 +566,8 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* JAXB Core (org.glassfish.jaxb:jaxb-core:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/) * JAXB Core (org.glassfish.jaxb:jaxb-core:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
* JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/) * JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
* TXW2 Runtime (org.glassfish.jaxb:txw2:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/) * TXW2 Runtime (org.glassfish.jaxb:txw2:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* MIME streaming extension (org.jvnet.mimepull:mimepull:1.9.15 - https://github.com/eclipse-ee4j/metro-mimepull) * MIME streaming extension (org.jvnet.mimepull:mimepull:1.9.15 - https://github.com/eclipse-ee4j/metro-mimepull)
* org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core) * org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core)
@@ -546,16 +576,16 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Eclipse Public License: Eclipse Public License:
* System Rules (com.github.stefanbirkner:system-rules:1.19.0 - http://stefanbirkner.github.io/system-rules/) * System Rules (com.github.stefanbirkner:system-rules:1.19.0 - http://stefanbirkner.github.io/system-rules/)
* H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com) * H2 Database Engine (com.h2database:h2:2.3.232 - https://h2database.com)
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca) * Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca)
* Jakarta Expression Language API (jakarta.el:jakarta.el-api:5.0.1 - https://projects.eclipse.org/projects/ee4j.el) * Jakarta Expression Language API (jakarta.el:jakarta.el-api:5.0.1 - https://projects.eclipse.org/projects/ee4j.el)
* Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api) * Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api)
* Jakarta Persistence API (jakarta.persistence:jakarta.persistence-api:3.1.0 - https://github.com/eclipse-ee4j/jpa-api) * Jakarta Persistence API (jakarta.persistence:jakarta.persistence-api:3.1.0 - https://github.com/eclipse-ee4j/jpa-api)
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.0.0 - https://projects.eclipse.org/projects/ee4j.servlet) * Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.1.0 - https://projects.eclipse.org/projects/ee4j.servlet)
* jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta) * jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta)
* Jakarta RESTful WS API (jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 - https://github.com/eclipse-ee4j/jaxrs-api) * Jakarta RESTful WS API (jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 - https://github.com/eclipse-ee4j/jaxrs-api)
* JUnit (junit:junit:4.13.2 - http://junit.org) * JUnit (junit:junit:4.13.2 - http://junit.org)
* AspectJ Weaver (org.aspectj:aspectjweaver:1.9.22 - https://www.eclipse.org/aspectj/) * AspectJ Weaver (org.aspectj:aspectjweaver:1.9.22.1 - https://www.eclipse.org/aspectj/)
* Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail) * Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail)
* Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/) * Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/)
@@ -569,65 +599,72 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client) * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation) * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
* Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy) * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.57.v20241219 - https://jetty.org/jetty-deploy/)
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http) * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.57.v20241219 - https://jetty.org/jetty-http/)
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io) * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.57.v20241219 - https://jetty.org/jetty-io/)
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx) * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx)
* Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: JNDI Naming (org.eclipse.jetty:jetty-jndi:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Plus (org.eclipse.jetty:jetty-plus:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite) * Jetty :: Rewrite Handler (org.eclipse.jetty:jetty-rewrite:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-rewrite)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security) * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-security)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-security) * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.57.v20241219 - https://jetty.org/jetty-security/)
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server) * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.57.v20241219 - https://jetty.org/jetty-server/)
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet) * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.57.v20241219 - https://jetty.org/jetty-servlet/)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets) * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets)
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util) * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.57.v20241219 - https://jetty.org/jetty-util/)
* Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax) * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.57.v20241219 - https://jetty.org/jetty-util-ajax/)
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp) * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.57.v20241219 - https://jetty.org/jetty-webapp/)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml) * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml) * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.57.v20241219 - https://jetty.org/jetty-xml/)
* Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api) * Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api)
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client) * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client)
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common) * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.57.v20241219 - https://jetty.org/http2-parent/http2-common/)
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack) * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack)
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport) * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server) * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas) * Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
* JSON-P Default Provider (org.glassfish:jakarta.json:2.0.1 - https://github.com/eclipse-ee4j/jsonp) * JSON-P Default Provider (org.glassfish:jakarta.json:2.0.1 - https://github.com/eclipse-ee4j/jsonp)
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api) * HK2 API module (org.glassfish.hk2:hk2-api:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator) * ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils) * HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
* OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator) * OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator)
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged) * aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) * jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core) * org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core)
* org.locationtech.jts.io:jts-io-common (org.locationtech.jts.io:jts-io-common:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-io/jts-io-common) * org.locationtech.jts.io:jts-io-common (org.locationtech.jts.io:jts-io-common:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-io/jts-io-common)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty)
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester) GENERAL PUBLIC LICENSE, version 3 (GPL-3.0):
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
* juniversalchardet (com.github.albfernandez:juniversalchardet:2.5.0 - https://github.com/albfernandez/juniversalchardet)
GNU Lesser General Public License (LGPL): GNU Lesser General Public License (LGPL):
* juniversalchardet (com.github.albfernandez:juniversalchardet:2.5.0 - https://github.com/albfernandez/juniversalchardet)
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf) * btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
* jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils) * jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
* jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils) * jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
* json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
* json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core) * json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
* json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator) * json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
* msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple) * msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
* uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template) * uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
* openpdf (com.github.librepdf:openpdf:2.0.3 - https://github.com/LibrePDF/OpenPDF/openpdf)
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/) * FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/)
* JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight) * JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight)
* Cryptacular Library (org.cryptacular:cryptacular:1.2.5 - http://www.cryptacular.org)
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:6.0.6.Final - http://hibernate.org) * Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:6.0.6.Final - http://hibernate.org)
* Hibernate ORM - hibernate-core (org.hibernate.orm:hibernate-core:6.4.8.Final - https://hibernate.org/orm) * Hibernate ORM - hibernate-core (org.hibernate.orm:hibernate-core:6.4.8.Final - https://hibernate.org/orm)
* Hibernate ORM - hibernate-jcache (org.hibernate.orm:hibernate-jcache:6.4.8.Final - https://hibernate.org/orm) * Hibernate ORM - hibernate-jcache (org.hibernate.orm:hibernate-jcache:6.4.8.Final - https://hibernate.org/orm)
* Hibernate ORM - hibernate-jpamodelgen (org.hibernate.orm:hibernate-jpamodelgen:6.4.8.Final - https://hibernate.org/orm) * Hibernate ORM - hibernate-jpamodelgen (org.hibernate.orm:hibernate-jpamodelgen:6.4.8.Final - https://hibernate.org/orm)
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/) * im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
* Javassist (org.javassist:javassist:3.29.2-GA - http://www.javassist.org/) * Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
* Flying Saucer Core Renderer (org.xhtmlrenderer:flying-saucer-core:9.11.4 - http://code.google.com/p/flying-saucer/flying-saucer-core/)
* Flying Saucer PDF Rendering (org.xhtmlrenderer:flying-saucer-pdf:9.11.4 - http://code.google.com/p/flying-saucer/flying-saucer-pdf/)
* XOM (xom:xom:1.3.9 - https://xom.nu) * XOM (xom:xom:1.3.9 - https://xom.nu)
Go License: Go License:
@@ -648,25 +685,22 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* better-files (com.github.pathikrit:better-files_2.13:3.9.1 - https://github.com/pathikrit/better-files) * better-files (com.github.pathikrit:better-files_2.13:3.9.1 - https://github.com/pathikrit/better-files)
* Java SemVer (com.github.zafarkhaja:java-semver:0.9.0 - https://github.com/zafarkhaja/jsemver) * Java SemVer (com.github.zafarkhaja:java-semver:0.9.0 - https://github.com/zafarkhaja/jsemver)
* dd-plist (com.googlecode.plist:dd-plist:1.28 - http://www.github.com/3breadt/dd-plist) * dd-plist (com.googlecode.plist:dd-plist:1.28 - http://www.github.com/3breadt/dd-plist)
* DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.10 - https://github.com/dbmdz/iiif-apis) * DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.11 - https://github.com/dbmdz/iiif-apis)
* s3mock (io.findify:s3mock_2.13:0.2.6 - https://github.com/findify/s3mock) * s3mock (io.findify:s3mock_2.13:0.2.6 - https://github.com/findify/s3mock)
* ClassGraph (io.github.classgraph:classgraph:4.8.165 - https://github.com/classgraph/classgraph) * ClassGraph (io.github.classgraph:classgraph:4.8.165 - https://github.com/classgraph/classgraph)
* JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.4 - http://jopt-simple.github.io/jopt-simple) * JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.4 - http://jopt-simple.github.io/jopt-simple)
* Bouncy Castle S/MIME API (org.bouncycastle:bcmail-jdk18on:1.77 - https://www.bouncycastle.org/java.html) * Bouncy Castle JavaMail S/MIME APIs (org.bouncycastle:bcmail-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
* Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk15on:1.67 - http://www.bouncycastle.org/java.html) * Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
* Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html) * Bouncy Castle Provider (org.bouncycastle:bcprov-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.67 - http://www.bouncycastle.org/java.html) * Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html)
* Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html)
* org.brotli:dec (org.brotli:dec:0.1.2 - http://brotli.org/dec) * org.brotli:dec (org.brotli:dec:0.1.2 - http://brotli.org/dec)
* Checker Qual (org.checkerframework:checker-qual:3.31.0 - https://checkerframework.org) * Checker Qual (org.checkerframework:checker-qual:3.49.0 - https://checkerframework.org/)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* mockito-core (org.mockito:mockito-core:3.12.4 - https://github.com/mockito/mockito) * mockito-core (org.mockito:mockito-core:3.12.4 - https://github.com/mockito/mockito)
* mockito-inline (org.mockito:mockito-inline:3.12.4 - https://github.com/mockito/mockito) * mockito-inline (org.mockito:mockito-inline:3.12.4 - https://github.com/mockito/mockito)
* SLF4J API Module (org.slf4j:slf4j-api:2.0.11 - http://www.slf4j.org) * SLF4J API Module (org.slf4j:slf4j-api:2.0.16 - http://www.slf4j.org)
* SLF4J Extensions Module (org.slf4j:slf4j-ext:1.7.28 - http://www.slf4j.org)
* HAL Browser (org.webjars:hal-browser:ad9b865 - http://webjars.org) * HAL Browser (org.webjars:hal-browser:ad9b865 - http://webjars.org)
* toastr (org.webjars.bowergithub.codeseven:toastr:2.1.4 - http://webjars.org) * toastr (org.webjars.bowergithub.codeseven:toastr:2.1.4 - http://webjars.org)
* backbone (org.webjars.bowergithub.jashkenas:backbone:1.4.1 - https://www.webjars.org) * backbone (org.webjars.bowergithub.jashkenas:backbone:1.4.1 - https://www.webjars.org)
@@ -674,28 +708,29 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* jquery (org.webjars.bowergithub.jquery:jquery-dist:3.7.1 - https://www.webjars.org) * jquery (org.webjars.bowergithub.jquery:jquery-dist:3.7.1 - https://www.webjars.org)
* urijs (org.webjars.bowergithub.medialize:uri.js:1.19.11 - https://www.webjars.org) * urijs (org.webjars.bowergithub.medialize:uri.js:1.19.11 - https://www.webjars.org)
* bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.6.2 - https://www.webjars.org) * bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.6.2 - https://www.webjars.org)
* core-js (org.webjars.npm:core-js:3.37.1 - https://www.webjars.org) * core-js (org.webjars.npm:core-js:3.41.0 - https://www.webjars.org)
* @json-editor/json-editor (org.webjars.npm:json-editor__json-editor:2.6.1 - https://www.webjars.org) * @json-editor/json-editor (org.webjars.npm:json-editor__json-editor:2.15.1 - https://www.webjars.org)
Mozilla Public License: Mozilla Public License:
* juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet) * juniversalchardet (com.github.albfernandez:juniversalchardet:2.5.0 - https://github.com/albfernandez/juniversalchardet)
* H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com) * openpdf (com.github.librepdf:openpdf:2.0.3 - https://github.com/LibrePDF/OpenPDF/openpdf)
* H2 Database Engine (com.h2database:h2:2.3.232 - https://h2database.com)
* Saxon-HE (net.sf.saxon:Saxon-HE:9.8.0-14 - http://www.saxonica.com/) * Saxon-HE (net.sf.saxon:Saxon-HE:9.8.0-14 - http://www.saxonica.com/)
* Javassist (org.javassist:javassist:3.29.2-GA - http://www.javassist.org/) * Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
* Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino) * Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino)
Public Domain: Public Domain:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/) * HdrHistogram (org.hdrhistogram:HdrHistogram:2.2.2 - http://hdrhistogram.github.io/HdrHistogram/)
* JSON in Java (org.json:json:20231013 - https://github.com/douglascrockford/JSON-java) * JSON in Java (org.json:json:20231013 - https://github.com/douglascrockford/JSON-java)
* LatencyUtils (org.latencyutils:LatencyUtils:2.0.3 - http://latencyutils.github.io/LatencyUtils/) * LatencyUtils (org.latencyutils:LatencyUtils:2.0.3 - http://latencyutils.github.io/LatencyUtils/)
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections) * Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections)
* XZ for Java (org.tukaani:xz:1.9 - https://tukaani.org/xz/java.html)
UnRar License: UnRar License:
@@ -703,16 +738,16 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Unicode/ICU License: Unicode/ICU License:
* ICU4J (com.ibm.icu:icu4j:62.1 - http://icu-project.org/) * ICU4J (com.ibm.icu:icu4j:62.2 - http://icu-project.org/)
W3C license: W3C license:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
jQuery license: jQuery license:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart) * jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)

View File

@@ -7,4 +7,5 @@
<!-- TODO: We should have these turned on. But, currently there's a known bug with indentation checks <!-- TODO: We should have these turned on. But, currently there's a known bug with indentation checks
on JMockIt Expectations blocks and similar. See https://github.com/checkstyle/checkstyle/issues/3739 --> on JMockIt Expectations blocks and similar. See https://github.com/checkstyle/checkstyle/issues/3739 -->
<suppress checks="Indentation" files="src[/\\]test[/\\]java"/> <suppress checks="Indentation" files="src[/\\]test[/\\]java"/>
<suppress checks="Regexp" files="DSpaceHttpClientFactory\.java"/>
</suppressions> </suppressions>

View File

@@ -136,5 +136,22 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
<module name="OneStatementPerLine"/> <module name="OneStatementPerLine"/>
<!-- Require that "catch" statements are not empty (must at least contain a comment) --> <!-- Require that "catch" statements are not empty (must at least contain a comment) -->
<module name="EmptyCatchBlock"/> <module name="EmptyCatchBlock"/>
<!-- Require to use DSpaceHttpClientFactory.getClient() statement instead of creating directly the client -->
<module name="Regexp">
<property name="format" value="HttpClientBuilder\.create\s*\(\s*\)" />
<property name="message" value="Use DSpaceHttpClientFactory.getClient() instead of HttpClientBuilder.create()" />
<property name="illegalPattern" value="true"/>
<property name="ignoreComments" value="true"/>
</module>
<!-- Require to use DSpaceHttpClientFactory.getClient() statement instead of creating directly the client -->
<module name="Regexp">
<property name="format" value="HttpClients\.createDefault\s*\(\s*\)" />
<property name="message" value="Use DSpaceHttpClientFactory.getClient() instead of HttpClients.createDefault()" />
<property name="illegalPattern" value="true"/>
<property name="ignoreComments" value="true"/>
</module>
</module> </module>
</module> </module>

View File

@@ -93,7 +93,7 @@ services:
additional_contexts: additional_contexts:
solrconfigs: ./dspace/solr/ solrconfigs: ./dspace/solr/
args: args:
SOLR_VERSION: "${SOLR_VER:-8.11}" SOLR_VERSION: "${SOLR_VER:-9.8}"
networks: networks:
dspacenet: dspacenet:
ports: ports:
@@ -105,10 +105,15 @@ services:
volumes: volumes:
# Keep Solr data directory between reboots # Keep Solr data directory between reboots
- solr_data:/var/solr/data - solr_data:/var/solr/data
# NOTE: We are not running Solr as "root", but we need root permissions to copy our cores to the mounted
# /var/solr/data directory. Then we start Solr as the "solr" user.
user: root
# Initialize all DSpace Solr cores then start Solr: # Initialize all DSpace Solr cores then start Solr:
# * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op # * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op
# * Second, copy configsets to this core: # * Second, copy configsets to this core:
# Updates to Solr configs require the container to be rebuilt/restarted: `docker compose -p d7 up -d --build dspacesolr` # Updates to Solr configs require the container to be rebuilt/restarted: `docker compose -p d7 up -d --build dspacesolr`
# * Third, ensure all new folders are owned by "solr" user
# * Finally, start Solr as the "solr" user via the provided solr-foreground script
entrypoint: entrypoint:
- /bin/bash - /bin/bash
- '-c' - '-c'
@@ -126,7 +131,8 @@ services:
cp -r /opt/solr/server/solr/configsets/qaevent/* qaevent cp -r /opt/solr/server/solr/configsets/qaevent/* qaevent
precreate-core suggestion /opt/solr/server/solr/configsets/suggestion precreate-core suggestion /opt/solr/server/solr/configsets/suggestion
cp -r /opt/solr/server/solr/configsets/suggestion/* suggestion cp -r /opt/solr/server/solr/configsets/suggestion/* suggestion
exec solr -f chown -R solr:solr /var/solr
runuser -u solr -- solr-foreground
volumes: volumes:
assetstore: assetstore:
pgdata: pgdata:

View File

@@ -177,7 +177,7 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId> <artifactId>jaxb2-maven-plugin</artifactId>
<version>3.2.0</version> <version>3.3.0</version>
<executions> <executions>
<execution> <execution>
<id>workflow-curation</id> <id>workflow-curation</id>
@@ -500,10 +500,6 @@
<groupId>jakarta.annotation</groupId> <groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId> <artifactId>jakarta.annotation-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
</dependency>
<dependency> <dependency>
<groupId>jaxen</groupId> <groupId>jaxen</groupId>
<artifactId>jaxen</artifactId> <artifactId>jaxen</artifactId>
@@ -653,11 +649,18 @@
<version>1.1.1</version> <version>1.1.1</version>
</dependency> </dependency>
<!-- guava is needed by OAuth, Guice, Mockserver, ORCID, s3mock, Solr, JClouds -->
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>
<artifactId>guava</artifactId> <artifactId>guava</artifactId>
</dependency> </dependency>
<!-- Gson is needed by JENA, borker-client, OAuth, Handle and JClouds -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
@@ -731,7 +734,7 @@
<dependency> <dependency>
<groupId>com.amazonaws</groupId> <groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId> <artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.781</version> <version>1.12.783</version>
</dependency> </dependency>
<!-- TODO: This may need to be replaced with the "orcid-model" artifact once this ticket is resolved: <!-- TODO: This may need to be replaced with the "orcid-model" artifact once this ticket is resolved:
@@ -767,11 +770,12 @@
<version>1.19.0</version> <version>1.19.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Used for Solr core export/import --> <!-- Used for Solr core export/import -->
<dependency> <dependency>
<groupId>com.opencsv</groupId> <groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId> <artifactId>opencsv</artifactId>
<version>5.10</version> <version>5.11</version>
</dependency> </dependency>
<!-- Email templating --> <!-- Email templating -->
@@ -860,6 +864,55 @@
</exclusions> </exclusions>
</dependency> </dependency>
<!-- JClouds Assetstorage Support -->
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${jclouds.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</exclusion>
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
<exclusion>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${jclouds.version}</version>
<exclusions>
<exclusion>
<groupId>jakarta.ws.rs</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>filesystem</artifactId>
<version>${jclouds.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jclouds.provider</groupId>
<artifactId>aws-s3</artifactId>
<version>${jclouds.version}</version>
</dependency>
<!-- required frontpage generation --> <!-- required frontpage generation -->
<dependency> <dependency>
<groupId>org.thymeleaf</groupId> <groupId>org.thymeleaf</groupId>
@@ -876,7 +929,20 @@
<dependency> <dependency>
<groupId>org.xhtmlrenderer</groupId> <groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId> <artifactId>flying-saucer-pdf</artifactId>
<version>9.11.4</version> <version>9.12.0</version>
<exclusions>
<!-- Conflicts with Hibernate. Use version that is brought in via Hibernate -->
<exclusion>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -21,6 +21,13 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.BitstreamFormat; import org.dspace.content.BitstreamFormat;
@@ -41,7 +48,7 @@ import org.xml.sax.SAXException;
* <P> * <P>
* <code>RegistryLoader -bitstream bitstream-formats.xml</code> * <code>RegistryLoader -bitstream bitstream-formats.xml</code>
* <P> * <P>
* <code>RegistryLoader -dc dc-types.xml</code> * <code>RegistryLoader -metadata dc-types.xml</code>
* *
* @author Robert Tansley * @author Robert Tansley
* @version $Revision$ * @version $Revision$
@@ -50,7 +57,7 @@ public class RegistryLoader {
/** /**
* log4j category * log4j category
*/ */
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RegistryLoader.class); private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RegistryLoader.class);
protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
.getBitstreamFormatService(); .getBitstreamFormatService();
@@ -67,50 +74,99 @@ public class RegistryLoader {
* @throws Exception if error * @throws Exception if error
*/ */
public static void main(String[] argv) throws Exception { public static void main(String[] argv) throws Exception {
String usage = "Usage: " + RegistryLoader.class.getName() // Set up command-line options and parse arguments
+ " (-bitstream | -metadata) registry-file.xml"; CommandLineParser parser = new DefaultParser();
Options options = createCommandLineOptions();
Context context = null;
try { try {
context = new Context(); CommandLine line = parser.parse(options, argv);
// Check if help option was entered or no options provided
if (line.hasOption('h') || line.getOptions().length == 0) {
printHelp(options);
System.exit(0);
}
Context context = new Context();
// Can't update registries anonymously, so we need to turn off // Can't update registries anonymously, so we need to turn off
// authorisation // authorisation
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
// Work out what we're loading try {
if (argv[0].equalsIgnoreCase("-bitstream")) { // Work out what we're loading
RegistryLoader.loadBitstreamFormats(context, argv[1]); if (line.hasOption('b')) {
} else if (argv[0].equalsIgnoreCase("-metadata")) { String filename = line.getOptionValue('b');
// Call MetadataImporter, as it handles Metadata schema updates if (StringUtils.isEmpty(filename)) {
MetadataImporter.loadRegistry(argv[1], true); System.err.println("No file path provided for bitstream format registry");
} else { printHelp(options);
System.err.println(usage); System.exit(1);
}
RegistryLoader.loadBitstreamFormats(context, filename);
} else if (line.hasOption('m')) {
String filename = line.getOptionValue('m');
if (StringUtils.isEmpty(filename)) {
System.err.println("No file path provided for metadata registry");
printHelp(options);
System.exit(1);
}
// Call MetadataImporter, as it handles Metadata schema updates
MetadataImporter.loadRegistry(filename, true);
} else {
System.err.println("No registry type specified");
printHelp(options);
System.exit(1);
}
// Commit changes and close Context
context.complete();
System.exit(0);
} catch (Exception e) {
log.fatal(LogHelper.getHeader(context, "error_loading_registries", ""), e);
System.err.println("Error: \n - " + e.getMessage());
System.exit(1);
} finally {
// Clean up our context, if it still exists & it was never completed
if (context != null && context.isValid()) {
context.abort();
}
} }
} catch (ParseException e) {
// Commit changes and close Context System.err.println("Error parsing command-line arguments: " + e.getMessage());
context.complete(); printHelp(options);
System.exit(0);
} catch (ArrayIndexOutOfBoundsException ae) {
System.err.println(usage);
System.exit(1); System.exit(1);
} catch (Exception e) {
log.fatal(LogHelper.getHeader(context, "error_loading_registries",
""), e);
System.err.println("Error: \n - " + e.getMessage());
System.exit(1);
} finally {
// Clean up our context, if it still exists & it was never completed
if (context != null && context.isValid()) {
context.abort();
}
} }
} }
/**
* Create the command-line options
* @return the command-line options
*/
private static Options createCommandLineOptions() {
Options options = new Options();
options.addOption("b", "bitstream", true, "load bitstream format registry from specified file");
options.addOption("m", "metadata", true, "load metadata registry from specified file");
options.addOption("h", "help", false, "print this help message");
return options;
}
/**
* Print the help message
* @param options the command-line options
*/
private static void printHelp(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("RegistryLoader",
"Load bitstream format or metadata registries into the database\n",
options,
"\nExamples:\n" +
" RegistryLoader -b bitstream-formats.xml\n" +
" RegistryLoader -m dc-types.xml",
true);
}
/** /**
* Load Bitstream Format metadata * Load Bitstream Format metadata
* *
@@ -221,7 +277,7 @@ public class RegistryLoader {
* contains: * contains:
* <P> * <P>
* <code> * <code>
* &lt;foo&gt;&lt;mimetype&gt;application/pdf&lt;/mimetype&gt;&lt;/foo&gt; * <foo><mimetype>application/pdf</mimetype></foo>
* </code> * </code>
* passing this the <code>foo</code> node and <code>mimetype</code> will * passing this the <code>foo</code> node and <code>mimetype</code> will
* return <code>application/pdf</code>. * return <code>application/pdf</code>.
@@ -262,10 +318,10 @@ public class RegistryLoader {
* document contains: * document contains:
* <P> * <P>
* <code> * <code>
* &lt;foo&gt; * <foo>
* &lt;bar&gt;val1&lt;/bar&gt; * <bar>val1</bar>
* &lt;bar&gt;val2&lt;/bar&gt; * <bar>val2</bar>
* &lt;/foo&gt; * </foo>
* </code> * </code>
* passing this the <code>foo</code> node and <code>bar</code> will * passing this the <code>foo</code> node and <code>bar</code> will
* return <code>val1</code> and <code>val2</code>. * return <code>val1</code> and <code>val2</code>.
@@ -295,4 +351,4 @@ public class RegistryLoader {
return data; return data;
} }
} }

View File

@@ -416,7 +416,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
discoverQuery.setQuery(query); discoverQuery.setQuery(query);
discoverQuery.setStart(start); discoverQuery.setStart(start);
discoverQuery.setMaxResults(limit); discoverQuery.setMaxResults(limit);
discoverQuery.setSortField("search.resourceid", DiscoverQuery.SORT_ORDER.asc);
return discoverQuery; return discoverQuery;
} }

View File

@@ -142,7 +142,8 @@ public class MetadataExportFilteredItemsReport extends DSpaceRunnable
FilteredItems items = contentReportService.findFilteredItems(context, query); FilteredItems items = contentReportService.findFilteredItems(context, query);
handler.logDebug("creating dspacecsv"); handler.logDebug("creating dspacecsv");
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, items.getItems().iterator(), true); DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, items.getItems().iterator(),
true, handler);
handler.logDebug("writing to file " + getFileNameOrExportFile()); handler.logDebug("writing to file " + getFileNameOrExportFile());
handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV); handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV);
context.restoreAuthSystemState(); context.restoreAuthSystemState();

View File

@@ -143,7 +143,7 @@ public class MetadataExportSearch extends DSpaceRunnable<MetadataExportSearchScr
Iterator<Item> itemIterator = searchService.iteratorSearch(context, dso, discoverQuery); Iterator<Item> itemIterator = searchService.iteratorSearch(context, dso, discoverQuery);
handler.logDebug("creating dspacecsv"); handler.logDebug("creating dspacecsv");
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, itemIterator, true); DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, itemIterator, true, handler);
handler.logDebug("writing to file " + getFileNameOrExportFile()); handler.logDebug("writing to file " + getFileNameOrExportFile());
handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV); handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV);
context.restoreAuthSystemState(); context.restoreAuthSystemState();

View File

@@ -23,6 +23,7 @@ import java.util.UUID;
import jakarta.annotation.Nullable; import jakarta.annotation.Nullable;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.util.RelationshipUtils; import org.dspace.app.util.RelationshipUtils;
@@ -89,7 +90,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
/** /**
* The authority controlled fields * The authority controlled fields
*/ */
protected static Set<String> authorityControlled; protected Set<String> authorityControlled;
/** /**
* The prefix of the authority controlled field * The prefix of the authority controlled field
@@ -742,10 +743,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
if (value == null || !value.contains(csv.getAuthoritySeparator())) { if (value == null || !value.contains(csv.getAuthoritySeparator())) {
simplyCopyValue(value, dcv); simplyCopyValue(value, dcv);
} else { } else {
String[] parts = value.split(csv.getAuthoritySeparator()); resolveValueAndAuthority(value, dcv);
dcv.setValue(parts[0]);
dcv.setAuthority(parts[1]);
dcv.setConfidence((parts.length > 2 ? Integer.valueOf(parts[2]) : Choices.CF_ACCEPTED));
} }
// fromAuthority==null: with the current implementation metadata values from external authority sources // fromAuthority==null: with the current implementation metadata values from external authority sources
@@ -1162,10 +1160,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
} else if (value == null || !value.contains(csv.getAuthoritySeparator())) { } else if (value == null || !value.contains(csv.getAuthoritySeparator())) {
simplyCopyValue(value, dcv); simplyCopyValue(value, dcv);
} else { } else {
String[] parts = value.split(csv.getEscapedAuthoritySeparator()); resolveValueAndAuthority(value, dcv);
dcv.setValue(parts[0]);
dcv.setAuthority(parts[1]);
dcv.setConfidence((parts.length > 2 ? Integer.valueOf(parts[2]) : Choices.CF_ACCEPTED));
} }
return dcv; return dcv;
} }
@@ -1176,6 +1171,35 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
dcv.setConfidence(Choices.CF_UNSET); dcv.setConfidence(Choices.CF_UNSET);
} }
private void resolveValueAndAuthority(String value, BulkEditMetadataValue dcv) {
// Cells with valid authority are composed of three parts ~ <value>, <authority>, <confidence>
// The value itself may also include the authority separator though
String[] parts = value.split(csv.getEscapedAuthoritySeparator());
// If we don't have enough parts, assume the whole string is the value
if (parts.length < 3) {
simplyCopyValue(value, dcv);
return;
}
try {
// The last part of the cell must be a confidence value (integer)
int confidence = Integer.parseInt(parts[parts.length - 1]);
String authority = parts[parts.length - 2];
String plainValue = String.join(
csv.getAuthoritySeparator(),
ArrayUtils.subarray(parts, 0, parts.length - 2)
);
dcv.setValue(plainValue);
dcv.setAuthority(authority);
dcv.setConfidence(confidence);
} catch (NumberFormatException e) {
// Otherwise assume the whole string is the value
simplyCopyValue(value, dcv);
}
}
/** /**
* Method to find if a String occurs in an array of Strings * Method to find if a String occurs in an array of Strings
* *
@@ -1368,10 +1392,10 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
/** /**
* is the field is defined as authority controlled * is the field is defined as authority controlled
*/ */
private static boolean isAuthorityControlledField(String md) { private boolean isAuthorityControlledField(String md) {
String mdf = md.contains(":") ? StringUtils.substringAfter(md, ":") : md; String mdf = md.contains(":") ? StringUtils.substringAfter(md, ":") : md;
mdf = StringUtils.substringBefore(mdf, "["); mdf = StringUtils.substringBefore(mdf, "[");
return authorityControlled.contains(mdf); return authorityControlled.contains(mdf) || authorityControlled.contains(md);
} }
/** /**
@@ -1802,5 +1826,4 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
String targetType, String originType, String originTypeName) { String targetType, String originType, String originTypeName) {
return RelationshipUtils.matchRelationshipType(relTypes, targetType, originType, originTypeName); return RelationshipUtils.matchRelationshipType(relTypes, targetType, originType, originTypeName);
} }
} }

View File

@@ -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.app.client;
import static org.apache.commons.collections4.ListUtils.emptyIfNull;
import java.util.List;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Factory of {@link HttpClient} with common configurations.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class DSpaceHttpClientFactory {
@Autowired
private ConfigurationService configurationService;
@Autowired
private DSpaceProxyRoutePlanner proxyRoutePlanner;
@Autowired(required = false)
private List<HttpRequestInterceptor> requestInterceptors;
@Autowired(required = false)
private List<HttpResponseInterceptor> responseInterceptors;
/**
* Get an instance of {@link DSpaceHttpClientFactory} from the Spring context.
* @return the bean instance
*/
public static DSpaceHttpClientFactory getInstance() {
return new DSpace().getSingletonService(DSpaceHttpClientFactory.class);
}
/**
* Build an instance of {@link HttpClient} setting the proxy if configured.
*
* @return the client
*/
public CloseableHttpClient build() {
return build(HttpClientBuilder.create(), true);
}
/**
* return a Builder if an instance of {@link HttpClient} pre-setting the proxy if configured.
*
* @return the client
*/
public HttpClientBuilder builder(boolean setProxy) {
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
if (setProxy) {
clientBuilder.setRoutePlanner(proxyRoutePlanner);
}
getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
return clientBuilder;
}
/**
* Build an instance of {@link HttpClient} without setting the proxy, even if
* configured.
*
* @return the client
*/
public CloseableHttpClient buildWithoutProxy() {
return build(HttpClientBuilder.create(), false);
}
/**
* Build an instance of {@link HttpClient} setting the proxy if configured,
* disabling automatic retries and setting the maximum total connection.
*
* @param maxConnTotal the maximum total connection value
* @return the client
*/
public CloseableHttpClient buildWithoutAutomaticRetries(int maxConnTotal) {
HttpClientBuilder clientBuilder = HttpClientBuilder.create()
.disableAutomaticRetries()
.setMaxConnTotal(maxConnTotal);
return build(clientBuilder, true);
}
/**
* Build an instance of {@link HttpClient} setting the proxy if configured with
* the given request configuration.
* @param requestConfig the request configuration
* @return the client
*/
public CloseableHttpClient buildWithRequestConfig(RequestConfig requestConfig) {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig);
return build(httpClientBuilder, true);
}
private CloseableHttpClient build(HttpClientBuilder clientBuilder, boolean setProxy) {
if (setProxy) {
clientBuilder.setRoutePlanner(proxyRoutePlanner);
}
getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
return clientBuilder.build();
}
public ConfigurationService getConfigurationService() {
return configurationService;
}
public void setConfigurationService(ConfigurationService configurationService) {
this.configurationService = configurationService;
}
public List<HttpRequestInterceptor> getRequestInterceptors() {
return emptyIfNull(requestInterceptors);
}
public void setRequestInterceptors(List<HttpRequestInterceptor> requestInterceptors) {
this.requestInterceptors = requestInterceptors;
}
public List<HttpResponseInterceptor> getResponseInterceptors() {
return emptyIfNull(responseInterceptors);
}
public void setResponseInterceptors(List<HttpResponseInterceptor> responseInterceptors) {
this.responseInterceptors = responseInterceptors;
}
public DSpaceProxyRoutePlanner getProxyRoutePlanner() {
return proxyRoutePlanner;
}
public void setProxyRoutePlanner(DSpaceProxyRoutePlanner proxyRoutePlanner) {
this.proxyRoutePlanner = proxyRoutePlanner;
}
}

View File

@@ -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.client;
import java.util.Arrays;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.impl.conn.DefaultRoutePlanner;
import org.apache.http.protocol.HttpContext;
import org.dspace.services.ConfigurationService;
/**
* Extension of {@link DefaultRoutePlanner} that determine the proxy based on
* the configuration service, ignoring configured hosts.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class DSpaceProxyRoutePlanner extends DefaultRoutePlanner {
private ConfigurationService configurationService;
public DSpaceProxyRoutePlanner(ConfigurationService configurationService) {
super(null);
this.configurationService = configurationService;
}
@Override
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
if (isTargetHostConfiguredToBeIgnored(target)) {
return null;
}
String proxyHost = configurationService.getProperty("http.proxy.host");
String proxyPort = configurationService.getProperty("http.proxy.port");
if (StringUtils.isAnyBlank(proxyHost, proxyPort)) {
return null;
}
try {
return new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http");
} catch (NumberFormatException e) {
throw new RuntimeException("Invalid proxy port configuration: " + proxyPort);
}
}
private boolean isTargetHostConfiguredToBeIgnored(HttpHost target) {
String[] hostsToIgnore = configurationService.getArrayProperty("http.proxy.hosts-to-ignore");
if (ArrayUtils.isEmpty(hostsToIgnore)) {
return false;
}
return Arrays.stream(hostsToIgnore)
.anyMatch(host -> matchesHost(host, target.getHostName()));
}
private boolean matchesHost(String hostPattern, String hostName) {
if (hostName.equals(hostPattern)) {
return true;
} else if (hostPattern.startsWith("*")) {
return hostName.endsWith(StringUtils.removeStart(hostPattern, "*"));
} else if (hostPattern.endsWith("*")) {
return hostName.startsWith(StringUtils.removeEnd(hostPattern, "*"));
}
return false;
}
}

View File

@@ -18,9 +18,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.ldn.model.Notification; import org.dspace.app.ldn.model.Notification;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -34,21 +34,13 @@ public class SendLDNMessageAction implements LDNAction {
private static final Logger log = LogManager.getLogger(SendLDNMessageAction.class); private static final Logger log = LogManager.getLogger(SendLDNMessageAction.class);
private CloseableHttpClient client = null; private CloseableHttpClient client;
public SendLDNMessageAction() { public SendLDNMessageAction() {
HttpClientBuilder builder = HttpClientBuilder.create();
client = builder
.disableAutomaticRetries()
.setMaxConnTotal(5)
.build();
} }
public SendLDNMessageAction(CloseableHttpClient client) { public SendLDNMessageAction(CloseableHttpClient client) {
this(); this.client = client;
if (client != null) {
this.client = client;
}
} }
@Override @Override
@@ -66,9 +58,10 @@ public class SendLDNMessageAction implements LDNAction {
// NOTE: Github believes there is a "Potential server-side request forgery due to a user-provided value" // NOTE: Github believes there is a "Potential server-side request forgery due to a user-provided value"
// This is a false positive because the LDN Service URL is configured by the user from DSpace. // This is a false positive because the LDN Service URL is configured by the user from DSpace.
// See the frontend configuration at [dspace.ui.url]/admin/ldn/services // See the frontend configuration at [dspace.ui.url]/admin/ldn/services
try ( if (client == null) {
CloseableHttpResponse response = client.execute(httpPost); client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5);
) { }
try (CloseableHttpResponse response = client.execute(httpPost)) {
if (isSuccessful(response.getStatusLine().getStatusCode())) { if (isSuccessful(response.getStatusLine().getStatusCode())) {
result = LDNActionStatus.CONTINUE; result = LDNActionStatus.CONTINUE;
} else if (isRedirect(response.getStatusLine().getStatusCode())) { } else if (isRedirect(response.getStatusLine().getStatusCode())) {
@@ -77,6 +70,7 @@ public class SendLDNMessageAction implements LDNAction {
} catch (Exception e) { } catch (Exception e) {
log.error(e); log.error(e);
} }
client.close();
return result; return result;
} }
@@ -91,9 +85,9 @@ public class SendLDNMessageAction implements LDNAction {
statusCode == HttpStatus.SC_TEMPORARY_REDIRECT; statusCode == HttpStatus.SC_TEMPORARY_REDIRECT;
} }
private LDNActionStatus handleRedirect(CloseableHttpResponse oldresponse, private LDNActionStatus handleRedirect(CloseableHttpResponse oldResponse,
HttpPost request) throws HttpException { HttpPost request) throws HttpException {
Header[] urls = oldresponse.getHeaders(HttpHeaders.LOCATION); Header[] urls = oldResponse.getHeaders(HttpHeaders.LOCATION);
String url = urls.length > 0 && urls[0] != null ? urls[0].getValue() : null; String url = urls.length > 0 && urls[0] != null ? urls[0].getValue() : null;
if (url == null) { if (url == null) {
throw new HttpException("Error following redirect, unable to reach" throw new HttpException("Error following redirect, unable to reach"
@@ -102,17 +96,14 @@ public class SendLDNMessageAction implements LDNAction {
LDNActionStatus result = LDNActionStatus.ABORT; LDNActionStatus result = LDNActionStatus.ABORT;
try { try {
request.setURI(new URI(url)); request.setURI(new URI(url));
try ( try (CloseableHttpResponse response = client.execute(request)) {
CloseableHttpResponse response = client.execute(request);
) {
if (isSuccessful(response.getStatusLine().getStatusCode())) { if (isSuccessful(response.getStatusLine().getStatusCode())) {
return LDNActionStatus.CONTINUE; result = LDNActionStatus.CONTINUE;
} }
} }
} catch (Exception e) { } catch (Exception e) {
log.error("Error following redirect:", e); log.error("Error following redirect:", e);
} }
return result;
return LDNActionStatus.ABORT;
} }
} }

View File

@@ -141,7 +141,7 @@ public class TikaTextExtractionFilter
@Override @Override
public void characters(char[] ch, int start, int length) throws SAXException { public void characters(char[] ch, int start, int length) throws SAXException {
try { try {
writer.append(new String(ch), start, length); writer.append(new String(ch, start, length));
} catch (IOException e) { } catch (IOException e) {
String errorMsg = String.format("Could not append to temporary file at %s " + String errorMsg = String.format("Could not append to temporary file at %s " +
"when performing text extraction", "when performing text extraction",
@@ -159,7 +159,7 @@ public class TikaTextExtractionFilter
@Override @Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
try { try {
writer.append(new String(ch), start, length); writer.append(new String(ch, start, length));
} catch (IOException e) { } catch (IOException e) {
String errorMsg = String.format("Could not append to temporary file at %s " + String errorMsg = String.format("Could not append to temporary file at %s " +
"when performing text extraction", "when performing text extraction",

View File

@@ -17,15 +17,15 @@ import jakarta.annotation.PostConstruct;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.sherpa.v2.SHERPAPublisherResponse; import org.dspace.app.sherpa.v2.SHERPAPublisherResponse;
import org.dspace.app.sherpa.v2.SHERPAResponse; import org.dspace.app.sherpa.v2.SHERPAResponse;
import org.dspace.app.sherpa.v2.SHERPAUtils; import org.dspace.app.sherpa.v2.SHERPAUtils;
@@ -45,8 +45,6 @@ import org.springframework.cache.annotation.Cacheable;
*/ */
public class SHERPAService { public class SHERPAService {
private CloseableHttpClient client = null;
private int maxNumberOfTries; private int maxNumberOfTries;
private long sleepBetweenTimeouts; private long sleepBetweenTimeouts;
private int timeout = 5000; private int timeout = 5000;
@@ -59,19 +57,6 @@ public class SHERPAService {
@Autowired @Autowired
ConfigurationService configurationService; ConfigurationService configurationService;
/**
* Create a new HTTP builder with sensible defaults in constructor
*/
public SHERPAService() {
HttpClientBuilder builder = HttpClientBuilder.create();
// httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
// not to hammer the SHERPA service too much.
client = builder
.disableAutomaticRetries()
.setMaxConnTotal(5)
.build();
}
/** /**
* Complete initialization of the Bean. * Complete initialization of the Bean.
*/ */
@@ -132,46 +117,47 @@ public class SHERPAService {
timeout, timeout,
sleepBetweenTimeouts)); sleepBetweenTimeouts));
try { try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
Thread.sleep(sleepBetweenTimeouts); Thread.sleep(sleepBetweenTimeouts);
// Construct a default HTTP method (first result) // Construct a default HTTP method (first result)
method = constructHttpGet(type, field, predicate, value, start, limit); method = constructHttpGet(type, field, predicate, value, start, limit);
// Execute the method // Execute the method
HttpResponse response = client.execute(method); try (CloseableHttpResponse response = client.execute(method)) {
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
log.debug(response.getStatusLine().getStatusCode() + ": " log.debug(response.getStatusLine().getStatusCode() + ": "
+ response.getStatusLine().getReasonPhrase()); + response.getStatusLine().getReasonPhrase());
if (statusCode != HttpStatus.SC_OK) { if (statusCode != HttpStatus.SC_OK) {
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: " sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: "
+ statusCode); + statusCode);
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
log.error("Error from SHERPA HTTP request: " + errorBody); log.error("Error from SHERPA HTTP request: " + errorBody);
} }
HttpEntity responseBody = response.getEntity(); HttpEntity responseBody = response.getEntity();
// If the response body is valid, pass to SHERPAResponse for parsing as JSON // If the response body is valid, pass to SHERPAResponse for parsing as JSON
if (null != responseBody) { if (null != responseBody) {
log.debug("Non-null SHERPA response received for query of " + value); log.debug("Non-null SHERPA response received for query of " + value);
InputStream content = null; InputStream content = null;
try { try {
content = responseBody.getContent(); content = responseBody.getContent();
sherpaResponse = sherpaResponse =
new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON); new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON);
} catch (IOException e) { } catch (IOException e) {
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e); log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
} finally { } finally {
if (content != null) { if (content != null) {
content.close(); content.close();
} }
}
} else {
log.debug("Empty SHERPA response body for query on " + value);
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
} }
} else {
log.debug("Empty SHERPA response body for query on " + value);
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
} }
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage(); String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
@@ -235,45 +221,46 @@ public class SHERPAService {
timeout, timeout,
sleepBetweenTimeouts)); sleepBetweenTimeouts));
try { try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
Thread.sleep(sleepBetweenTimeouts); Thread.sleep(sleepBetweenTimeouts);
// Construct a default HTTP method (first result) // Construct a default HTTP method (first result)
method = constructHttpGet(type, field, predicate, value, start, limit); method = constructHttpGet(type, field, predicate, value, start, limit);
// Execute the method // Execute the method
HttpResponse response = client.execute(method); try (CloseableHttpResponse response = client.execute(method)) {
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
log.debug(response.getStatusLine().getStatusCode() + ": " log.debug(response.getStatusLine().getStatusCode() + ": "
+ response.getStatusLine().getReasonPhrase()); + response.getStatusLine().getReasonPhrase());
if (statusCode != HttpStatus.SC_OK) { if (statusCode != HttpStatus.SC_OK) {
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: " sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
+ statusCode); + statusCode);
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
log.error("Error from SHERPA HTTP request: " + errorBody); log.error("Error from SHERPA HTTP request: " + errorBody);
} }
HttpEntity responseBody = response.getEntity(); HttpEntity responseBody = response.getEntity();
// If the response body is valid, pass to SHERPAResponse for parsing as JSON // If the response body is valid, pass to SHERPAResponse for parsing as JSON
if (null != responseBody) { if (null != responseBody) {
log.debug("Non-null SHERPA response received for query of " + value); log.debug("Non-null SHERPA response received for query of " + value);
InputStream content = null; InputStream content = null;
try { try {
content = responseBody.getContent(); content = responseBody.getContent();
sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON); sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON);
} catch (IOException e) { } catch (IOException e) {
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e); log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
} finally { } finally {
if (content != null) { if (content != null) {
content.close(); content.close();
} }
}
} else {
log.debug("Empty SHERPA response body for query on " + value);
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
} }
} else {
log.debug("Empty SHERPA response body for query on " + value);
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
} }
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage(); String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
@@ -283,7 +270,7 @@ public class SHERPAService {
String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(); String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage();
log.error(errorMessage, e); log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage); sherpaResponse = new SHERPAResponse(errorMessage);
} catch (InterruptedException e) { } catch (InterruptedException e) {
String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage(); String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage();
log.error(errorMessage, e); log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage); sherpaResponse = new SHERPAResponse(errorMessage);

View File

@@ -1231,8 +1231,8 @@ public class LogAnalyser {
} }
accessionedQuery.append("]"); accessionedQuery.append("]");
discoverQuery.addFilterQueries(accessionedQuery.toString()); discoverQuery.addFilterQueries(accessionedQuery.toString());
discoverQuery.addFilterQueries("withdrawn: false"); discoverQuery.addFilterQueries("withdrawn:false");
discoverQuery.addFilterQueries("archived: true"); discoverQuery.addFilterQueries("archived:true");
return (int) SearchUtils.getSearchService().search(context, discoverQuery).getTotalSearchResults(); return (int) SearchUtils.getSearchService().search(context, discoverQuery).getTotalSearchResults();
} }

View File

@@ -119,8 +119,11 @@ public class PublicationLoaderRunnable
DiscoverResultItemIterator researchers = findResearchers(); DiscoverResultItemIterator researchers = findResearchers();
while (researchers.hasNext()) { while (researchers.hasNext()) {
Item researcher = researchers.next(); Item researcher = researchers.next();
researcher = context.reloadEntity(researcher);
publicationLoader.importRecords(context, researcher); publicationLoader.importRecords(context, researcher);
setLastImportMetadataValue(researcher); setLastImportMetadataValue(researcher);
context.commit();
context.uncacheEntity(researcher);
} }
} finally { } finally {
context.restoreAuthSystemState(); context.restoreAuthSystemState();

View File

@@ -64,20 +64,36 @@ public class InitializeEntities {
*/ */
public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException { public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException {
InitializeEntities initializeEntities = new InitializeEntities(); InitializeEntities initializeEntities = new InitializeEntities();
// Set up command-line options and parse arguments
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new DefaultParser();
Options options = createCommandLineOptions(); Options options = createCommandLineOptions();
CommandLine line = parser.parse(options,argv); CommandLine line = parser.parse(options,argv);
String fileLocation = getFileLocationFromCommandLine(line); // First of all, check if the help option was entered or a required argument is missing
checkHelpEntered(options, line); checkHelpEntered(options, line);
// Get the file location from the command line
String fileLocation = getFileLocationFromCommandLine(line);
// Run the script
initializeEntities.run(fileLocation); initializeEntities.run(fileLocation);
} }
/**
* Check if the help option was entered or a required argument is missing. If so, print help and exit.
* @param options the defined command-line options
* @param line the parsed command-line arguments
*/
private static void checkHelpEntered(Options options, CommandLine line) { private static void checkHelpEntered(Options options, CommandLine line) {
if (line.hasOption("h")) { if (line.hasOption("h") || !line.hasOption("f")) {
HelpFormatter formatter = new HelpFormatter(); HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("Initialize Entities", options); formatter.printHelp("Initialize Entities", options);
System.exit(0); System.exit(0);
} }
} }
/**
* Get the file path from the command-line argument. Exits with exit code 1 if no file argument was entered.
* @param line the parsed command-line arguments
* @return the file path
*/
private static String getFileLocationFromCommandLine(CommandLine line) { private static String getFileLocationFromCommandLine(CommandLine line) {
String query = line.getOptionValue("f"); String query = line.getOptionValue("f");
if (StringUtils.isEmpty(query)) { if (StringUtils.isEmpty(query)) {
@@ -88,13 +104,25 @@ public class InitializeEntities {
return query; return query;
} }
/**
* Create the command-line options
* @return the command-line options
*/
protected static Options createCommandLineOptions() { protected static Options createCommandLineOptions() {
Options options = new Options(); Options options = new Options();
options.addOption("f", "file", true, "the location for the file containing the xml data"); options.addOption("f", "file", true, "the path to the file containing the " +
"relationship definitions (e.g. ${dspace.dir}/config/entities/relationship-types.xml)");
options.addOption("h", "help", false, "print this message");
return options; return options;
} }
/**
* Run the script for the given file location
* @param fileLocation the file location
* @throws SQLException If something goes wrong initializing context or inserting relationship types
* @throws AuthorizeException If the script user fails to authorize while inserting relationship types
*/
private void run(String fileLocation) throws SQLException, AuthorizeException { private void run(String fileLocation) throws SQLException, AuthorizeException {
Context context = new Context(); Context context = new Context();
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
@@ -102,6 +130,12 @@ public class InitializeEntities {
context.complete(); context.complete();
} }
/**
* Parse the XML file at fileLocation to create relationship types in the database
* @param context DSpace context
* @param fileLocation the full or relative file path to the relationship types XML
* @throws AuthorizeException If the script user fails to authorize while inserting relationship types
*/
private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException { private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException {
try { try {
File fXmlFile = new File(fileLocation); File fXmlFile = new File(fileLocation);
@@ -158,15 +192,15 @@ public class InitializeEntities {
for (int j = 0; j < leftCardinalityList.getLength(); j++) { for (int j = 0; j < leftCardinalityList.getLength(); j++) {
Node node = leftCardinalityList.item(j); Node node = leftCardinalityList.item(j);
leftCardinalityMin = getString(leftCardinalityMin,(Element) node, "min"); leftCardinalityMin = getCardinalityMinString(leftCardinalityMin,(Element) node, "min");
leftCardinalityMax = getString(leftCardinalityMax,(Element) node, "max"); leftCardinalityMax = getCardinalityMinString(leftCardinalityMax,(Element) node, "max");
} }
for (int j = 0; j < rightCardinalityList.getLength(); j++) { for (int j = 0; j < rightCardinalityList.getLength(); j++) {
Node node = rightCardinalityList.item(j); Node node = rightCardinalityList.item(j);
rightCardinalityMin = getString(rightCardinalityMin,(Element) node, "min"); rightCardinalityMin = getCardinalityMinString(rightCardinalityMin,(Element) node, "min");
rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max"); rightCardinalityMax = getCardinalityMinString(rightCardinalityMax,(Element) node, "max");
} }
populateRelationshipType(context, leftType, rightType, leftwardType, rightwardType, populateRelationshipType(context, leftType, rightType, leftwardType, rightwardType,
@@ -182,13 +216,39 @@ public class InitializeEntities {
} }
} }
private String getString(String leftCardinalityMin,Element node, String minOrMax) { /**
* Extract the min or max value for the left or right cardinality from the node text content
* @param leftCardinalityMin current left cardinality min
* @param node node to extract the min or max value from
* @param minOrMax element tag name to parse
* @return final left cardinality min
*/
private String getCardinalityMinString(String leftCardinalityMin, Element node, String minOrMax) {
if (node.getElementsByTagName(minOrMax).getLength() > 0) { if (node.getElementsByTagName(minOrMax).getLength() > 0) {
leftCardinalityMin = node.getElementsByTagName(minOrMax).item(0).getTextContent(); leftCardinalityMin = node.getElementsByTagName(minOrMax).item(0).getTextContent();
} }
return leftCardinalityMin; return leftCardinalityMin;
} }
/**
* Populate the relationship type based on values parsed from the XML relationship types configuration
*
* @param context DSpace context
* @param leftType left relationship type (e.g. "Publication").
* @param rightType right relationship type (e.g. "Journal").
* @param leftwardType leftward relationship type (e.g. "isAuthorOfPublication").
* @param rightwardType rightward relationship type (e.g. "isPublicationOfAuthor").
* @param leftCardinalityMin left cardinality min
* @param leftCardinalityMax left cardinality max
* @param rightCardinalityMin right cardinality min
* @param rightCardinalityMax right cardinality max
* @param copyToLeft copy metadata values to left if right side is deleted
* @param copyToRight copy metadata values to right if left side is deleted
* @param tilted set a tilted relationship side (left or right) if there are many relationships going one way
* to help performance (e.g. authors with 1000s of publications)
* @throws SQLException if database error occurs while saving the relationship type
* @throws AuthorizeException if authorization error occurs while saving the relationship type
*/
private void populateRelationshipType(Context context, String leftType, String rightType, String leftwardType, private void populateRelationshipType(Context context, String leftType, String rightType, String leftwardType,
String rightwardType, String leftCardinalityMin, String leftCardinalityMax, String rightwardType, String leftCardinalityMin, String leftCardinalityMax,
String rightCardinalityMin, String rightCardinalityMax, String rightCardinalityMin, String rightCardinalityMax,

View File

@@ -100,6 +100,14 @@ public class OpenSearchServiceImpl implements OpenSearchService {
configurationService.getProperty("websvc.opensearch.uicontext"); configurationService.getProperty("websvc.opensearch.uicontext");
} }
/**
* Get base search UI URL (websvc.opensearch.max_num_of_items_per_request)
*/
public int getMaxNumOfItemsPerRequest() {
return configurationService.getIntProperty(
"websvc.opensearch.max_num_of_items_per_request", 100);
}
@Override @Override
public String getContentType(String format) { public String getContentType(String format) {
return "html".equals(format) ? "text/html" : return "html".equals(format) ? "text/html" :

View File

@@ -257,8 +257,14 @@ public class SyndicationFeed {
String pubDateString = getOneDC(item, dateField); String pubDateString = getOneDC(item, dateField);
if (pubDateString != null) { if (pubDateString != null) {
ZonedDateTime pubDate = new DCDate(pubDateString).toDate(); ZonedDateTime pubDate = new DCDate(pubDateString).toDate();
entry.setPublishedDate(java.util.Date.from(pubDate.toInstant())); // If date string could not be parsed as a date, then pubDate will be null
hasDate = true; if (pubDate != null) {
entry.setPublishedDate(java.util.Date.from(pubDate.toInstant()));
hasDate = true;
} else {
log.warn("Date field {} for item {} could not be parsed: {}", dateField, item.getID(),
pubDateString);
}
} }
// date of last change to Item // date of last change to Item
entry.setUpdatedDate(java.util.Date.from(item.getLastModified())); entry.setUpdatedDate(java.util.Date.from(item.getLastModified()));

View File

@@ -13,12 +13,12 @@ import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.util.dao.WebAppDAO; import org.dspace.app.util.dao.WebAppDAO;
import org.dspace.app.util.service.WebAppService; import org.dspace.app.util.service.WebAppService;
import org.dspace.core.Context; import org.dspace.core.Context;
@@ -77,8 +77,8 @@ public class WebAppServiceImpl implements WebAppService {
for (WebApp app : webApps) { for (WebApp app : webApps) {
method = new HttpHead(app.getUrl()); method = new HttpHead(app.getUrl());
int status; int status;
try (CloseableHttpClient client = HttpClientBuilder.create().build()) { try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpResponse response = client.execute(method); CloseableHttpResponse response = client.execute(method);
status = response.getStatusLine().getStatusCode(); status = response.getStatusLine().getStatusCode();
} }
if (status != HttpStatus.SC_OK) { if (status != HttpStatus.SC_OK) {

View File

@@ -112,4 +112,10 @@ public interface OpenSearchService {
public DSpaceObject resolveScope(Context context, String scope) throws SQLException; public DSpaceObject resolveScope(Context context, String scope) throws SQLException;
/**
* Retrieves the maximum number of items that can be included in a single opensearch request.
*
* @return the maximum number of items allowed per request
*/
int getMaxNumOfItemsPerRequest();
} }

View File

@@ -22,12 +22,13 @@ import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authenticate.oidc.OidcClient; import org.dspace.authenticate.oidc.OidcClient;
import org.dspace.authenticate.oidc.OidcClientException; import org.dspace.authenticate.oidc.OidcClientException;
import org.dspace.authenticate.oidc.model.OidcTokenResponseDTO; import org.dspace.authenticate.oidc.model.OidcTokenResponseDTO;
@@ -83,21 +84,17 @@ public class OidcClientImpl implements OidcClient {
} }
private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) { private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) {
try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpClient client = HttpClientBuilder.create().build(); return executeAndReturns(() -> {
CloseableHttpResponse response = client.execute(httpUriRequest);
return executeAndReturns(() -> { if (isNotSuccessfull(response)) {
throw new OidcClientException(getStatusCode(response), formatErrorMessage(response));
HttpResponse response = client.execute(httpUriRequest); }
return objectMapper.readValue(getContent(response), clazz);
if (isNotSuccessfull(response)) { });
throw new OidcClientException(getStatusCode(response), formatErrorMessage(response)); } catch (IOException e) {
} throw new RuntimeException(e);
}
return objectMapper.readValue(getContent(response), clazz);
});
} }
private <T> T executeAndReturns(ThrowingSupplier<T, Exception> supplier) { private <T> T executeAndReturns(ThrowingSupplier<T, Exception> supplier) {

View File

@@ -7,27 +7,22 @@
*/ */
package org.dspace.authority.orcid; package org.dspace.authority.orcid;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authority.AuthorityValue; import org.dspace.authority.AuthorityValue;
import org.dspace.authority.SolrAuthorityInterface; import org.dspace.authority.SolrAuthorityInterface;
import org.dspace.external.OrcidRestConnector; import org.dspace.external.OrcidRestConnector;
import org.dspace.external.provider.orcid.xml.XMLtoBio; import org.dspace.external.provider.orcid.xml.XMLtoBio;
import org.json.JSONObject; import org.dspace.orcid.model.factory.OrcidFactoryUtils;
import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier; import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier;
import org.orcid.jaxb.model.v3.release.record.Person; import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.v3.release.search.Result; import org.orcid.jaxb.model.v3.release.search.Result;
@@ -50,6 +45,11 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
private String accessToken; private String accessToken;
/**
* Maximum retries to allow for the access token retrieval
*/
private int maxClientRetries = 3;
public void setOAUTHUrl(String oAUTHUrl) { public void setOAUTHUrl(String oAUTHUrl) {
OAUTHUrl = oAUTHUrl; OAUTHUrl = oAUTHUrl;
} }
@@ -62,46 +62,32 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
} }
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
/** /**
* Initialize the accessToken that is required for all subsequent calls to ORCID * Initialize the accessToken that is required for all subsequent calls to ORCID
*/ */
public void init() { public void init() {
if (StringUtils.isBlank(accessToken) // Initialize access token at spring instantiation. If it fails, the access token will be null rather
&& StringUtils.isNotBlank(clientSecret) // than causing a fatal Spring startup error
&& StringUtils.isNotBlank(clientId) initializeAccessToken();
&& StringUtils.isNotBlank(OAUTHUrl)) { }
String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials";
try {
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build(); public void initializeAccessToken() {
HttpResponse getResponse = httpClient.execute(httpPost); // If we have reaches max retries or the access token is already set, return immediately
if (maxClientRetries <= 0 || org.apache.commons.lang3.StringUtils.isNotBlank(accessToken)) {
JSONObject responseObject = null; return;
try (InputStream is = getResponse.getEntity().getContent(); }
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { try {
String inputStr; accessToken = OrcidFactoryUtils.retrieveAccessToken(clientId, clientSecret, OAUTHUrl).orElse(null);
while ((inputStr = streamReader.readLine()) != null && responseObject == null) { } catch (IOException e) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) { log.error("Error retrieving ORCID access token, {} retries left", --maxClientRetries);
try {
responseObject = new JSONObject(inputStr);
} catch (Exception e) {
//Not as valid as I'd hoped, move along
responseObject = null;
}
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
accessToken = (String) responseObject.get("access_token");
}
} catch (Exception e) {
throw new RuntimeException("Error during initialization of the Orcid connector", e);
}
} }
} }
@@ -116,7 +102,7 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
*/ */
@Override @Override
public List<AuthorityValue> queryAuthorities(String text, int max) { public List<AuthorityValue> queryAuthorities(String text, int max) {
init(); initializeAccessToken();
List<Person> bios = queryBio(text, max); List<Person> bios = queryBio(text, max);
List<AuthorityValue> result = new ArrayList<>(); List<AuthorityValue> result = new ArrayList<>();
for (Person person : bios) { for (Person person : bios) {
@@ -135,7 +121,7 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
*/ */
@Override @Override
public AuthorityValue queryAuthorityID(String id) { public AuthorityValue queryAuthorityID(String id) {
init(); initializeAccessToken();
Person person = getBio(id); Person person = getBio(id);
AuthorityValue valueFromPerson = Orcidv3AuthorityValue.create(person); AuthorityValue valueFromPerson = Orcidv3AuthorityValue.create(person);
return valueFromPerson; return valueFromPerson;
@@ -151,11 +137,14 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
if (!isValid(id)) { if (!isValid(id)) {
return null; return null;
} }
init(); if (orcidRestConnector == null) {
log.error("ORCID REST connector is null, returning null Person");
return null;
}
initializeAccessToken();
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken); InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
XMLtoBio converter = new XMLtoBio(); XMLtoBio converter = new XMLtoBio();
Person person = converter.convertSinglePerson(bioDocument); return converter.convertSinglePerson(bioDocument);
return person;
} }
@@ -167,10 +156,16 @@ public class Orcidv3SolrAuthorityImpl implements SolrAuthorityInterface {
* @return List<Person> * @return List<Person>
*/ */
public List<Person> queryBio(String text, int start, int rows) { public List<Person> queryBio(String text, int start, int rows) {
init();
if (rows > 100) { if (rows > 100) {
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100."); throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
} }
// Check REST connector is initialized
if (orcidRestConnector == null) {
log.error("ORCID REST connector is not initialized, returning empty list");
return Collections.emptyList();
}
// Check / init access token
initializeAccessToken();
String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows; String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken); log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);

View File

@@ -21,7 +21,7 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import jakarta.persistence.SequenceGenerator; import jakarta.persistence.SequenceGenerator;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.apache.solr.common.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.HibernateProxyHelper; import org.dspace.core.HibernateProxyHelper;

View File

@@ -19,6 +19,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authorize.dao.ResourcePolicyDAO; import org.dspace.authorize.dao.ResourcePolicyDAO;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService; import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
@@ -51,6 +52,9 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService {
@Autowired @Autowired
private GroupService groupService; private GroupService groupService;
@Autowired
private AuthorizeService authorizeService;
protected ResourcePolicyServiceImpl() { protected ResourcePolicyServiceImpl() {
} }
@@ -422,6 +426,6 @@ public class ResourcePolicyServiceImpl implements ResourcePolicyService {
} else if (group != null && groupService.isMember(context, eperson, group)) { } else if (group != null && groupService.isMember(context, eperson, group)) {
isMy = true; isMy = true;
} }
return isMy; return isMy || authorizeService.isAdmin(context, eperson, resourcePolicy.getdSpaceObject());
} }
} }

View File

@@ -23,7 +23,6 @@ import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.discovery.DiscoverFacetField;
import org.dspace.discovery.DiscoverQuery; import org.dspace.discovery.DiscoverQuery;
import org.dspace.discovery.DiscoverQuery.SORT_ORDER; import org.dspace.discovery.DiscoverQuery.SORT_ORDER;
import org.dspace.discovery.DiscoverResult; import org.dspace.discovery.DiscoverResult;
@@ -34,7 +33,6 @@ import org.dspace.discovery.SearchService;
import org.dspace.discovery.SearchServiceException; import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.SearchUtils; import org.dspace.discovery.SearchUtils;
import org.dspace.discovery.configuration.DiscoveryConfiguration; import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.indexobject.IndexableItem; import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
@@ -181,32 +179,28 @@ public class SolrBrowseDAO implements BrowseDAO {
addLocationScopeFilter(query); addLocationScopeFilter(query);
addDefaultFilterQueries(query); addDefaultFilterQueries(query);
if (distinct) { if (distinct) {
DiscoverFacetField dff; // We use a json.facet query for metadata browsing because it allows us to limit the results
// while obtaining the total number of facet values with numBuckets:true and sort in reverse order
// To get the number of distinct values we use the next "json.facet" query param // Example of json.facet query:
// {"entries_count": {"type":"terms","field": "<fieldName>_filter", "limit":0, "numBuckets":true}}" // {"<fieldName>": {"type":"terms","field": "<fieldName>_filter", "limit":0, "offset":0,
// "sort":"index desc", "numBuckets":true, "prefix":"<startsWith>"}}
ObjectNode jsonFacet = JsonNodeFactory.instance.objectNode(); ObjectNode jsonFacet = JsonNodeFactory.instance.objectNode();
ObjectNode entriesCount = JsonNodeFactory.instance.objectNode(); ObjectNode entriesFacet = JsonNodeFactory.instance.objectNode();
entriesCount.put("type", "terms"); entriesFacet.put("type", "terms");
entriesCount.put("field", facetField + "_filter"); entriesFacet.put("field", facetField + "_filter");
entriesCount.put("limit", 0); entriesFacet.put("limit", limit);
entriesCount.put("numBuckets", true); entriesFacet.put("offset", offset);
jsonFacet.set("entries_count", entriesCount); entriesFacet.put("numBuckets", true);
if (ascending) {
if (StringUtils.isNotBlank(startsWith)) { entriesFacet.put("sort", "index");
dff = new DiscoverFacetField(facetField,
DiscoveryConfigurationParameters.TYPE_TEXT, limit,
DiscoveryConfigurationParameters.SORT.VALUE, startsWith, offset);
// Add the prefix to the json facet query
entriesCount.put("prefix", startsWith);
} else { } else {
dff = new DiscoverFacetField(facetField, entriesFacet.put("sort", "index desc");
DiscoveryConfigurationParameters.TYPE_TEXT, limit,
DiscoveryConfigurationParameters.SORT.VALUE, offset);
} }
query.addFacetField(dff); if (StringUtils.isNotBlank(startsWith)) {
query.setFacetMinCount(1); // Add the prefix to the json facet query
entriesFacet.put("prefix", startsWith);
}
jsonFacet.set(facetField, entriesFacet);
query.setMaxResults(0); query.setMaxResults(0);
query.addProperty("json.facet", jsonFacet.toString()); query.addProperty("json.facet", jsonFacet.toString());
} else { } else {
@@ -282,26 +276,15 @@ public class SolrBrowseDAO implements BrowseDAO {
DiscoverResult resp = getSolrResponse(); DiscoverResult resp = getSolrResponse();
List<FacetResult> facet = resp.getFacetResult(facetField); List<FacetResult> facet = resp.getFacetResult(facetField);
int count = doCountQuery(); int count = doCountQuery();
int start = 0;
int max = facet.size(); int max = facet.size();
List<String[]> result = new ArrayList<>(); List<String[]> result = new ArrayList<>();
if (ascending) {
for (int i = start; i < (start + max) && i < count; i++) { for (int i = 0; i < max && i < count; i++) {
FacetResult c = facet.get(i); FacetResult c = facet.get(i);
String freq = showFrequencies ? String.valueOf(c.getCount()) String freq = showFrequencies ? String.valueOf(c.getCount())
: ""; : "";
result.add(new String[] {c.getDisplayedValue(), result.add(new String[] {c.getDisplayedValue(),
c.getAuthorityKey(), freq}); c.getAuthorityKey(), freq});
}
} else {
for (int i = count - start - 1; i >= count - (start + max)
&& i >= 0; i--) {
FacetResult c = facet.get(i);
String freq = showFrequencies ? String.valueOf(c.getCount())
: "";
result.add(new String[] {c.getDisplayedValue(),
c.getAuthorityKey(), freq});
}
} }
return result; return result;
@@ -362,9 +345,9 @@ public class SolrBrowseDAO implements BrowseDAO {
} }
if (isAscending) { if (isAscending) {
query.setQuery("bi_" + column + "_sort" + ": [* TO \"" + value + "\"}"); query.setQuery("bi_" + column + "_sort" + ":[* TO \"" + value + "\"}");
} else { } else {
query.setQuery("bi_" + column + "_sort" + ": {\"" + value + "\" TO *]"); query.setQuery("bi_" + column + "_sort" + ":{\"" + value + "\" TO *]");
query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)"); query.addFilterQueries("-(bi_" + column + "_sort" + ":" + value + "*)");
} }
DiscoverResult resp = null; DiscoverResult resp = null;

View File

@@ -1021,7 +1021,8 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
if (StringUtils.isNotBlank(q)) { if (StringUtils.isNotBlank(q)) {
StringBuilder buildQuery = new StringBuilder(); StringBuilder buildQuery = new StringBuilder();
String escapedQuery = ClientUtils.escapeQueryChars(q); String escapedQuery = ClientUtils.escapeQueryChars(q);
buildQuery.append("(").append(escapedQuery).append(" OR ").append(escapedQuery).append("*").append(")"); buildQuery.append("(").append(escapedQuery).append(" OR dc.title_sort:*")
.append(escapedQuery).append("*").append(")");
discoverQuery.setQuery(buildQuery.toString()); discoverQuery.setQuery(buildQuery.toString());
} }
DiscoverResult resp = searchService.search(context, discoverQuery); DiscoverResult resp = searchService.search(context, discoverQuery);

View File

@@ -187,11 +187,11 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
String authority) { String authority) {
List<MetadataValue> metadata = getMetadata(dso, schema, element, qualifier, lang); List<MetadataValue> metadata = getMetadata(dso, schema, element, qualifier, lang);
List<MetadataValue> result = new ArrayList<>(metadata); List<MetadataValue> result = new ArrayList<>(metadata);
if (!authority.equals(Item.ANY)) { if (!Item.ANY.equals(authority)) {
Iterator<MetadataValue> iterator = result.iterator(); Iterator<MetadataValue> iterator = result.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
MetadataValue metadataValue = iterator.next(); MetadataValue metadataValue = iterator.next();
if (!authority.equals(metadataValue.getAuthority())) { if (!StringUtils.equals(authority, metadataValue.getAuthority())) {
iterator.remove(); iterator.remove();
} }
} }
@@ -509,7 +509,7 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
MetadataField metadataField = metadataValue.getMetadataField(); MetadataField metadataField = metadataValue.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema(); MetadataSchema metadataSchema = metadataField.getMetadataSchema();
// We will attempt to disprove a match - if we can't we have a match // We will attempt to disprove a match - if we can't we have a match
if (!element.equals(Item.ANY) && !element.equals(metadataField.getElement())) { if (!Item.ANY.equals(element) && !StringUtils.equals(element, metadataField.getElement())) {
// Elements do not match, no wildcard // Elements do not match, no wildcard
return false; return false;
} }
@@ -520,9 +520,9 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
// Value is qualified, so no match // Value is qualified, so no match
return false; return false;
} }
} else if (!qualifier.equals(Item.ANY)) { } else if (!Item.ANY.equals(qualifier)) {
// Not a wildcard, so qualifier must match exactly // Not a wildcard, so qualifier must match exactly
if (!qualifier.equals(metadataField.getQualifier())) { if (!StringUtils.equals(qualifier, metadataField.getQualifier())) {
return false; return false;
} }
} }
@@ -533,15 +533,15 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
// Value is qualified, so no match // Value is qualified, so no match
return false; return false;
} }
} else if (!language.equals(Item.ANY)) { } else if (!Item.ANY.equals(language)) {
// Not a wildcard, so language must match exactly // Not a wildcard, so language must match exactly
if (!language.equals(metadataValue.getLanguage())) { if (!StringUtils.equals(language, metadataValue.getLanguage())) {
return false; return false;
} }
} }
if (!schema.equals(Item.ANY)) { if (!Item.ANY.equals(schema)) {
if (metadataSchema != null && !metadataSchema.getName().equals(schema)) { if (!StringUtils.equals(schema, metadataSchema.getName())) {
// The namespace doesn't match // The namespace doesn't match
return false; return false;
} }

View File

@@ -23,6 +23,7 @@ import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler; import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -36,6 +37,11 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
@Autowired @Autowired
private DSpaceObjectUtils dSpaceObjectUtils; private DSpaceObjectUtils dSpaceObjectUtils;
@Autowired
private ConfigurationService configurationService;
private int csxExportLimit = -1;
@Override @Override
public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata, String identifier, public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata, String identifier,
DSpaceRunnableHandler handler) throws Exception { DSpaceRunnableHandler handler) throws Exception {
@@ -43,7 +49,7 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
if (exportAllItems) { if (exportAllItems) {
handler.logInfo("Exporting whole repository WARNING: May take some time!"); handler.logInfo("Exporting whole repository WARNING: May take some time!");
toExport = itemService.findAll(context); toExport = itemService.findAll(context, getCsvExportLimit(), 0);
} else { } else {
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService() DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService()
.resolveToObject(context, identifier); .resolveToObject(context, identifier);
@@ -63,7 +69,7 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
} else if (dso.getType() == Constants.COLLECTION) { } else if (dso.getType() == Constants.COLLECTION) {
handler.logInfo("Exporting collection '" + dso.getName() + "' (" + identifier + ")"); handler.logInfo("Exporting collection '" + dso.getName() + "' (" + identifier + ")");
Collection collection = (Collection) dso; Collection collection = (Collection) dso;
toExport = itemService.findByCollection(context, collection); toExport = itemService.findByCollection(context, collection, getCsvExportLimit(), 0);
} else if (dso.getType() == Constants.COMMUNITY) { } else if (dso.getType() == Constants.COMMUNITY) {
handler.logInfo("Exporting community '" + dso.getName() + "' (" + identifier + ")"); handler.logInfo("Exporting community '" + dso.getName() + "' (" + identifier + ")");
toExport = buildFromCommunity(context, (Community) dso); toExport = buildFromCommunity(context, (Community) dso);
@@ -74,18 +80,21 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
} }
} }
DSpaceCSV csv = this.export(context, toExport, exportAllMetadata); DSpaceCSV csv = this.export(context, toExport, exportAllMetadata, handler);
return csv; return csv;
} }
@Override @Override
public DSpaceCSV export(Context context, Iterator<Item> toExport, boolean exportAll) throws Exception { public DSpaceCSV export(Context context, Iterator<Item> toExport,
boolean exportAll, DSpaceRunnableHandler handler) throws Exception {
Context.Mode originalMode = context.getCurrentMode(); Context.Mode originalMode = context.getCurrentMode();
context.setMode(Context.Mode.READ_ONLY); context.setMode(Context.Mode.READ_ONLY);
// Process each item // Process each item until we reach the limit
int itemExportLimit = getCsvExportLimit();
DSpaceCSV csv = new DSpaceCSV(exportAll); DSpaceCSV csv = new DSpaceCSV(exportAll);
while (toExport.hasNext()) {
for (int itemsAdded = 0; toExport.hasNext() && itemsAdded < itemExportLimit; itemsAdded++) {
Item item = toExport.next(); Item item = toExport.next();
csv.addItem(item); csv.addItem(item);
context.uncacheEntity(item); context.uncacheEntity(item);
@@ -97,8 +106,9 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
} }
@Override @Override
public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception { public DSpaceCSV export(Context context, Community community,
return export(context, buildFromCommunity(context, community), exportAll); boolean exportAll, DSpaceRunnableHandler handler) throws Exception {
return export(context, buildFromCommunity(context, community), exportAll, handler);
} }
/** /**
@@ -117,21 +127,30 @@ public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExpo
// Add all the collections // Add all the collections
List<Collection> collections = community.getCollections(); List<Collection> collections = community.getCollections();
for (Collection collection : collections) { for (Collection collection : collections) {
Iterator<Item> items = itemService.findByCollection(context, collection); // Never obtain more items than the configured limit
while (items.hasNext()) { Iterator<Item> items = itemService.findByCollection(context, collection, getCsvExportLimit(), 0);
while (result.size() < getCsvExportLimit() && items.hasNext()) {
result.add(items.next()); result.add(items.next());
} }
} }
// Add all the sub-communities // Add all the sub-communities
List<Community> communities = community.getSubcommunities(); List<Community> communities = community.getSubcommunities();
for (Community subCommunity : communities) { for (Community subCommunity : communities) {
Iterator<Item> items = buildFromCommunity(context, subCommunity); Iterator<Item> items = buildFromCommunity(context, subCommunity);
while (items.hasNext()) { while (result.size() < getCsvExportLimit() && items.hasNext()) {
result.add(items.next()); result.add(items.next());
} }
} }
return result.iterator(); return result.iterator();
} }
@Override
public int getCsvExportLimit() {
if (csxExportLimit == -1) {
csxExportLimit = configurationService.getIntProperty("bulkedit.export.max.items", 500);
}
return csxExportLimit;
}
} }

View File

@@ -571,13 +571,17 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
Set<String> metadataFields = new HashSet<>(); Set<String> metadataFields = new HashSet<>();
Map<String, List<String>> formsToFields = this.authoritiesFormDefinitions.get(nameVocab); Map<String, List<String>> formsToFields = this.authoritiesFormDefinitions.get(nameVocab);
// Vocabulary is not associated with any form definition, meaning it won't be a browse index
if (formsToFields == null) {
return null;
}
for (Map.Entry<String, List<String>> formToField : formsToFields.entrySet()) { for (Map.Entry<String, List<String>> formToField : formsToFields.entrySet()) {
metadataFields.addAll(formToField.getValue().stream().map(value -> metadataFields.addAll(formToField.getValue().stream().map(value ->
StringUtils.replace(value, "_", ".")) StringUtils.replace(value, "_", "."))
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
DiscoverySearchFilterFacet matchingFacet = null; DiscoverySearchFilterFacet matchingFacet = null;
for (DiscoverySearchFilterFacet facetConfig : searchConfigurationService.getAllFacetsConfig()) { for (DiscoverySearchFilterFacet facetConfig : searchConfigurationService.getAllUniqueFacetsConfig()) {
boolean coversAllFieldsFromVocab = true; boolean coversAllFieldsFromVocab = true;
for (String fieldFromVocab: metadataFields) { for (String fieldFromVocab: metadataFields) {
boolean coversFieldFromVocab = false; boolean coversFieldFromVocab = false;

View File

@@ -11,8 +11,6 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -21,7 +19,11 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat; import org.dspace.content.BitstreamFormat;
@@ -1310,13 +1312,12 @@ public abstract class AbstractMETSIngester extends AbstractPackageIngester {
if (params.getBooleanProperty("manifestOnly", false)) { if (params.getBooleanProperty("manifestOnly", false)) {
// NOTE: since we are only dealing with a METS manifest, // NOTE: since we are only dealing with a METS manifest,
// we will assume all external files are available via URLs. // we will assume all external files are available via URLs.
try { try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
// attempt to open a connection to given URL // attempt to open a connection to given URL
URL fileURL = new URL(path); try (CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(path))) {
URLConnection connection = fileURL.openConnection(); // open stream to access file contents
return httpResponse.getEntity().getContent();
// open stream to access file contents }
return connection.getInputStream();
} catch (IOException io) { } catch (IOException io) {
log log
.error("Unable to retrieve external file from URL '" .error("Unable to retrieve external file from URL '"

View File

@@ -202,7 +202,7 @@ public interface DSpaceObjectService<T extends DSpaceObject> {
* Get the value(s) of a metadata field. * Get the value(s) of a metadata field.
* @param dSpaceObject the object whose metadata are sought. * @param dSpaceObject the object whose metadata are sought.
* @param mdString the name of the field: {@code schema.element.qualifier}. * @param mdString the name of the field: {@code schema.element.qualifier}.
* @param authority name of the authority which controls these values, or null. * @param authority name of the authority which controls these values, or Item.ANY, or null.
* @return all matching metadata values, or null if none. * @return all matching metadata values, or null if none.
*/ */
public List<MetadataValue> getMetadata(T dSpaceObject, String mdString, String authority); public List<MetadataValue> getMetadata(T dSpaceObject, String mdString, String authority);
@@ -216,7 +216,7 @@ public interface DSpaceObjectService<T extends DSpaceObject> {
* @param lang the language of the requested field value(s), * @param lang the language of the requested field value(s),
* null if explicitly no language, * null if explicitly no language,
* or {@link org.dspace.content.Item.ANY} to match all languages. * or {@link org.dspace.content.Item.ANY} to match all languages.
* @param authority name of the authority which controls these values, or null. * @param authority name of the authority which controls these values, or Item.ANY, or null.
* @return value(s) of the indicated field for the given DSO, or null. * @return value(s) of the indicated field for the given DSO, or null.
*/ */
public List<MetadataValue> getMetadata(T dSpaceObject, String schema, public List<MetadataValue> getMetadata(T dSpaceObject, String schema,

View File

@@ -44,7 +44,8 @@ public interface MetadataDSpaceCsvExportService {
* @return A DSpaceCSV object containing the exported information * @return A DSpaceCSV object containing the exported information
* @throws Exception If something goes wrong * @throws Exception If something goes wrong
*/ */
public DSpaceCSV export(Context context, Iterator<Item> toExport, boolean exportAll) throws Exception; public DSpaceCSV export(Context context, Iterator<Item> toExport,
boolean exportAll, DSpaceRunnableHandler handler) throws Exception;
/** /**
* This method will export all the Items within the given Community to a DSpaceCSV * This method will export all the Items within the given Community to a DSpaceCSV
@@ -54,6 +55,9 @@ public interface MetadataDSpaceCsvExportService {
* @return A DSpaceCSV object containing the exported information * @return A DSpaceCSV object containing the exported information
* @throws Exception If something goes wrong * @throws Exception If something goes wrong
*/ */
public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception; public DSpaceCSV export(Context context, Community community,
boolean exportAll, DSpaceRunnableHandler handler) throws Exception;
} int getCsvExportLimit();
}

View File

@@ -55,7 +55,7 @@ import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
/** /**
* Class representing an e-mail message. The {@link send} method causes the * Builder representing an e-mail message. The {@link send} method causes the
* assembled message to be formatted and sent. * assembled message to be formatted and sent.
* <p> * <p>
* Typical use: * Typical use:
@@ -168,6 +168,9 @@ public class Email {
*/ */
private String charset; private String charset;
/** The message being assembled. */
MimeMessage message;
private static final Logger LOG = LogManager.getLogger(); private static final Logger LOG = LogManager.getLogger();
/** Velocity template settings. */ /** Velocity template settings. */
@@ -188,6 +191,9 @@ public class Email {
/** Velocity template for a message body */ /** Velocity template for a message body */
private Template template; private Template template;
/** The message text. */
private String body;
/** /**
* Create a new email message. * Create a new email message.
*/ */
@@ -254,9 +260,15 @@ public class Email {
/** /**
* Fill out the next argument in the template. * Fill out the next argument in the template.
* *
* @param arg the value for the next argument * @param arg the value for the next argument. If {@code null},
* a zero-length string is substituted.
*/ */
public void addArgument(Object arg) { public void addArgument(Object arg) {
if (null == arg) {
arg = "";
LOG.warn("Null argument {} to email template {} replaced with zero-length string",
arguments.size(), contentName);
}
arguments.add(arg); arguments.add(arg);
} }
@@ -327,7 +339,27 @@ public class Email {
} }
/** /**
* Sends the email. If the template defines a Velocity context property * Sends the email. If sending is disabled then the assembled message is
* logged instead.
*
* @throws MessagingException if there was a problem sending the mail.
* @throws IOException if IO error
*/
public void send() throws MessagingException, IOException {
build();
ConfigurationService config
= DSpaceServicesFactory.getInstance().getConfigurationService();
boolean disabled = config.getBooleanProperty("mail.server.disabled", false);
if (disabled) {
LOG.info(format(message, body));
} else {
Transport.send(message);
}
}
/**
* Build the message. If the template defines a Velocity context property
* named among the values of DSpace configuration property * named among the values of DSpace configuration property
* {@code mail.message.headers} then that name and its value will be added * {@code mail.message.headers} then that name and its value will be added
* to the message's headers. * to the message's headers.
@@ -336,11 +368,12 @@ public class Email {
* called, the value of any "subject" property will be used as if setSubject * called, the value of any "subject" property will be used as if setSubject
* had been called with that value. Thus a template may define its subject, * had been called with that value. Thus a template may define its subject,
* but the caller may override it. * but the caller may override it.
* *
* @throws MessagingException if there was a problem sending the mail. * @throws MessagingException if there is no template, or passed through.
* @throws IOException if IO error * @throws IOException passed through.
*/ */
public void send() throws MessagingException, IOException { void build()
throws MessagingException, IOException {
if (null == template) { if (null == template) {
// No template -- no content -- PANIC!!! // No template -- no content -- PANIC!!!
throw new MessagingException("Email has no body"); throw new MessagingException("Email has no body");
@@ -351,7 +384,6 @@ public class Email {
// Get the mail configuration properties // Get the mail configuration properties
String from = config.getProperty("mail.from.address"); String from = config.getProperty("mail.from.address");
boolean disabled = config.getBooleanProperty("mail.server.disabled", false);
// If no character set specified, attempt to retrieve a default // If no character set specified, attempt to retrieve a default
if (charset == null) { if (charset == null) {
@@ -362,7 +394,7 @@ public class Email {
Session session = DSpaceServicesFactory.getInstance().getEmailService().getSession(); Session session = DSpaceServicesFactory.getInstance().getEmailService().getSession();
// Create message // Create message
MimeMessage message = new MimeMessage(session); message = new MimeMessage(session);
// Set the recipients of the message // Set the recipients of the message
for (String recipient : recipients) { for (String recipient : recipients) {
@@ -385,7 +417,7 @@ public class Email {
LOG.error("Template not merged: {}", ex.getMessage()); LOG.error("Template not merged: {}", ex.getMessage());
throw new MessagingException("Template not merged", ex); throw new MessagingException("Template not merged", ex);
} }
String fullMessage = writer.toString(); body = writer.toString();
// Set some message header fields // Set some message header fields
Instant date = Instant.now(); Instant date = Instant.now();
@@ -412,20 +444,19 @@ public class Email {
message.setSubject(subject); message.setSubject(subject);
} }
// Add attachments // Attach the body.
if (attachments.isEmpty() && moreAttachments.isEmpty()) { if (attachments.isEmpty() && moreAttachments.isEmpty()) { // Flat body.
// If a character set has been specified, or a default exists
if (charset != null) { if (charset != null) {
message.setText(fullMessage, charset); message.setText(body, charset);
} else { } else {
message.setText(fullMessage); message.setText(body);
} }
} else { } else { // Add attachments.
Multipart multipart = new MimeMultipart(); Multipart multipart = new MimeMultipart();
// create the first part of the email // create the first part of the email
BodyPart messageBodyPart = new MimeBodyPart(); BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setText(fullMessage); messageBodyPart.setText(body);
multipart.addBodyPart(messageBodyPart); multipart.addBodyPart(messageBodyPart);
// Add file attachments // Add file attachments
@@ -457,30 +488,47 @@ public class Email {
replyToAddr[0] = new InternetAddress(replyTo); replyToAddr[0] = new InternetAddress(replyTo);
message.setReplyTo(replyToAddr); message.setReplyTo(replyToAddr);
} }
}
if (disabled) { /**
StringBuilder text = new StringBuilder( * Flatten the email into a string.
"Message not sent due to mail.server.disabled:\n"); *
* @param message the message headers, attachments, etc.
* @param body the message body.
* @return stringified email message.
* @throws MessagingException passed through.
*/
private String format(MimeMessage message, String body)
throws MessagingException {
StringBuilder text = new StringBuilder(
"Message not sent due to mail.server.disabled:\n");
Enumeration<String> headers = message.getAllHeaderLines(); Enumeration<String> headers = message.getAllHeaderLines();
while (headers.hasMoreElements()) { while (headers.hasMoreElements()) {
text.append(headers.nextElement()).append('\n'); text.append(headers.nextElement()).append('\n');
}
if (!attachments.isEmpty()) {
text.append("\nAttachments:\n");
for (FileAttachment f : attachments) {
text.append(f.name).append('\n');
}
text.append('\n');
}
text.append('\n').append(fullMessage);
LOG.info(text.toString());
} else {
Transport.send(message);
} }
if (!attachments.isEmpty()) {
text.append("\nAttachments:\n");
for (FileAttachment f : attachments) {
text.append(f.name).append('\n');
}
text.append('\n');
}
text.append('\n').append(body);
return text.toString();
}
/**
* Get the formatted message for testing.
*
* @return the message flattened to a String.
* @throws MessagingException passed through.
*/
String getMessage()
throws MessagingException {
return format(message, body);
} }
/** /**

View File

@@ -500,4 +500,5 @@ public final class Utils {
return LocalDateTime.of(-4713, 11, 12, 0, 0, 0) return LocalDateTime.of(-4713, 11, 12, 0, 0, 0)
.toInstant(ZoneOffset.UTC); .toInstant(ZoneOffset.UTC);
} }
} }

View File

@@ -9,11 +9,15 @@ package org.dspace.ctask.general;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
@@ -135,24 +139,20 @@ public class BasicLinkChecker extends AbstractCurationTask {
* @return The HTTP response code (e.g. 200 / 301 / 404 / 500) * @return The HTTP response code (e.g. 200 / 301 / 404 / 500)
*/ */
protected int getResponseStatus(String url, int redirects) { protected int getResponseStatus(String url, int redirects) {
try { RequestConfig config = RequestConfig.custom().setRedirectsEnabled(true).build();
URL theURL = new URL(url); try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config)) {
HttpURLConnection connection = (HttpURLConnection) theURL.openConnection(); CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(url));
connection.setInstanceFollowRedirects(true); int statusCode = httpResponse.getStatusLine().getStatusCode();
int statusCode = connection.getResponseCode();
int maxRedirect = configurationService.getIntProperty("curate.checklinks.max-redirect", 0); int maxRedirect = configurationService.getIntProperty("curate.checklinks.max-redirect", 0);
if ((statusCode == HttpURLConnection.HTTP_MOVED_TEMP || statusCode == HttpURLConnection.HTTP_MOVED_PERM || if ((statusCode == HttpURLConnection.HTTP_MOVED_TEMP || statusCode == HttpURLConnection.HTTP_MOVED_PERM ||
statusCode == HttpURLConnection.HTTP_SEE_OTHER)) { statusCode == HttpURLConnection.HTTP_SEE_OTHER)) {
connection.disconnect(); String newUrl = httpResponse.getFirstHeader("Location").getValue();
String newUrl = connection.getHeaderField("Location");
if (newUrl != null && (maxRedirect >= redirects || maxRedirect == -1)) { if (newUrl != null && (maxRedirect >= redirects || maxRedirect == -1)) {
redirects++; redirects++;
return getResponseStatus(newUrl, redirects); return getResponseStatus(newUrl, redirects);
} }
} }
return statusCode; return statusCode;
} catch (IOException ioe) { } catch (IOException ioe) {
// Must be a bad URL // Must be a bad URL
log.debug("Bad link: " + ioe.getMessage()); log.debug("Bad link: " + ioe.getMessage());

View File

@@ -30,13 +30,13 @@ import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactory;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
@@ -255,53 +255,50 @@ public class MetadataWebService extends AbstractCurationTask implements Namespac
} }
protected int callService(String value, Item item, StringBuilder resultSb) throws IOException { protected int callService(String value, Item item, StringBuilder resultSb) throws IOException {
String callUrl = urlTemplate.replaceAll("\\{" + templateParam + "\\}", value); String callUrl = urlTemplate.replaceAll("\\{" + templateParam + "\\}", value);
CloseableHttpClient client = HttpClientBuilder.create().build(); try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpGet req = new HttpGet(callUrl); HttpGet req = new HttpGet(callUrl);
for (Map.Entry<String, String> entry : headers.entrySet()) { for (Map.Entry<String, String> entry : headers.entrySet()) {
req.addHeader(entry.getKey(), entry.getValue()); req.addHeader(entry.getKey(), entry.getValue());
} }
HttpResponse resp = client.execute(req); try (CloseableHttpResponse resp = client.execute(req)) {
int status = Curator.CURATE_ERROR; int status = Curator.CURATE_ERROR;
int statusCode = resp.getStatusLine().getStatusCode(); int statusCode = resp.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) { if (statusCode == HttpStatus.SC_OK) {
HttpEntity entity = resp.getEntity(); HttpEntity entity = resp.getEntity();
if (entity != null) { if (entity != null) {
// boiler-plate handling taken from Apache 4.1 javadoc // boiler-plate handling taken from Apache 4.1 javadoc
InputStream instream = entity.getContent(); InputStream instream = entity.getContent();
try { try {
// This next line triggers a false-positive XXE warning from LGTM, even though we disallow DTD // This next line triggers a false-positive XXE warning from LGTM, even though
// parsing during initialization of docBuilder in init() // we disallow DTD parsing during initialization of docBuilder in init()
Document doc = docBuilder.parse(instream); // lgtm [java/xxe] Document doc = docBuilder.parse(instream); // lgtm [java/xxe]
status = processResponse(doc, item, resultSb); status = processResponse(doc, item, resultSb);
} catch (SAXException saxE) { } catch (SAXException saxE) {
log.error("caught exception: " + saxE); log.error("caught exception: " + saxE);
resultSb.append(" unable to read response document"); resultSb.append(" unable to read response document");
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
// In case of an unexpected exception you may want to abort // In case of an unexpected exception you may want to abort
// the HTTP request in order to shut down the underlying // the HTTP request in order to shut down the underlying
// connection and release it back to the connection manager. // connection and release it back to the connection manager.
req.abort(); req.abort();
log.error("caught exception: " + ex); log.error("caught exception: " + ex);
throw ex; throw ex;
} finally { } finally {
// Closing the input stream will trigger connection release // Closing the input stream will trigger connection release
instream.close(); instream.close();
} }
// When HttpClient instance is no longer needed, } else {
// shut down the connection manager to ensure log.error(" obtained no valid service response");
// immediate deallocation of all system resources resultSb.append("no service response");
client.close(); }
} else { } else {
log.error(" obtained no valid service response"); log.error("service returned non-OK status: " + statusCode);
resultSb.append("no service response"); resultSb.append("no service response");
}
return status;
} }
} else {
log.error("service returned non-OK status: " + statusCode);
resultSb.append("no service response");
} }
return status;
} }
protected int processResponse(Document doc, Item item, StringBuilder resultSb) throws IOException { protected int processResponse(Document doc, Item item, StringBuilder resultSb) throws IOException {

View File

@@ -12,12 +12,12 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
@@ -60,22 +60,20 @@ public class MicrosoftTranslator extends AbstractTranslator {
String url = baseUrl + "?appId=" + apiKey; String url = baseUrl + "?appId=" + apiKey;
url += "&to=" + to + "&from=" + from + "&text=" + text; url += "&to=" + to + "&from=" + from + "&text=" + text;
try (CloseableHttpClient client = HttpClientBuilder.create().build()) { try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpGet hm = new HttpGet(url); HttpGet hm = new HttpGet(url);
HttpResponse httpResponse = client.execute(hm); try (CloseableHttpResponse httpResponse = client.execute(hm)) {
log.debug("Response code from API call is " + httpResponse); log.debug("Response code from API call is " + httpResponse);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
if (httpResponse.getStatusLine().getStatusCode() == 200) { String response = IOUtils.toString(httpResponse.getEntity().getContent(),
String response = IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.ISO_8859_1);
StandardCharsets.ISO_8859_1); response = response
response = response .replaceAll("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", "");
.replaceAll("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", ""); response = response.replaceAll("</string>", "");
response = response.replaceAll("</string>", ""); translatedText = response;
translatedText = response; }
} }
} }
return translatedText; return translatedText;
} }
} }

View File

@@ -25,6 +25,8 @@ import java.util.UUID;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.io.output.NullOutputStream; import org.apache.commons.io.output.NullOutputStream;
import org.dspace.app.util.DSpaceObjectUtilsImpl;
import org.dspace.app.util.service.DSpaceObjectUtils;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
@@ -36,6 +38,7 @@ import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.scripts.DSpaceRunnable; import org.dspace.scripts.DSpaceRunnable;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace; import org.dspace.utils.DSpace;
/** /**
@@ -46,7 +49,9 @@ import org.dspace.utils.DSpace;
public class Curation extends DSpaceRunnable<CurationScriptConfiguration> { public class Curation extends DSpaceRunnable<CurationScriptConfiguration> {
protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
protected DSpaceObjectUtils dspaceObjectUtils = DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName(DSpaceObjectUtilsImpl.class.getName(), DSpaceObjectUtilsImpl.class);
HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
protected Context context; protected Context context;
private CurationClientOptions curationClientOptions; private CurationClientOptions curationClientOptions;
@@ -346,9 +351,29 @@ public class Curation extends DSpaceRunnable<CurationScriptConfiguration> {
if (this.commandLine.hasOption('i')) { if (this.commandLine.hasOption('i')) {
this.id = this.commandLine.getOptionValue('i').toLowerCase(); this.id = this.commandLine.getOptionValue('i').toLowerCase();
DSpaceObject dso;
if (!this.id.equalsIgnoreCase("all")) { if (!this.id.equalsIgnoreCase("all")) {
HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); // First, try to parse the id as a UUID. If that fails, treat it as a handle.
DSpaceObject dso; UUID uuid = null;
try {
uuid = UUID.fromString(id);
} catch (Exception e) {
// It's not a UUID, proceed to treat it as a handle.
}
if (uuid != null) {
try {
dso = dspaceObjectUtils.findDSpaceObject(context, uuid);
if (dso != null) {
// We already resolved an object, return early
return;
}
} catch (SQLException e) {
String error = "SQLException trying to find dso with uuid " + uuid;
super.handler.logError(error);
throw new RuntimeException(error, e);
}
}
// If we get here, the id is not a UUID, so we assume it's a handle.
try { try {
dso = handleService.resolveToObject(this.context, id); dso = handleService.resolveToObject(this.context, id);
} catch (SQLException e) { } catch (SQLException e) {

View File

@@ -0,0 +1,58 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.content.Item;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* This plugin adds indicators to the solr document to determine if the item
* has geospatial metadata
*
* The facet is added to Discovery in the usual way (create a searchFilter bean
* and add it to the expected place) just with an empty list of used metadata
* fields because there are none.
*
* @author Kim Shepherd
*/
public class SolrServiceGeospatialFilterPlugin implements SolrServiceIndexPlugin {
@Autowired
ConfigurationService configurationService;
@Autowired
ItemService itemService;
@Override
public void additionalIndex(Context context, IndexableObject indexableObject, SolrInputDocument document) {
if (indexableObject instanceof IndexableItem) {
Item item = ((IndexableItem) indexableObject).getIndexedObject();
// Get configured field name
String geospatialField = configurationService.getProperty("discovery.filter.geospatial.field");
if (geospatialField == null) {
return;
}
String[] fieldParts = geospatialField.split("\\.", 3);
if (fieldParts.length < 2) {
return;
}
boolean hasGeospatialMetadata = itemService.getMetadataFirstValue(item,
fieldParts[0], fieldParts[1], fieldParts.length > 2 ? fieldParts[2] : null, Item.ANY) != null;
// also add _keyword and _filter because
// they are needed in order to work as a facet and filter.
document.addField("has_geospatial_metadata", hasGeospatialMetadata);
document.addField("has_geospatial_metadata_keyword", hasGeospatialMetadata);
document.addField("has_geospatial_metadata_filter", hasGeospatialMetadata);
}
}
}

View File

@@ -38,6 +38,7 @@ import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.json.BucketBasedJsonFacet; import org.apache.solr.client.solrj.response.json.BucketBasedJsonFacet;
import org.apache.solr.client.solrj.response.json.BucketJsonFacet;
import org.apache.solr.client.solrj.response.json.NestableJsonFacet; import org.apache.solr.client.solrj.response.json.NestableJsonFacet;
import org.apache.solr.client.solrj.util.ClientUtils; import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrDocument;
@@ -70,6 +71,7 @@ import org.dspace.discovery.indexobject.IndexableCommunity;
import org.dspace.discovery.indexobject.IndexableItem; import org.dspace.discovery.indexobject.IndexableItem;
import org.dspace.discovery.indexobject.factory.IndexFactory; import org.dspace.discovery.indexobject.factory.IndexFactory;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory; import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.discovery.indexobject.factory.ItemIndexFactory;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
@@ -339,6 +341,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
try { try {
final List<IndexFactory> indexableObjectServices = indexObjectServiceFactory. final List<IndexFactory> indexableObjectServices = indexObjectServiceFactory.
getIndexFactories(); getIndexFactories();
int indexObject = 0;
for (IndexFactory indexableObjectService : indexableObjectServices) { for (IndexFactory indexableObjectService : indexableObjectServices) {
if (type == null || StringUtils.equals(indexableObjectService.getType(), type)) { if (type == null || StringUtils.equals(indexableObjectService.getType(), type)) {
final Iterator<IndexableObject> indexableObjects = indexableObjectService.findAll(context); final Iterator<IndexableObject> indexableObjects = indexableObjectService.findAll(context);
@@ -346,6 +349,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
final IndexableObject indexableObject = indexableObjects.next(); final IndexableObject indexableObject = indexableObjects.next();
indexContent(context, indexableObject, force); indexContent(context, indexableObject, force);
context.uncacheEntity(indexableObject.getIndexedObject()); context.uncacheEntity(indexableObject.getIndexedObject());
indexObject++;
if ((indexObject % 100) == 0 && indexableObjectService instanceof ItemIndexFactory) {
context.uncacheEntities();
}
} }
} }
} }
@@ -988,8 +995,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} }
//Resolve our facet field values //Resolve our facet field values
resolveFacetFields(context, query, result, skipLoadingResponse, solrQueryResponse); resolveFacetFields(context, query, result, skipLoadingResponse, solrQueryResponse);
//Add total entries count for metadata browsing //Resolve our json facet field values used for metadata browsing
resolveEntriesCount(result, solrQueryResponse); resolveJsonFacetFields(context, result, solrQueryResponse);
} }
// If any stale entries are found in the current page of results, // If any stale entries are found in the current page of results,
// we remove those stale entries and rerun the same query again. // we remove those stale entries and rerun the same query again.
@@ -1016,33 +1023,38 @@ public class SolrServiceImpl implements SearchService, IndexingService {
} }
/** /**
* Stores the total count of entries for metadata index browsing. The count is calculated by the * Process the 'json.facet' response, which is currently only used for metadata browsing
* <code>json.facet</code> parameter with the following value:
* *
* <pre><code> * @param context context object
* { * @param result the result object to add the facet results to
* "entries_count": { * @param solrQueryResponse the solr query response
* "type": "terms", * @throws SQLException if database error
* "field": "facetNameField_filter",
* "limit": 0,
* "prefix": "prefix_value",
* "numBuckets": true
* }
* }
* </code></pre>
*
* This value is returned in the <code>facets</code> field of the Solr response.
*
* @param result DiscoverResult object where the total entries count will be stored
* @param solrQueryResponse QueryResponse object containing the solr response
*/ */
private void resolveEntriesCount(DiscoverResult result, QueryResponse solrQueryResponse) { private void resolveJsonFacetFields(Context context, DiscoverResult result, QueryResponse solrQueryResponse)
throws SQLException {
NestableJsonFacet response = solrQueryResponse.getJsonFacetingResponse(); NestableJsonFacet response = solrQueryResponse.getJsonFacetingResponse();
if (response != null) { if (response != null && response.getBucketBasedFacetNames() != null) {
BucketBasedJsonFacet facet = response.getBucketBasedFacets("entries_count"); for (String facetName : response.getBucketBasedFacetNames()) {
if (facet != null) { BucketBasedJsonFacet facet = response.getBucketBasedFacets(facetName);
result.setTotalEntries(facet.getNumBucketsCount()); if (facet != null) {
result.setTotalEntries(facet.getNumBucketsCount());
for (BucketJsonFacet bucket : facet.getBuckets()) {
String facetValue = bucket.getVal() != null ? bucket.getVal().toString() : "";
String field = facetName + "_filter";
String displayedValue = transformDisplayedValue(context, field, facetValue);
String authorityValue = transformAuthorityValue(context, field, facetValue);
String sortValue = transformSortValue(context, field, facetValue);
String filterValue = displayedValue;
if (StringUtils.isNotBlank(authorityValue)) {
filterValue = authorityValue;
}
result.addFacetResult(facetName,
new DiscoverResult.FacetResult(filterValue, displayedValue,
authorityValue, sortValue, bucket.getCount(),
DiscoveryConfigurationParameters.TYPE_TEXT));
}
}
} }
} }
} }
@@ -1266,7 +1278,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
try { try {
SolrQuery solrQuery = new SolrQuery(); SolrQuery solrQuery = new SolrQuery();
//Set the query to handle since this is unique //Set the query to handle since this is unique
solrQuery.setQuery(SearchUtils.RESOURCE_UNIQUE_ID + ": " + new IndexableItem(item).getUniqueIndexID()); solrQuery.setQuery(SearchUtils.RESOURCE_UNIQUE_ID + ":" + new IndexableItem(item).getUniqueIndexID());
//Only return obj identifier fields in result doc //Only return obj identifier fields in result doc
solrQuery.setFields(SearchUtils.RESOURCE_TYPE_FIELD, SearchUtils.RESOURCE_ID_FIELD); solrQuery.setFields(SearchUtils.RESOURCE_TYPE_FIELD, SearchUtils.RESOURCE_ID_FIELD);
//Add the more like this parameters ! //Add the more like this parameters !

View File

@@ -10,8 +10,10 @@ package org.dspace.discovery.configuration;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -197,15 +199,19 @@ public class DiscoveryConfigurationService {
} }
/** /**
* @return All configurations for {@link org.dspace.discovery.configuration.DiscoverySearchFilterFacet} * Get the unique set of configured Discovery facets. This is used when inspecting configuration
* to include hierarchical vocabularies in the browse menu.
*
* @return All unique instances of {@link org.dspace.discovery.configuration.DiscoverySearchFilterFacet}
* included in "sidebarFacets" bean, across all Discovery configurations.
*/ */
public List<DiscoverySearchFilterFacet> getAllFacetsConfig() { public List<DiscoverySearchFilterFacet> getAllUniqueFacetsConfig() {
List<DiscoverySearchFilterFacet> configs = new ArrayList<>(); Set<DiscoverySearchFilterFacet> configs = new LinkedHashSet<>();
for (String key : map.keySet()) { for (String key : map.keySet()) {
DiscoveryConfiguration config = map.get(key); DiscoveryConfiguration config = map.get(key);
configs.addAll(config.getSidebarFacets()); configs.addAll(config.getSidebarFacets());
} }
return configs; return new ArrayList<>(configs);
} }
public static void main(String[] args) { public static void main(String[] args) {

View File

@@ -181,6 +181,11 @@ public abstract class IndexFactoryImpl<T extends IndexableObject, S> implements
*/ */
protected void addFacetIndex(SolrInputDocument document, String field, String sortValue, String authority, protected void addFacetIndex(SolrInputDocument document, String field, String sortValue, String authority,
String fvalue) { String fvalue) {
// If facet value is null/blank, then we cannot index
if (StringUtils.isBlank(fvalue)) {
return;
}
// the separator for the filter can be eventually configured // the separator for the filter can be eventually configured
String separator = DSpaceServicesFactory.getInstance().getConfigurationService() String separator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("discovery.solr.facets.split.char"); .getProperty("discovery.solr.facets.split.char");

View File

@@ -17,15 +17,15 @@ import java.util.regex.Pattern;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.eperson.service.CaptchaService; import org.dspace.eperson.service.CaptchaService;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -82,18 +82,17 @@ public class CaptchaServiceImpl implements CaptchaService {
throw new RuntimeException(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e);
} }
HttpClient httpClient = HttpClientBuilder.create().build(); try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
HttpResponse httpResponse; final ObjectMapper objectMapper = new ObjectMapper();
GoogleCaptchaResponse googleResponse; try (CloseableHttpResponse httpResponse = httpClient.execute(httpPost)) {
final ObjectMapper objectMapper = new ObjectMapper(); GoogleCaptchaResponse googleResponse = objectMapper.readValue(httpResponse.getEntity().getContent(),
try { GoogleCaptchaResponse.class);
httpResponse = httpClient.execute(httpPost); validateGoogleResponse(googleResponse, action);
googleResponse = objectMapper.readValue(httpResponse.getEntity().getContent(), GoogleCaptchaResponse.class); }
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
throw new RuntimeException("Error during verify google recaptcha site", e); throw new RuntimeException("Error during verify google recaptcha site", e);
} }
validateGoogleResponse(googleResponse, action);
} }
private boolean responseSanityCheck(String response) { private boolean responseSanityCheck(String response) {

View File

@@ -131,7 +131,8 @@ public class SubscribeServiceImpl implements SubscribeService {
@Override @Override
public boolean isSubscribed(Context context, EPerson eperson, DSpaceObject dSpaceObject) throws SQLException { public boolean isSubscribed(Context context, EPerson eperson, DSpaceObject dSpaceObject) throws SQLException {
return subscriptionDAO.findByEPersonAndDso(context, eperson, dSpaceObject, -1, -1) != null; List<Subscription> subscriptions = subscriptionDAO.findByEPersonAndDso(context, eperson, dSpaceObject, -1, -1);
return subscriptions != null && !subscriptions.isEmpty();
} }
@Override @Override

View File

@@ -10,12 +10,45 @@ package org.dspace.eperson.factory;
import org.dspace.eperson.service.CaptchaService; import org.dspace.eperson.service.CaptchaService;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Factory to get services for Captcha protection of DSpace forms / endpoints
*
* @author Kim Shepherd
*/
public abstract class CaptchaServiceFactory { public abstract class CaptchaServiceFactory {
public abstract CaptchaService getCaptchaService(); /**
* Get the singleton instance of this class
* @return singleton instance of this class
*/
public static CaptchaServiceFactory getInstance() { public static CaptchaServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager() return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("captchaServiceFactory", CaptchaServiceFactory.class); .getServiceByName("captchaServiceFactory", CaptchaServiceFactory.class);
} }
/**
* Get the configured CaptchService
* TODO: This will be fully "operational" once we have full coverage of all
* forms by all supported captcha providers. Until then, REST repositories
* should request the specific captcha service required.
* @return the configured CaptchaService
*/
public abstract CaptchaService getCaptchaService();
/**
* Get the configured Altcha CaptchaService. This is needed by REST repositories
* processing captcha payloads for forms that are *only* protected by Altcha.
* TODO: We are working towards full coverage of all forms by all providers
* @return the configured Altcha CaptchaService
*/
public abstract CaptchaService getAltchaCaptchaService();
/**
* Get the configured Google CaptchaService. This is needed by REST repositories
* processing captcha payloads for forms that are *only* protected by Google.
* TODO: We are working towards full coverage of all forms by all providers
* @return the configured Google CaptchaService
*/
public abstract CaptchaService getGoogleCaptchaService();
} }

View File

@@ -12,6 +12,11 @@ import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
/**
* Factory to get services for Captcha protection of DSpace forms / endpoints
*
* @author Kim Shepherd
*/
public class CaptchaServiceFactoryImpl extends CaptchaServiceFactory { public class CaptchaServiceFactoryImpl extends CaptchaServiceFactory {
@Autowired @Autowired
@@ -25,9 +30,16 @@ public class CaptchaServiceFactoryImpl extends CaptchaServiceFactory {
@Autowired @Autowired
private ConfigurationService configurationService; private ConfigurationService configurationService;
/**
* Get the configured CaptchService
* TODO: This will be fully "operational" once we have full coverage of all
* forms by all supported captcha providers. Until then, REST repositories
* should request the specific captcha service required.
* @return the configured CaptchaService
*/
@Override @Override
public CaptchaService getCaptchaService() { public CaptchaService getCaptchaService() {
String provider = configurationService.getProperty("captcha.provider"); String provider = configurationService.getProperty("captcha.provider", "google");
if ("altcha".equalsIgnoreCase(provider)) { if ("altcha".equalsIgnoreCase(provider)) {
return altchaCaptchaService; return altchaCaptchaService;
@@ -35,4 +47,26 @@ public class CaptchaServiceFactoryImpl extends CaptchaServiceFactory {
return googleCaptchaService; // default to Google ReCaptcha return googleCaptchaService; // default to Google ReCaptcha
} }
/**
* Get the configured Altcha CaptchaService. This is needed by REST repositories
* processing captcha payloads for forms that are *only* protected by Altcha.
* TODO: We are working towards full coverage of all forms by all providers
* @return the configured Altcha CaptchaService
*/
@Override
public CaptchaService getAltchaCaptchaService() {
return altchaCaptchaService;
}
/**
* Get the configured Google CaptchaService. This is needed by REST repositories
* processing captcha payloads for forms that are *only* protected by Google.
* TODO: We are working towards full coverage of all forms by all providers
* @return the configured Google CaptchaService
*/
@Override
public CaptchaService getGoogleCaptchaService() {
return googleCaptchaService;
}
} }

View File

@@ -27,13 +27,13 @@ import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.NoHttpResponseException; import org.apache.http.NoHttpResponseException;
import org.apache.http.StatusLine; import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.app.util.Util; import org.dspace.app.util.Util;
import org.json.JSONObject; import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -120,33 +120,34 @@ public class OpenaireRestConnector {
params.add(new BasicNameValuePair("grant_type", "client_credentials")); params.add(new BasicNameValuePair("grant_type", "client_credentials"));
httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8")); httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
HttpClient httpClient = HttpClientBuilder.create().build(); try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
HttpResponse getResponse = httpClient.execute(httpPost); HttpResponse getResponse = httpClient.execute(httpPost);
JSONObject responseObject = null; JSONObject responseObject = null;
try (InputStream is = getResponse.getEntity().getContent(); try (InputStream is = getResponse.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
String inputStr; String inputStr;
// verify if we have basic json // verify if we have basic json
while ((inputStr = streamReader.readLine()) != null && responseObject == null) { while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token") if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")
&& inputStr.contains("expires_in")) { && inputStr.contains("expires_in")) {
try { try {
responseObject = new JSONObject(inputStr); responseObject = new JSONObject(inputStr);
} catch (Exception e) { } catch (Exception e) {
// Not as valid as I'd hoped, move along // Not as valid as I'd hoped, move along
responseObject = null; responseObject = null;
}
} }
} }
} }
} if (responseObject == null || !responseObject.has("access_token") || !responseObject.has("expires_in")) {
if (responseObject == null || !responseObject.has("access_token") || !responseObject.has("expires_in")) { throw new IOException("Unable to grab the access token using provided service url, " +
throw new IOException("Unable to grab the access token using provided service url, client id and secret"); "client id and secret");
} }
return new OpenaireRestToken(responseObject.get("access_token").toString(),
Long.valueOf(responseObject.get("expires_in").toString()));
return new OpenaireRestToken(responseObject.get("access_token").toString(),
Long.valueOf(responseObject.get("expires_in").toString()));
}
} }
/** /**
@@ -171,42 +172,43 @@ public class OpenaireRestConnector {
httpGet.addHeader("Authorization", "Bearer " + accessToken); httpGet.addHeader("Authorization", "Bearer " + accessToken);
} }
HttpClient httpClient = HttpClientBuilder.create().build(); try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
getResponse = httpClient.execute(httpGet); getResponse = httpClient.execute(httpGet);
StatusLine status = getResponse.getStatusLine(); StatusLine status = getResponse.getStatusLine();
// registering errors // registering errors
switch (status.getStatusCode()) { switch (status.getStatusCode()) {
case HttpStatus.SC_NOT_FOUND: case HttpStatus.SC_NOT_FOUND:
// 404 - Not found // 404 - Not found
case HttpStatus.SC_FORBIDDEN: case HttpStatus.SC_FORBIDDEN:
// 403 - Invalid Access Token // 403 - Invalid Access Token
case 429: case 429:
// 429 - Rate limit abuse for unauthenticated user // 429 - Rate limit abuse for unauthenticated user
Header[] limitUsed = getResponse.getHeaders("x-ratelimit-used"); Header[] limitUsed = getResponse.getHeaders("x-ratelimit-used");
Header[] limitMax = getResponse.getHeaders("x-ratelimit-limit"); Header[] limitMax = getResponse.getHeaders("x-ratelimit-limit");
if (limitUsed.length > 0) { if (limitUsed.length > 0) {
String limitMsg = limitUsed[0].getValue(); String limitMsg = limitUsed[0].getValue();
if (limitMax.length > 0) { if (limitMax.length > 0) {
limitMsg = limitMsg.concat(" of " + limitMax[0].getValue()); limitMsg = limitMsg.concat(" of " + limitMax[0].getValue());
}
getGotError(new NoHttpResponseException(status.getReasonPhrase() + " with usage limit "
+ limitMsg),
url + '/' + file);
} else {
// 429 - Rate limit abuse
getGotError(new NoHttpResponseException(status.getReasonPhrase()), url + '/' + file);
} }
getGotError( break;
new NoHttpResponseException(status.getReasonPhrase() + " with usage limit " + limitMsg), default:
url + '/' + file); // 200 or other
} else { break;
// 429 - Rate limit abuse }
getGotError(new NoHttpResponseException(status.getReasonPhrase()), url + '/' + file);
}
break;
default:
// 200 or other
break;
}
// do not close this httpClient // do not close this httpClient
result = getResponse.getEntity().getContent(); result = getResponse.getEntity().getContent();
}
} catch (MalformedURLException e1) { } catch (MalformedURLException e1) {
getGotError(e1, url + '/' + file); getGotError(e1, url + '/' + file);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -7,17 +7,18 @@
*/ */
package org.dspace.external; package org.dspace.external;
import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Scanner; import java.util.Scanner;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
/** /**
* @author Antoine Snyers (antoine at atmire.com) * @author Antoine Snyers (antoine at atmire.com)
@@ -39,7 +40,7 @@ public class OrcidRestConnector {
} }
public InputStream get(String path, String accessToken) { public InputStream get(String path, String accessToken) {
HttpResponse getResponse = null; CloseableHttpResponse getResponse = null;
InputStream result = null; InputStream result = null;
path = trimSlashes(path); path = trimSlashes(path);
@@ -49,11 +50,13 @@ public class OrcidRestConnector {
httpGet.addHeader("Content-Type", "application/vnd.orcid+xml"); httpGet.addHeader("Content-Type", "application/vnd.orcid+xml");
httpGet.addHeader("Authorization","Bearer " + accessToken); httpGet.addHeader("Authorization","Bearer " + accessToken);
} }
try { try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
HttpClient httpClient = HttpClientBuilder.create().build();
getResponse = httpClient.execute(httpGet); getResponse = httpClient.execute(httpGet);
//do not close this httpClient try (InputStream responseStream = getResponse.getEntity().getContent()) {
result = getResponse.getEntity().getContent(); // Read all the content of the response stream into a byte array to prevent TruncatedChunkException
byte[] content = responseStream.readAllBytes();
result = new ByteArrayInputStream(content);
}
} catch (Exception e) { } catch (Exception e) {
getGotError(e, fullPath); getGotError(e, fullPath);
} }

View File

@@ -7,24 +7,17 @@
*/ */
package org.dspace.external.provider.impl; package org.dspace.external.provider.impl;
import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.content.dto.MetadataValueDTO; import org.dspace.content.dto.MetadataValueDTO;
@@ -32,8 +25,9 @@ import org.dspace.external.OrcidRestConnector;
import org.dspace.external.model.ExternalDataObject; import org.dspace.external.model.ExternalDataObject;
import org.dspace.external.provider.AbstractExternalDataProvider; import org.dspace.external.provider.AbstractExternalDataProvider;
import org.dspace.external.provider.orcid.xml.XMLtoBio; import org.dspace.external.provider.orcid.xml.XMLtoBio;
import org.json.JSONObject; import org.dspace.orcid.model.factory.OrcidFactoryUtils;
import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier; import org.orcid.jaxb.model.v3.release.common.OrcidIdentifier;
import org.orcid.jaxb.model.v3.release.record.Email;
import org.orcid.jaxb.model.v3.release.record.Person; import org.orcid.jaxb.model.v3.release.record.Person;
import org.orcid.jaxb.model.v3.release.search.Result; import org.orcid.jaxb.model.v3.release.search.Result;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -60,6 +54,11 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
private XMLtoBio converter; private XMLtoBio converter;
/**
* Maximum retries to allow for the access token retrieval
*/
private int maxClientRetries = 3;
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})"; public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
private static final int MAX_INDEX = 10000; private static final int MAX_INDEX = 10000;
@@ -78,47 +77,37 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
* @throws java.io.IOException passed through from HTTPclient. * @throws java.io.IOException passed through from HTTPclient.
*/ */
public void init() throws IOException { public void init() throws IOException {
if (StringUtils.isNotBlank(clientSecret) && StringUtils.isNotBlank(clientId) // Initialize access token at spring instantiation. If it fails, the access token will be null rather
&& StringUtils.isNotBlank(OAUTHUrl)) { // than causing a fatal Spring startup error
String authenticationParameters = "?client_id=" + clientId + initializeAccessToken();
"&client_secret=" + clientSecret + }
"&scope=/read-public&grant_type=client_credentials";
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build(); /**
HttpResponse getResponse = httpClient.execute(httpPost); * Initialize access token, logging an error and decrementing remaining retries if an IOException is thrown.
* If the optional access token result is empty, set to null instead.
JSONObject responseObject = null; */
try (InputStream is = getResponse.getEntity().getContent(); public void initializeAccessToken() {
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { // If we have reaches max retries or the access token is already set, return immediately
String inputStr; if (maxClientRetries <= 0 || StringUtils.isNotBlank(accessToken)) {
while ((inputStr = streamReader.readLine()) != null && responseObject == null) { return;
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) { }
try { try {
responseObject = new JSONObject(inputStr); accessToken = OrcidFactoryUtils.retrieveAccessToken(clientId, clientSecret, OAUTHUrl).orElse(null);
} catch (Exception e) { } catch (IOException e) {
//Not as valid as I'd hoped, move along log.error("Error retrieving ORCID access token, {} retries left", --maxClientRetries);
responseObject = null;
}
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
accessToken = (String) responseObject.get("access_token");
}
} }
} }
@Override @Override
public Optional<ExternalDataObject> getExternalDataObject(String id) { public Optional<ExternalDataObject> getExternalDataObject(String id) {
initializeAccessToken();
Person person = getBio(id); Person person = getBio(id);
ExternalDataObject externalDataObject = convertToExternalDataObject(person); ExternalDataObject externalDataObject = convertToExternalDataObject(person);
return Optional.of(externalDataObject); return Optional.of(externalDataObject);
} }
protected ExternalDataObject convertToExternalDataObject(Person person) { protected ExternalDataObject convertToExternalDataObject(Person person) {
initializeAccessToken();
ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier); ExternalDataObject externalDataObject = new ExternalDataObject(sourceIdentifier);
if (person.getName() != null) { if (person.getName() != null) {
String lastName = ""; String lastName = "";
@@ -126,13 +115,20 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
if (person.getName().getFamilyName() != null) { if (person.getName().getFamilyName() != null) {
lastName = person.getName().getFamilyName().getContent(); lastName = person.getName().getFamilyName().getContent();
externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null, externalDataObject.addMetadata(new MetadataValueDTO("person", "familyName", null, null,
lastName)); lastName));
} }
if (person.getName().getGivenNames() != null) { if (person.getName().getGivenNames() != null) {
firstName = person.getName().getGivenNames().getContent(); firstName = person.getName().getGivenNames().getContent();
externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null, externalDataObject.addMetadata(new MetadataValueDTO("person", "givenName", null, null,
firstName)); firstName));
}
if (person.getEmails().getEmails() != null && !person.getEmails().getEmails().isEmpty()) {
Email email = person.getEmails().getEmails().get(0);
if (person.getEmails().getEmails().size() > 1) {
email = person.getEmails().getEmails().stream().filter(Email::isPrimary).findFirst().orElse(email);
}
externalDataObject.addMetadata(new MetadataValueDTO("person", "email", null,
null, email.getEmail()));
} }
externalDataObject.setId(person.getName().getPath()); externalDataObject.setId(person.getName().getPath());
externalDataObject externalDataObject
@@ -140,7 +136,7 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
new MetadataValueDTO("person", "identifier", "orcid", null, person.getName().getPath())); new MetadataValueDTO("person", "identifier", "orcid", null, person.getName().getPath()));
externalDataObject externalDataObject
.addMetadata(new MetadataValueDTO("dc", "identifier", "uri", null, .addMetadata(new MetadataValueDTO("dc", "identifier", "uri", null,
orcidUrl + "/" + person.getName().getPath())); orcidUrl + "/" + person.getName().getPath()));
if (!StringUtils.isBlank(lastName) && !StringUtils.isBlank(firstName)) { if (!StringUtils.isBlank(lastName) && !StringUtils.isBlank(firstName)) {
externalDataObject.setDisplayValue(lastName + ", " + firstName); externalDataObject.setDisplayValue(lastName + ", " + firstName);
externalDataObject.setValue(lastName + ", " + firstName); externalDataObject.setValue(lastName + ", " + firstName);
@@ -151,8 +147,8 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
externalDataObject.setDisplayValue(firstName); externalDataObject.setDisplayValue(firstName);
externalDataObject.setValue(firstName); externalDataObject.setValue(firstName);
} }
} else if (person.getPath() != null ) { } else if (person.getPath() != null) {
externalDataObject.setId(StringUtils.substringBetween(person.getPath(),"/","/person")); externalDataObject.setId(StringUtils.substringBetween(person.getPath(), "/", "/person"));
} }
return externalDataObject; return externalDataObject;
} }
@@ -167,14 +163,13 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
if (!isValid(id)) { if (!isValid(id)) {
return null; return null;
} }
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken); if (orcidRestConnector == null) {
Person person = converter.convertSinglePerson(bioDocument); log.error("ORCID REST connector is null, returning null ORCID Person Bio");
try { return null;
bioDocument.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
} }
return person; initializeAccessToken();
InputStream bioDocument = orcidRestConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
return converter.convertSinglePerson(bioDocument);
} }
/** /**
@@ -188,12 +183,18 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
@Override @Override
public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) { public List<ExternalDataObject> searchExternalDataObjects(String query, int start, int limit) {
initializeAccessToken();
if (limit > 100) { if (limit > 100) {
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100."); throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
} }
if (start > MAX_INDEX) { if (start > MAX_INDEX) {
throw new IllegalArgumentException("The starting number of results to retrieve cannot exceed 10000."); throw new IllegalArgumentException("The starting number of results to retrieve cannot exceed 10000.");
} }
// Check REST connector is initialized
if (orcidRestConnector == null) {
log.error("ORCID REST connector is not initialized, returning empty list");
return Collections.emptyList();
}
String searchPath = "search?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8) String searchPath = "search?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8)
+ "&start=" + start + "&start=" + start
@@ -205,7 +206,7 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
for (Result result : results) { for (Result result : results) {
OrcidIdentifier orcidIdentifier = result.getOrcidIdentifier(); OrcidIdentifier orcidIdentifier = result.getOrcidIdentifier();
if (orcidIdentifier != null) { if (orcidIdentifier != null) {
log.debug("Found OrcidId=" + orcidIdentifier.toString()); log.debug("Found OrcidId=" + orcidIdentifier.getPath());
String orcid = orcidIdentifier.getPath(); String orcid = orcidIdentifier.getPath();
Person bio = getBio(orcid); Person bio = getBio(orcid);
if (bio != null) { if (bio != null) {
@@ -213,14 +214,6 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
} }
} }
} }
try {
bioDocument.close();
} catch (IOException e) {
log.error(e.getMessage(), e);
}
if (Objects.isNull(bios)) {
return Collections.emptyList();
}
return bios.stream().map(bio -> convertToExternalDataObject(bio)).collect(Collectors.toList()); return bios.stream().map(bio -> convertToExternalDataObject(bio)).collect(Collectors.toList());
} }
@@ -231,6 +224,11 @@ public class OrcidV3AuthorDataProvider extends AbstractExternalDataProvider {
@Override @Override
public int getNumberOfResults(String query) { public int getNumberOfResults(String query) {
if (orcidRestConnector == null) {
log.error("ORCID REST connector is null, returning 0");
return 0;
}
initializeAccessToken();
String searchPath = "search?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8) String searchPath = "search?q=" + URLEncoder.encode(query, StandardCharsets.UTF_8)
+ "&start=" + 0 + "&start=" + 0
+ "&rows=" + 0; + "&rows=" + 0;

View File

@@ -97,7 +97,7 @@ public class SHERPAv2JournalDataProvider extends AbstractExternalDataProvider {
if (CollectionUtils.isNotEmpty(sherpaJournal.getIssns())) { if (CollectionUtils.isNotEmpty(sherpaJournal.getIssns())) {
String issn = sherpaJournal.getIssns().get(0); String issn = sherpaJournal.getIssns().get(0);
externalDataObject.addMetadata(new MetadataValueDTO( externalDataObject.addMetadata(new MetadataValueDTO(
"dc", "identifier", "issn", null, issn)); "creativeworkseries", "issn", null, null, issn));
} }

View File

@@ -106,8 +106,7 @@ public class SHERPAv2JournalISSNDataProvider extends AbstractExternalDataProvide
String issn = sherpaJournal.getIssns().get(0); String issn = sherpaJournal.getIssns().get(0);
externalDataObject.setId(issn); externalDataObject.setId(issn);
externalDataObject.addMetadata(new MetadataValueDTO( externalDataObject.addMetadata(new MetadataValueDTO(
"dc", "identifier", "issn", null, issn)); "creativeworkseries", "issn", null, null, issn));
} }
log.debug("New external data object. Title=" + externalDataObject.getValue() + ". ID=" log.debug("New external data object. Title=" + externalDataObject.getValue() + ". ID="

View File

@@ -108,8 +108,9 @@ public class ExternalDataServiceImpl implements ExternalDataService {
} }
log.info(LogHelper.getHeader(context, "create_item_from_externalDataObject", "Created item" + log.info(LogHelper.getHeader(context, "create_item_from_externalDataObject", "Created item" +
"with id: " + item.getID() + " from source: " + externalDataObject.getSource() + " with identifier: " + " with id: " + item.getID() +
externalDataObject.getId())); " from source: " + externalDataObject.getSource() +
" with identifier: " + externalDataObject.getId()));
try { try {
List<SuggestionProvider> providers = suggestionService.getSuggestionProviders(); List<SuggestionProvider> providers = suggestionService.getSuggestionProviders();
if (providers != null) { if (providers != null) {

View File

@@ -18,9 +18,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.google.GoogleAnalyticsEvent; import org.dspace.google.GoogleAnalyticsEvent;
/** /**
@@ -42,7 +42,7 @@ public class GoogleAnalyticsClientImpl implements GoogleAnalyticsClient {
public GoogleAnalyticsClientImpl(String keyPrefix, GoogleAnalyticsClientRequestBuilder requestBuilder) { public GoogleAnalyticsClientImpl(String keyPrefix, GoogleAnalyticsClientRequestBuilder requestBuilder) {
this.keyPrefix = keyPrefix; this.keyPrefix = keyPrefix;
this.requestBuilder = requestBuilder; this.requestBuilder = requestBuilder;
this.httpclient = HttpClients.createDefault(); this.httpclient = DSpaceHttpClientFactory.getInstance().build();
} }
@Override @Override

View File

@@ -15,11 +15,14 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.DSpaceObjectService;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.LogHelper; import org.dspace.core.LogHelper;
@@ -62,9 +65,6 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident
@Autowired(required = true) @Autowired(required = true)
private HandleService handleService; private HandleService handleService;
@Autowired(required = true)
private ItemService itemService;
/** /**
* After all the properties are set check that the versioning is enabled * After all the properties are set check that the versioning is enabled
* *
@@ -171,6 +171,16 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident
throw new RuntimeException("The current user is not authorized to change this item.", ex); throw new RuntimeException("The current user is not authorized to change this item.", ex);
} }
} }
if (dso instanceof Collection || dso instanceof Community) {
try {
// Update the metadata with the handle for collections and communities.
modifyHandleMetadata(context, dso, getCanonical(id));
} catch (SQLException ex) {
throw new RuntimeException("A problem with the database connection occured.", ex);
} catch (AuthorizeException ex) {
throw new RuntimeException("The current user is not authorized to change this item.", ex);
}
}
return id; return id;
} }
@@ -489,27 +499,29 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident
* Remove all handles from an item's metadata and add the supplied handle instead. * Remove all handles from an item's metadata and add the supplied handle instead.
* *
* @param context The relevant DSpace Context. * @param context The relevant DSpace Context.
* @param item which item to modify * @param dso which dso to modify
* @param handle which handle to add * @param handle which handle to add
* @throws SQLException if database error * @throws SQLException if database error
* @throws AuthorizeException if authorization error * @throws AuthorizeException if authorization error
*/ */
protected void modifyHandleMetadata(Context context, Item item, String handle) protected void modifyHandleMetadata(Context context, DSpaceObject dso, String handle)
throws SQLException, AuthorizeException { throws SQLException, AuthorizeException {
// we want to exchange the old handle against the new one. To do so, we // we want to exchange the old handle against the new one. To do so, we
// load all identifiers, clear the metadata field, re add all // load all identifiers, clear the metadata field, re add all
// identifiers which are not from type handle and add the new handle. // identifiers which are not from type handle and add the new handle.
String handleref = handleService.getCanonicalForm(handle); String handleref = handleService.getCanonicalForm(handle);
List<MetadataValue> identifiers = itemService DSpaceObjectService<DSpaceObject> dSpaceObjectService =
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); ContentServiceFactory.getInstance().getDSpaceObjectService(dso);
itemService.clearMetadata(context, item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY); List<MetadataValue> identifiers = dSpaceObjectService
.getMetadata(dso, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY);
dSpaceObjectService.clearMetadata(context, dso, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY);
for (MetadataValue identifier : identifiers) { for (MetadataValue identifier : identifiers) {
if (this.supports(identifier.getValue())) { if (this.supports(identifier.getValue())) {
// ignore handles // ignore handles
continue; continue;
} }
itemService.addMetadata(context, dSpaceObjectService.addMetadata(context,
item, dso,
identifier.getMetadataField(), identifier.getMetadataField(),
identifier.getLanguage(), identifier.getLanguage(),
identifier.getValue(), identifier.getValue(),
@@ -517,9 +529,9 @@ public class VersionedHandleIdentifierProviderWithCanonicalHandles extends Ident
identifier.getConfidence()); identifier.getConfidence());
} }
if (!StringUtils.isEmpty(handleref)) { if (!StringUtils.isEmpty(handleref)) {
itemService.addMetadata(context, item, MetadataSchemaEnum.DC.getName(), dSpaceObjectService.addMetadata(context, dso, MetadataSchemaEnum.DC.getName(),
"identifier", "uri", null, handleref); "identifier", "uri", null, handleref);
} }
itemService.update(context, item); dSpaceObjectService.update(context, dso);
} }
} }

View File

@@ -36,10 +36,10 @@ import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.CrosswalkException;
@@ -719,7 +719,7 @@ public class DataCiteConnector
httpContext.setCredentialsProvider(credentialsProvider); httpContext.setCredentialsProvider(credentialsProvider);
HttpEntity entity = null; HttpEntity entity = null;
try ( CloseableHttpClient httpclient = HttpClientBuilder.create().build(); ) { try (CloseableHttpClient httpclient = DSpaceHttpClientFactory.getInstance().build()) {
HttpResponse response = httpclient.execute(req, httpContext); HttpResponse response = httpclient.execute(req, httpContext);
StatusLine status = response.getStatusLine(); StatusLine status = response.getStatusLine();

View File

@@ -26,9 +26,9 @@ import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.identifier.DOI; import org.dspace.identifier.DOI;
import org.dspace.identifier.IdentifierException; import org.dspace.identifier.IdentifierException;
@@ -87,7 +87,7 @@ public class EZIDRequest {
this.authority = authority; this.authority = authority;
} }
client = HttpClientBuilder.create().build(); client = DSpaceHttpClientFactory.getInstance().build();
httpContext = HttpClientContext.create(); httpContext = HttpClientContext.create();
if (null != username) { if (null != username) {
URI uri = new URI(scheme, host, path, null); URI uri = new URI(scheme, host, path, null);
@@ -124,7 +124,7 @@ public class EZIDRequest {
this.authority = authority; this.authority = authority;
} }
client = HttpClientBuilder.create().build(); client = DSpaceHttpClientFactory.getInstance().build();
httpContext = HttpClientContext.create(); httpContext = HttpClientContext.create();
if (null != username) { if (null != username) {
CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

View File

@@ -12,12 +12,14 @@ import static org.dspace.iiif.canvasdimension.Util.checkDimensions;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.iiif.util.IIIFSharedUtils; import org.dspace.iiif.util.IIIFSharedUtils;
@@ -35,14 +37,10 @@ public class IIIFApiQueryServiceImpl implements IIIFApiQueryService {
public int[] getImageDimensions(Bitstream bitstream) { public int[] getImageDimensions(Bitstream bitstream) {
int[] arr = new int[2]; int[] arr = new int[2];
String path = IIIFSharedUtils.getInfoJsonPath(bitstream); String path = IIIFSharedUtils.getInfoJsonPath(bitstream);
URL url;
BufferedReader in = null; BufferedReader in = null;
try { try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
url = new URL(path); CloseableHttpResponse httpResponse = httpClient.execute(new HttpGet(path));
HttpURLConnection con = (HttpURLConnection) url.openConnection(); in = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
con.setRequestMethod("GET");
in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine; String inputLine;
StringBuilder response = new StringBuilder(); StringBuilder response = new StringBuilder();
while ((inputLine = in.readLine()) != null) { while ((inputLine = in.readLine()) != null) {

View File

@@ -17,7 +17,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import jakarta.el.MethodNotFoundException;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.importer.external.datamodel.ImportRecord; import org.dspace.importer.external.datamodel.ImportRecord;
import org.dspace.importer.external.datamodel.Query; import org.dspace.importer.external.datamodel.Query;
@@ -144,7 +143,7 @@ public class MultipleParallelImportMetadataSourceServiceImpl implements QuerySou
@Override @Override
public ImportRecord getRecord(Query query) throws MetadataSourceException { public ImportRecord getRecord(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for multiple external data sources"); throw new UnsupportedOperationException("This method is not implemented for multiple external data sources");
} }
@Override @Override

View File

@@ -21,7 +21,6 @@ import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
@@ -99,7 +98,7 @@ public class ADSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for CrossRef"); throw new UnsupportedOperationException("This method is not implemented for CrossRef");
} }
@Override @Override

View File

@@ -15,7 +15,6 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import jakarta.el.MethodNotFoundException;
import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.client.Invocation;
@@ -162,7 +161,7 @@ public class ArXivImportMetadataSourceServiceImpl extends AbstractImportMetadata
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
// FIXME: we need this method? // FIXME: we need this method?
throw new MethodNotFoundException("This method is not implemented for ArXiv"); throw new UnsupportedOperationException("This method is not implemented for ArXiv");
} }
/** /**

View File

@@ -20,7 +20,6 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpException; import org.apache.http.HttpException;
@@ -113,7 +112,7 @@ public class CiniiImportMetadataSourceServiceImpl extends AbstractImportMetadata
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for Cinii"); throw new UnsupportedOperationException("This method is not implemented for Cinii");
} }
public String getUrl() { public String getUrl() {

View File

@@ -20,7 +20,6 @@ import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
@@ -112,7 +111,7 @@ public class CrossRefImportMetadataSourceServiceImpl extends AbstractImportMetad
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for CrossRef"); throw new UnsupportedOperationException("This method is not implemented for CrossRef");
} }
public String getID(String id) { public String getID(String id) {

View File

@@ -17,7 +17,6 @@ import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -204,7 +203,7 @@ public class DataCiteImportMetadataSourceServiceImpl
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for DataCite"); throw new UnsupportedOperationException("This method is not implemented for DataCite");
} }
public String getID(String query) { public String getID(String query) {

View File

@@ -17,19 +17,16 @@ import java.util.Optional;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -53,16 +50,11 @@ public class LiveImportClientImpl implements LiveImportClient {
@Override @Override
public String executeHttpGetRequest(int timeout, String URL, Map<String, Map<String, String>> params) { public String executeHttpGetRequest(int timeout, String URL, Map<String, Map<String, String>> params) {
HttpGet method = null; HttpGet method = null;
RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(timeout).build();
try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient) try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient)
.orElseGet(HttpClients::createDefault)) { .orElse(DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config))) {
Builder requestConfigBuilder = RequestConfig.custom();
requestConfigBuilder.setConnectionRequestTimeout(timeout);
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
String uri = buildUrl(URL, params.get(URI_PARAMETERS)); String uri = buildUrl(URL, params.get(URI_PARAMETERS));
method = new HttpGet(uri); method = new HttpGet(uri);
method.setConfig(defaultRequestConfig);
Map<String, String> headerParams = params.get(HEADER_PARAMETERS); Map<String, String> headerParams = params.get(HEADER_PARAMETERS);
if (MapUtils.isNotEmpty(headerParams)) { if (MapUtils.isNotEmpty(headerParams)) {
@@ -71,7 +63,6 @@ public class LiveImportClientImpl implements LiveImportClient {
} }
} }
configureProxy(method, defaultRequestConfig);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Performing GET request to \"" + uri + "\"..."); log.debug("Performing GET request to \"" + uri + "\"...");
} }
@@ -95,21 +86,17 @@ public class LiveImportClientImpl implements LiveImportClient {
@Override @Override
public String executeHttpPostRequest(String URL, Map<String, Map<String, String>> params, String entry) { public String executeHttpPostRequest(String URL, Map<String, Map<String, String>> params, String entry) {
HttpPost method = null; HttpPost method = null;
RequestConfig config = RequestConfig.custom().build();
try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient) try (CloseableHttpClient httpClient = Optional.ofNullable(this.httpClient)
.orElseGet(HttpClients::createDefault)) { .orElse(DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(config))) {
Builder requestConfigBuilder = RequestConfig.custom();
RequestConfig defaultRequestConfig = requestConfigBuilder.build();
String uri = buildUrl(URL, params.get(URI_PARAMETERS)); String uri = buildUrl(URL, params.get(URI_PARAMETERS));
method = new HttpPost(uri); method = new HttpPost(uri);
method.setConfig(defaultRequestConfig);
if (StringUtils.isNotBlank(entry)) { if (StringUtils.isNotBlank(entry)) {
method.setEntity(new StringEntity(entry)); method.setEntity(new StringEntity(entry));
} }
setHeaderParams(method, params); setHeaderParams(method, params);
configureProxy(method, defaultRequestConfig);
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Performing POST request to \"" + uri + "\"..." ); log.debug("Performing POST request to \"" + uri + "\"..." );
} }
@@ -129,17 +116,6 @@ public class LiveImportClientImpl implements LiveImportClient {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
private void configureProxy(HttpRequestBase method, RequestConfig defaultRequestConfig) {
String proxyHost = configurationService.getProperty("http.proxy.host");
String proxyPort = configurationService.getProperty("http.proxy.port");
if (StringUtils.isNotBlank(proxyHost) && StringUtils.isNotBlank(proxyPort)) {
RequestConfig requestConfig = RequestConfig.copy(defaultRequestConfig)
.setProxy(new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http"))
.build();
method.setConfig(requestConfig);
}
}
/** /**
* Allows to set the header parameters to the HTTP Post method * Allows to set the header parameters to the HTTP Post method
* *

View File

@@ -0,0 +1,300 @@
/**
* 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.importer.external.metadatamapping.contributor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.importer.external.metadatamapping.MetadataFieldConfig;
import org.dspace.importer.external.metadatamapping.MetadataFieldMapping;
import org.dspace.importer.external.metadatamapping.MetadatumDTO;
/**
* A simple JsonPath Metadata processor
* that allow extract value from json object
* by configuring the path in the query variable via the bean.
* moreover this can also perform more compact extractions
* by configuring specific json processor in "metadataProcessor"
*
* In addition from some array where `query` points to the values can be selected using some additional condition check.
* This can be expressed in jsonpath, but not in jsonpointer expression.
*
* e.g.
* query /descriptions
* conditionkey "descriptionType"
* conditionvalue "Abstract"
* retrievedvalue "description"
*
* and json
*
* "descriptions": [
* {"description":"Description A","descriptionType":"Abstract"},
* {"description":"Description B","descriptionType":"Other"}
* ]
*
* should deliver the value "Description A".
* In addition there is some metadataPostProcessor modifying and changing the retrieved value,
* e.g. mapping to controlled values
*
* @author Mykhaylo Boychuk (mykhaylo.boychuk@4science.com)
* @author Florian Gantner (florian.gantner@uni-bamberg.de)
*/
public class EnhancedJsonPathAttributeConditionMetadataContributor implements MetadataContributor<String> {
private final static Logger log = LogManager.getLogger();
private String query;
private String conditionKey;
private String conditionValue;
private String elementAttribute;
private MetadataFieldConfig field;
protected JsonPathMetadataProcessor metadataProcessor;
protected JsonPathMetadataProcessor metadataPostProcessor;
/**
* Initialize SimpleJsonPathMetadataContributor with a query, prefixToNamespaceMapping and MetadataFieldConfig
*
* @param query The JSonPath query
* @param field the matadata field to map the result of the Json path query
* <a href="https://github.com/DSpace/DSpace/tree/master/dspace-api/src/main/java/org/dspace/importer/external#metadata-mapping-">MetadataFieldConfig</a>
*/
public EnhancedJsonPathAttributeConditionMetadataContributor(String query, MetadataFieldConfig field) {
this.query = query;
this.field = field;
}
/**
* Unused by this implementation
*/
@Override
public void setMetadataFieldMapping(MetadataFieldMapping<String, MetadataContributor<String>> rt) {
}
/**
* Empty constructor for SimpleJsonPathMetadataContributor
*/
public EnhancedJsonPathAttributeConditionMetadataContributor() {
}
/**
* Return the MetadataFieldConfig used while retrieving MetadatumDTO
*
* @return MetadataFieldConfig
*/
public MetadataFieldConfig getField() {
return field;
}
/**
* Setting the MetadataFieldConfig
*
* @param field MetadataFieldConfig used while retrieving MetadatumDTO
*/
public void setField(MetadataFieldConfig field) {
this.field = field;
}
/**
* Return query used to create the JSonPath
*
* @return the query this instance is based on
*/
public String getQuery() {
return query;
}
/**
* Return query used to create the JSonPath
*
*/
public void setQuery(String query) {
this.query = query;
}
/**
* Return condition attribute key which is checked
*
* @return the attribute key which is checked
*/
public String getConditionKey() {
return conditionKey;
}
/**
* The key of the json attribute which is checked for the condition
*
* @param conditionKey
*/
public void setConditionKey(String conditionKey) {
this.conditionKey = conditionKey;
}
/**
* Return condition attribute value which is checked
*
* @return the attribute value which is checked
*/
public String getConditionValue() {
return conditionValue;
}
/**
* The value of the json attribute which must match the condition
*
* @param conditionValue
*/
public void setConditionValue(String conditionValue) {
this.conditionValue = conditionValue;
}
/**
* Return element attribute key where the final value is retrieved from
*
* @return the attribute key for the element
*/
public String getElementAttribute() {
return elementAttribute;
}
/**
* The json attribute where the value is retrieved from
*
* @param elementAttribute
*/
public void setElementAttribute(String elementAttribute) {
this.elementAttribute = elementAttribute;
}
/**
* Used to process data got by jsonpath expression, like arrays to stringify, change date format or else
* If it is null, toString will be used.
*
* @param metadataProcessor
*/
public void setMetadataProcessor(JsonPathMetadataProcessor metadataProcessor) {
this.metadataProcessor = metadataProcessor;
}
/**
* Used to process data got by jsonpath expression, like arrays to stringify, change date format or else
* If it is null, toString will be used.
*
* @param metadataPostProcessor
*/
public void setMetadataPostProcessor(JsonPathMetadataProcessor metadataPostProcessor) {
this.metadataPostProcessor = metadataPostProcessor;
}
/**
* Retrieve the metadata associated with the given object.
* The toString() of the resulting object will be used.
*
* @param fullJson A class to retrieve metadata from.
* @return a collection of import records. Only the identifier of the found records may be put in the record.
*/
@Override
public Collection<MetadatumDTO> contributeMetadata(String fullJson) {
Collection<MetadatumDTO> metadata = new ArrayList<>();
Collection<String> metadataValue = new ArrayList<>();
if (Objects.nonNull(metadataProcessor)) {
metadataValue = metadataProcessor.processMetadata(fullJson);
} else {
JsonNode jsonNode = convertStringJsonToJsonNode(fullJson);
JsonNode node = jsonNode.at(query);
if (node.isArray()) {
Iterator<JsonNode> nodes = node.iterator();
while (nodes.hasNext()) {
JsonNode nodeV = nodes.next();
if (!checkCondition(nodeV)) {
continue;
}
if (getElementAttribute() != null) {
JsonNode element = nodeV.get(getElementAttribute());
if (element != null && !element.isMissingNode()) {
String nodeValue = getStringValue(element);
if (StringUtils.isNotBlank(nodeValue)) {
metadataValue.add(nodeValue);
}
}
} else {
String nodeValue = getStringValue(nodeV);
if (StringUtils.isNotBlank(nodeValue)) {
metadataValue.add(nodeValue);
}
}
}
} else if (!node.isNull() && StringUtils.isNotBlank(node.toString())) {
if (getElementAttribute() != null && checkCondition(node)) {
JsonNode element = node.get(getElementAttribute());
if (element != null && !element.isMissingNode()) {
String nodeValue = getStringValue(element);
if (StringUtils.isNotBlank(nodeValue)) {
metadataValue.add(nodeValue);
}
}
} else if (checkCondition(node)) {
String nodeValue = getStringValue(node);
if (StringUtils.isNotBlank(nodeValue)) {
metadataValue.add(nodeValue);
}
}
}
}
if (metadataPostProcessor != null) {
Collection<String> postmetadataValues = new ArrayList<>();
for (String value: metadataValue) {
Collection<String> postmetadataValue = metadataPostProcessor.processMetadata(value);
if (postmetadataValue != null) {
postmetadataValues.addAll(postmetadataValue);
}
}
metadataValue = postmetadataValues;
}
for (String value : metadataValue) {
MetadatumDTO metadatumDto = new MetadatumDTO();
metadatumDto.setValue(value);
metadatumDto.setElement(field.getElement());
metadatumDto.setQualifier(field.getQualifier());
metadatumDto.setSchema(field.getSchema());
metadata.add(metadatumDto);
}
return metadata;
}
/**
* Check some jsonNode if some jsonpointer expression matches some condition for some match.
* The match is parsed as some regex condition
* @param node
* @return true if node matches the condition or false if not
*/
private boolean checkCondition(JsonNode node) {
if (getConditionKey() == null && getConditionValue() == null) {
return true;
}
if (getConditionKey() != null) {
JsonNode conditionnode = node.get(getConditionKey());
if (getConditionValue() == null && conditionnode != null && !conditionnode.isMissingNode()) {
return true;
} else if (conditionnode != null && !conditionnode.isMissingNode() &&
conditionnode.toString().matches(getConditionValue())) {
return true;
}
} else if (getConditionKey() == null && node.toString().matches(getConditionValue())) {
return true;
}
return false;
}
private String getStringValue(JsonNode node) {
if (node.isTextual()) {
return node.textValue();
}
if (node.isNumber()) {
return node.numberValue().toString();
}
log.error("It wasn't possible to convert the value of the following JsonNode:" + node.asText());
return StringUtils.EMPTY;
}
private JsonNode convertStringJsonToJsonNode(String json) {
ObjectMapper mapper = new ObjectMapper();
JsonNode body = null;
try {
body = mapper.readTree(json);
} catch (JsonProcessingException e) {
log.error("Unable to process json response.", e);
}
return body;
}
}

View File

@@ -0,0 +1,33 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.importer.external.metadatamapping.contributor;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.util.SimpleMapConverter;
/**
* This Processor allows to map text values to controlled list of vocabularies using some mapConverter
*
* @author Florian Gantner (florian.gantner@uni-bamberg.de)
*/
public class MappingValueProcessor implements JsonPathMetadataProcessor {
private final static Logger log = LogManager.getLogger();
private SimpleMapConverter converter;
@Override
public Collection<String> processMetadata(String value) {
Collection<String> mappedValues = new ArrayList<>();
mappedValues.add(converter.getValue(value));
return mappedValues;
}
public void setConverter(SimpleMapConverter converter) {
this.converter = converter;
}
}

View File

@@ -15,7 +15,6 @@ import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import jakarta.el.MethodNotFoundException;
import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.client.Invocation;
@@ -135,12 +134,12 @@ public class OpenAireImportMetadataSourceServiceImpl extends AbstractImportMetad
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for OpenAIRE"); throw new UnsupportedOperationException("This method is not implemented for OpenAIRE");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for OpenAIRE"); throw new UnsupportedOperationException("This method is not implemented for OpenAIRE");
} }
/** /**

View File

@@ -17,7 +17,6 @@ import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -131,7 +130,7 @@ public class OpenAlexImportMetadataSourceServiceImpl extends AbstractImportMetad
@Override @Override
public Collection<ImportRecord> getRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> getRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for OpenAlex"); throw new UnsupportedOperationException("This method is not implemented for OpenAlex");
} }
/** /**
@@ -152,12 +151,12 @@ public class OpenAlexImportMetadataSourceServiceImpl extends AbstractImportMetad
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for OpenAlex"); throw new UnsupportedOperationException("This method is not implemented for OpenAlex");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for OpenAlex"); throw new UnsupportedOperationException("This method is not implemented for OpenAlex");
} }
/** /**

View File

@@ -235,6 +235,10 @@ public class PubmedImportMetadataSourceServiceImpl extends AbstractImportMetadat
try { try {
SAXBuilder saxBuilder = new SAXBuilder(); SAXBuilder saxBuilder = new SAXBuilder();
// Disallow external entities & entity expansion to protect against XXE attacks
// (NOTE: We receive errors if we disable all DTDs for PubMed, so this is the best we can do)
saxBuilder.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxBuilder.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
Document document = saxBuilder.build(new StringReader(src)); Document document = saxBuilder.build(new StringReader(src));
Element root = document.getRootElement(); Element root = document.getRootElement();

View File

@@ -18,7 +18,6 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpException; import org.apache.http.HttpException;
import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ClientProtocolException;
@@ -153,7 +152,7 @@ public class PubmedEuropeMetadataSourceServiceImpl extends AbstractImportMetadat
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for PubMed Europe"); throw new UnsupportedOperationException("This method is not implemented for PubMed Europe");
} }
@Override @Override

View File

@@ -19,7 +19,6 @@ import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
@@ -91,12 +90,12 @@ public class RorImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for ROR"); throw new UnsupportedOperationException("This method is not implemented for ROR");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for ROR"); throw new UnsupportedOperationException("This method is not implemented for ROR");
} }
@Override @Override

View File

@@ -21,7 +21,6 @@ import java.util.concurrent.Callable;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jakarta.el.MethodNotFoundException;
import jakarta.ws.rs.BadRequestException; import jakarta.ws.rs.BadRequestException;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
@@ -99,17 +98,17 @@ public class ScieloImportMetadataSourceServiceImpl extends AbstractImportMetadat
@Override @Override
public int getRecordsCount(Query query) throws MetadataSourceException { public int getRecordsCount(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for Scielo"); throw new UnsupportedOperationException("This method is not implemented for Scielo");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for Scielo"); throw new UnsupportedOperationException("This method is not implemented for Scielo");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for Scielo"); throw new UnsupportedOperationException("This method is not implemented for Scielo");
} }
/** /**

View File

@@ -23,7 +23,6 @@ import java.util.concurrent.Callable;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -152,7 +151,7 @@ public class ScopusImportMetadataSourceServiceImpl extends AbstractImportMetadat
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) public Collection<ImportRecord> findMatchingRecords(Item item)
throws MetadataSourceException { throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for Scopus"); throw new UnsupportedOperationException("This method is not implemented for Scopus");
} }
@Override @Override

View File

@@ -19,7 +19,6 @@ import java.util.concurrent.Callable;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -104,7 +103,7 @@ public class VuFindImportMetadataSourceServiceImpl extends AbstractImportMetadat
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for VuFind"); throw new UnsupportedOperationException("This method is not implemented for VuFind");
} }
@Override @Override

View File

@@ -22,7 +22,6 @@ import java.util.concurrent.Callable;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import jakarta.el.MethodNotFoundException;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -57,7 +56,7 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
private static final String AI_PATTERN = "^AI=(.*)"; private static final String AI_PATTERN = "^AI=(.*)";
private static final Pattern ISI_PATTERN = Pattern.compile("^\\d{15}$"); private static final Pattern ISI_PATTERN = Pattern.compile("^\\d{15}$");
private int timeout = 1000; private final int timeout = 1000;
private String url; private String url;
private String urlSearch; private String urlSearch;
@@ -109,17 +108,17 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
@Override @Override
public int getRecordsCount(Query query) throws MetadataSourceException { public int getRecordsCount(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for WOS"); throw new UnsupportedOperationException("This method is not implemented for WOS");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Item item) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for WOS"); throw new UnsupportedOperationException("This method is not implemented for WOS");
} }
@Override @Override
public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException { public Collection<ImportRecord> findMatchingRecords(Query query) throws MetadataSourceException {
throw new MethodNotFoundException("This method is not implemented for WOS"); throw new UnsupportedOperationException("This method is not implemented for WOS");
} }
/** /**
@@ -127,7 +126,7 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
*/ */
private class SearchNBByQueryCallable implements Callable<Integer> { private class SearchNBByQueryCallable implements Callable<Integer> {
private String query; private final String query;
private SearchNBByQueryCallable(String queryString) { private SearchNBByQueryCallable(String queryString) {
this.query = queryString; this.query = queryString;
@@ -156,7 +155,8 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
Element tot = xpath.evaluateFirst(root); Element tot = xpath.evaluateFirst(root);
return Integer.valueOf(tot.getValue()); return Integer.valueOf(tot.getValue());
} }
return null; log.warn("API key is missing: cannot execute count request.");
return 0;
} }
} }
@@ -167,7 +167,7 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
*/ */
private class FindByIdCallable implements Callable<List<ImportRecord>> { private class FindByIdCallable implements Callable<List<ImportRecord>> {
private String doi; private final String doi;
private FindByIdCallable(String doi) { private FindByIdCallable(String doi) {
this.doi = URLEncoder.encode(doi, StandardCharsets.UTF_8); this.doi = URLEncoder.encode(doi, StandardCharsets.UTF_8);
@@ -186,6 +186,8 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
for (Element record : elements) { for (Element record : elements) {
results.add(transformSourceRecords(record)); results.add(transformSourceRecords(record));
} }
} else {
log.warn("API key is missing: cannot execute live import request.");
} }
return results; return results;
} }
@@ -203,7 +205,7 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
*/ */
private class SearchByQueryCallable implements Callable<List<ImportRecord>> { private class SearchByQueryCallable implements Callable<List<ImportRecord>> {
private Query query; private final Query query;
private SearchByQueryCallable(String queryString, Integer maxResult, Integer start) { private SearchByQueryCallable(String queryString, Integer maxResult, Integer start) {
query = new Query(); query = new Query();
@@ -233,6 +235,8 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
for (Element el : omElements) { for (Element el : omElements) {
results.add(transformSourceRecords(el)); results.add(transformSourceRecords(el));
} }
} else {
log.warn("API key is missing: cannot execute live import request.");
} }
return results; return results;
} }
@@ -271,9 +275,7 @@ public class WOSImportMetadataSourceServiceImpl extends AbstractImportMetadataSo
} else if (isIsi(query)) { } else if (isIsi(query)) {
return "UT=(" + query + ")"; return "UT=(" + query + ")";
} }
StringBuilder queryBuilder = new StringBuilder("TS=("); return "TS=(" + query + ")";
queryBuilder.append(query).append(")");
return queryBuilder.toString();
} }
private boolean isIsi(String query) { private boolean isIsi(String query) {

View File

@@ -10,9 +10,6 @@ package org.dspace.license;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader; import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@@ -28,9 +25,9 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
import org.jdom2.Attribute; import org.jdom2.Attribute;
import org.jdom2.Document; import org.jdom2.Document;
@@ -70,12 +67,7 @@ public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService,
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
HttpClientBuilder builder = HttpClientBuilder.create(); client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5);
client = builder
.disableAutomaticRetries()
.setMaxConnTotal(5)
.build();
// disallow DTD parsing to ensure no XXE attacks can occur. // disallow DTD parsing to ensure no XXE attacks can occur.
// See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html // See https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
@@ -333,23 +325,13 @@ public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService,
@Override @Override
public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException { public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl"); String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI; String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI;
try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
URL request_url; CloseableHttpResponse httpResponse = httpClient.execute(new HttpPost(issueUrl));
try {
request_url = new URL(issueUrl);
} catch (MalformedURLException e) {
return null;
}
URLConnection connection = request_url.openConnection();
connection.setDoOutput(true);
try {
// parsing document from input stream // parsing document from input stream
InputStream stream = connection.getInputStream(); InputStream stream = httpResponse.getEntity().getContent();
Document doc = parser.build(stream); Document doc = parser.build(stream);
return doc; return doc;
} catch (Exception e) { } catch (Exception e) {
log.error("Error while retrieving the license document for URI: " + licenseURI, e); log.error("Error while retrieving the license document for URI: " + licenseURI, e);
} }

View File

@@ -35,13 +35,14 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder; import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.orcid.OrcidToken; import org.dspace.orcid.OrcidToken;
import org.dspace.orcid.exception.OrcidClientException; import org.dspace.orcid.exception.OrcidClientException;
import org.dspace.orcid.model.OrcidEntityType; import org.dspace.orcid.model.OrcidEntityType;
@@ -254,10 +255,8 @@ public class OrcidClientImpl implements OrcidClient {
} }
private void executeSuccessful(HttpUriRequest httpUriRequest) { private void executeSuccessful(HttpUriRequest httpUriRequest) {
try { try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpClient client = HttpClientBuilder.create().build(); CloseableHttpResponse response = client.execute(httpUriRequest);
HttpResponse response = client.execute(httpUriRequest);
if (isNotSuccessfull(response)) { if (isNotSuccessfull(response)) {
throw new OrcidClientException( throw new OrcidClientException(
getStatusCode(response), getStatusCode(response),
@@ -272,21 +271,17 @@ public class OrcidClientImpl implements OrcidClient {
} }
private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) { private <T> T executeAndParseJson(HttpUriRequest httpUriRequest, Class<T> clazz) {
try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpClient client = HttpClientBuilder.create().build(); return executeAndReturns(() -> {
CloseableHttpResponse response = client.execute(httpUriRequest);
return executeAndReturns(() -> { if (isNotSuccessfull(response)) {
throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
HttpResponse response = client.execute(httpUriRequest); }
return objectMapper.readValue(response.getEntity().getContent(), clazz);
if (isNotSuccessfull(response)) { });
throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response)); } catch (IOException e) {
} throw new RuntimeException(e);
}
return objectMapper.readValue(response.getEntity().getContent(), clazz);
});
} }
/** /**
@@ -301,44 +296,37 @@ public class OrcidClientImpl implements OrcidClient {
* @throws OrcidClientException if the incoming response is not successful * @throws OrcidClientException if the incoming response is not successful
*/ */
private <T> T executeAndUnmarshall(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull, Class<T> clazz) { private <T> T executeAndUnmarshall(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull, Class<T> clazz) {
try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
HttpClient client = HttpClientBuilder.create().build(); return executeAndReturns(() -> {
CloseableHttpResponse response = client.execute(httpUriRequest);
return executeAndReturns(() -> { if (handleNotFoundAsNull && isNotFound(response)) {
return null;
HttpResponse response = client.execute(httpUriRequest); }
if (isNotSuccessfull(response)) {
if (handleNotFoundAsNull && isNotFound(response)) { throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
return null; }
} return unmarshall(response.getEntity(), clazz);
});
if (isNotSuccessfull(response)) { } catch (IOException e) {
throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response)); throw new RuntimeException(e);
} }
return unmarshall(response.getEntity(), clazz);
});
} }
private OrcidResponse execute(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull) { private OrcidResponse execute(HttpUriRequest httpUriRequest, boolean handleNotFoundAsNull) {
HttpClient client = HttpClientBuilder.create().build(); try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().build()) {
return executeAndReturns(() -> {
return executeAndReturns(() -> { CloseableHttpResponse response = client.execute(httpUriRequest);
if (handleNotFoundAsNull && isNotFound(response)) {
HttpResponse response = client.execute(httpUriRequest); return new OrcidResponse(getStatusCode(response), null, getContent(response));
}
if (handleNotFoundAsNull && isNotFound(response)) { if (isNotSuccessfull(response)) {
return new OrcidResponse(getStatusCode(response), null, getContent(response)); throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response));
} }
return new OrcidResponse(getStatusCode(response), getPutCode(response), getContent(response));
if (isNotSuccessfull(response)) { });
throw new OrcidClientException(getStatusCode(response), formatErrorMessage(response)); } catch (IOException e) {
} throw new RuntimeException(e);
}
return new OrcidResponse(getStatusCode(response), getPutCode(response), getContent(response));
});
} }
private <T> T executeAndReturns(ThrowingSupplier<T, Exception> supplier) { private <T> T executeAndReturns(ThrowingSupplier<T, Exception> supplier) {

View File

@@ -7,10 +7,21 @@
*/ */
package org.dspace.orcid.model.factory; package org.dspace.orcid.model.factory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.json.JSONObject;
/** /**
* Utility class for Orcid factory classes. This is used to parse the * Utility class for Orcid factory classes. This is used to parse the
@@ -65,4 +76,48 @@ public final class OrcidFactoryUtils {
return configurations; return configurations;
} }
/**
* Retrieve access token from ORCID, given a client ID, client secret and OAuth URL
*
* @param clientId ORCID client ID
* @param clientSecret ORCID client secret
* @param oauthUrl ORCID oauth redirect URL
* @return response object as Optional string
* @throws IOException if any errors are encountered making the connection or reading a response
*/
public static Optional<String> retrieveAccessToken(String clientId, String clientSecret, String oauthUrl)
throws IOException {
if (StringUtils.isNotBlank(clientSecret) && StringUtils.isNotBlank(clientId)
&& StringUtils.isNotBlank(oauthUrl)) {
String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials";
HttpPost httpPost = new HttpPost(oauthUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpResponse response;
try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().build()) {
response = httpClient.execute(httpPost);
}
JSONObject responseObject = null;
if (response != null && response.getStatusLine().getStatusCode() == 200) {
try (InputStream is = response.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is,
StandardCharsets.UTF_8))) {
String inputStr;
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
responseObject = new JSONObject(inputStr);
}
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
return Optional.of((String) responseObject.get("access_token"));
}
}
// Return empty by default
return Optional.empty();
}
} }

View File

@@ -22,9 +22,9 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity; import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.QAEvent; import org.dspace.content.QAEvent;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
@@ -114,20 +114,19 @@ public class QAEventActionServiceImpl implements QAEventActionService {
* Make acknowledgement to the configured urls for the event status. * Make acknowledgement to the configured urls for the event status.
*/ */
private void makeAcknowledgement(String eventId, String source, String status) { private void makeAcknowledgement(String eventId, String source, String status) {
String[] ackwnoledgeCallbacks = configurationService String[] acknowledgeCallbacks = configurationService
.getArrayProperty("qaevents." + source + ".acknowledge-url"); .getArrayProperty("qaevents." + source + ".acknowledge-url");
if (ackwnoledgeCallbacks != null) { if (acknowledgeCallbacks != null) {
for (String ackwnoledgeCallback : ackwnoledgeCallbacks) { for (String acknowledgeCallback : acknowledgeCallbacks) {
if (StringUtils.isNotBlank(ackwnoledgeCallback)) { if (StringUtils.isNotBlank(acknowledgeCallback)) {
ObjectNode node = jsonMapper.createObjectNode(); ObjectNode node = jsonMapper.createObjectNode();
node.put("eventId", eventId); node.put("eventId", eventId);
node.put("status", status); node.put("status", status);
StringEntity requestEntity = new StringEntity(node.toString(), ContentType.APPLICATION_JSON); StringEntity requestEntity = new StringEntity(node.toString(), ContentType.APPLICATION_JSON);
CloseableHttpClient httpclient = HttpClients.createDefault(); try (CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
HttpPost postMethod = new HttpPost(ackwnoledgeCallback); HttpPost postMethod = new HttpPost(acknowledgeCallback);
postMethod.setEntity(requestEntity); postMethod.setEntity(requestEntity);
try { httpClient.execute(postMethod);
httpclient.execute(postMethod);
} catch (IOException e) { } catch (IOException e) {
log.error(e.getMessage(), e); log.error(e.getMessage(), e);
} }

View File

@@ -117,9 +117,9 @@ public class Harvest {
} }
if (!withdrawn) { if (!withdrawn) {
discoverQuery.addFilterQueries("archived: true OR withdrawn: false"); discoverQuery.addFilterQueries("archived:true OR withdrawn:false");
} else { } else {
discoverQuery.addFilterQueries("archived: true OR withdrawn: true"); discoverQuery.addFilterQueries("archived:true OR withdrawn:true");
} }
// Order by item ID, so that for a given harvest the order will be // Order by item ID, so that for a given harvest the order will be

View File

@@ -19,11 +19,11 @@ import org.apache.http.HttpResponse;
import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.HttpClientConnectionManager; import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator; import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
/** /**
@@ -112,7 +112,7 @@ public class HttpConnectionPoolService {
* @return the client. * @return the client.
*/ */
public CloseableHttpClient getClient() { public CloseableHttpClient getClient() {
CloseableHttpClient httpClient = HttpClientBuilder.create() CloseableHttpClient httpClient = DSpaceHttpClientFactory.getInstance().builder(true).create()
.setKeepAliveStrategy(keepAliveStrategy) .setKeepAliveStrategy(keepAliveStrategy)
.setConnectionManager(connManager) .setConnectionManager(connManager)
.build(); .build();

View File

@@ -54,7 +54,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrClient;
@@ -84,6 +83,7 @@ import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams; import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.NamedList;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.Bundle; import org.dspace.content.Bundle;
@@ -1208,7 +1208,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
+ "." + "."
+ i + i
+ ".csv"); + ".csv");
try ( CloseableHttpClient hc = HttpClientBuilder.create().build(); ) { try (CloseableHttpClient hc = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
HttpResponse response = hc.execute(get); HttpResponse response = hc.execute(get);
csvInputstream = response.getEntity().getContent(); csvInputstream = response.getEntity().getContent();
//Write the csv output to a file ! //Write the csv output to a file !
@@ -1350,7 +1350,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
HttpGet get = new HttpGet(solrRequestUrl); HttpGet get = new HttpGet(solrRequestUrl);
List<String[]> rows; List<String[]> rows;
try ( CloseableHttpClient hc = HttpClientBuilder.create().build(); ) { try (CloseableHttpClient hc = DSpaceHttpClientFactory.getInstance().buildWithoutProxy()) {
HttpResponse response = hc.execute(get); HttpResponse response = hc.execute(get);
InputStream csvOutput = response.getEntity().getContent(); InputStream csvOutput = response.getEntity().getContent();
Reader csvReader = new InputStreamReader(csvOutput); Reader csvReader = new InputStreamReader(csvOutput);

View File

@@ -93,7 +93,7 @@ public class StatisticsLoggingConsumer implements Consumer {
// We are mapping a new item make sure that the owning collection is // We are mapping a new item make sure that the owning collection is
// updated // updated
Item newItem = (Item) event.getObject(ctx); Item newItem = (Item) event.getObject(ctx);
String updateQuery = "id: " + newItem.getID() + " AND type:" String updateQuery = "id:" + newItem.getID() + " AND type:"
+ newItem.getType(); + newItem.getType();
List<String> fieldNames = new ArrayList<String>(); List<String> fieldNames = new ArrayList<String>();
@@ -116,7 +116,7 @@ public class StatisticsLoggingConsumer implements Consumer {
&& event.getObject(ctx) instanceof Item) { && event.getObject(ctx) instanceof Item) {
// Unmapping items // Unmapping items
Item newItem = (Item) event.getObject(ctx); Item newItem = (Item) event.getObject(ctx);
String updateQuery = "id: " + newItem.getID() + " AND type:" String updateQuery = "id:" + newItem.getID() + " AND type:"
+ newItem.getType(); + newItem.getType();
List<String> fieldNames = new ArrayList<String>(); List<String> fieldNames = new ArrayList<String>();

View File

@@ -68,10 +68,10 @@ public class StatisticsBSAdapter {
switch (visitType) { switch (visitType) {
case ITEM_VISITS: case ITEM_VISITS:
return solrLoggerService return solrLoggerService
.queryTotal("type: " + Constants.ITEM + " AND id: " + item.getID(), resolveFilterQueries(), 0) .queryTotal("type:" + Constants.ITEM + " AND id:" + item.getID(), resolveFilterQueries(), 0)
.getCount(); .getCount();
case BITSTREAM_VISITS: case BITSTREAM_VISITS:
return solrLoggerService.queryTotal("type: " + Constants.BITSTREAM + " AND owningItem: " + item.getID(), return solrLoggerService.queryTotal("type:" + Constants.BITSTREAM + " AND owningItem:" + item.getID(),
resolveFilterQueries(), 0).getCount(); resolveFilterQueries(), 0).getCount();
case TOTAL_VISITS: case TOTAL_VISITS:
return getNumberOfVisits(ITEM_VISITS, item) + getNumberOfVisits(BITSTREAM_VISITS, item); return getNumberOfVisits(ITEM_VISITS, item) + getNumberOfVisits(BITSTREAM_VISITS, item);

View File

@@ -209,7 +209,7 @@ public class StatisticsDataSearches extends StatisticsData {
protected String getQuery() { protected String getQuery() {
String query; String query;
if (currentDso != null) { if (currentDso != null) {
query = "scopeType: " + currentDso.getType() + " AND "; query = "scopeType:" + currentDso.getType() + " AND ";
if (currentDso instanceof DSpaceObjectLegacySupport) { if (currentDso instanceof DSpaceObjectLegacySupport) {
query += " (scopeId:" + currentDso.getID() + " OR scopeId:" + ((DSpaceObjectLegacySupport) currentDso) query += " (scopeId:" + currentDso.getID() + " OR scopeId:" + ((DSpaceObjectLegacySupport) currentDso)
.getLegacyId() + ")"; .getLegacyId() + ")";

View File

@@ -237,7 +237,7 @@ public class StatisticsDataVisits extends StatisticsData {
false, null, facetMinCount); false, null, facetMinCount);
for (int j = 0; j < maxObjectCounts.length; j++) { for (int j = 0; j < maxObjectCounts.length; j++) {
ObjectCount firstCount = maxObjectCounts[j]; ObjectCount firstCount = maxObjectCounts[j];
String newQuery = dataSetQuery.getFacetField() + ": " + ClientUtils String newQuery = dataSetQuery.getFacetField() + ":" + ClientUtils
.escapeQueryChars(firstCount.getValue()) + " AND " + query; .escapeQueryChars(firstCount.getValue()) + " AND " + query;
ObjectCount[] maxDateFacetCounts = solrLoggerService ObjectCount[] maxDateFacetCounts = solrLoggerService
.queryFacetDate(newQuery, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(), .queryFacetDate(newQuery, filterQuery, dataSetQuery.getMax(), dateFacet.getDateType(),
@@ -813,7 +813,7 @@ public class StatisticsDataVisits extends StatisticsData {
String query = ""; String query = "";
//Check (& add if needed) the dsoType //Check (& add if needed) the dsoType
if (dsoType != -1) { if (dsoType != -1) {
query += "type: " + dsoType; query += "type:" + dsoType;
} }
//Check (& add if needed) the dsoId //Check (& add if needed) the dsoId

View File

@@ -146,7 +146,7 @@ public class StatisticsDataWorkflow extends StatisticsData {
*/ */
protected String getQuery() { protected String getQuery() {
String query = "statistics_type:" + SolrLoggerServiceImpl.StatisticsType.WORKFLOW.text(); String query = "statistics_type:" + SolrLoggerServiceImpl.StatisticsType.WORKFLOW.text();
query += " AND NOT(previousWorkflowStep: SUBMIT)"; query += " AND NOT(previousWorkflowStep:SUBMIT)";
if (currentDso != null) { if (currentDso != null) {
if (currentDso.getType() == Constants.COMMUNITY) { if (currentDso.getType() == Constants.COMMUNITY) {
query += " AND owningComm:"; query += " AND owningComm:";

View File

@@ -15,13 +15,13 @@ import java.time.LocalDate;
import java.util.List; import java.util.List;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.dspace.app.client.DSpaceHttpClientFactory;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.statistics.export.OpenURLTracker; import org.dspace.statistics.export.OpenURLTracker;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -69,16 +69,16 @@ public class OpenUrlServiceImpl implements OpenUrlService {
* @throws IOException * @throws IOException
*/ */
protected int getResponseCodeFromUrl(final String urlStr) throws IOException { protected int getResponseCodeFromUrl(final String urlStr) throws IOException {
HttpGet httpGet = new HttpGet(urlStr); try (CloseableHttpClient httpClient = getHttpClient(getHttpClientRequestConfig())) {
HttpClient httpClient = getHttpClient(getHttpClientRequestConfig()); HttpGet httpGet = new HttpGet(urlStr);
HttpResponse httpResponse = httpClient.execute(httpGet); try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
return httpResponse.getStatusLine().getStatusCode(); return httpResponse.getStatusLine().getStatusCode();
}
}
} }
protected HttpClient getHttpClient(RequestConfig requestConfig) { protected CloseableHttpClient getHttpClient(RequestConfig requestConfig) {
return HttpClientBuilder.create() return DSpaceHttpClientFactory.getInstance().buildWithRequestConfig(requestConfig);
.setDefaultRequestConfig(requestConfig)
.build();
} }
protected RequestConfig getHttpClientRequestConfig() { protected RequestConfig getHttpClientRequestConfig() {

View File

@@ -0,0 +1,81 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.storage.bitstore;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import com.google.common.io.ByteSource;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
/**
* A ByteSource implementation that provides access to DSpace Bitstream content.
* Extends Google Guava's ByteSource to allow streaming access to bitstream data.
*
* Author: Mark Diggory, Nathan Buckingham
*/
public class BitstreamByteSource extends ByteSource {
/** Service for accessing bitstream content */
private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
/** The bitstream this source provides access to */
private final Bitstream bitstream;
/**
* Creates a new BitstreamByteSource for the given bitstream.
*
* @param bitstream the DSpace bitstream to wrap
*/
public BitstreamByteSource(Bitstream bitstream) {
this.bitstream = bitstream;
}
/**
* Gets the underlying bitstream.
*
* @return the DSpace bitstream object
*/
public Bitstream getBitstream() {
return bitstream;
}
/**
* Opens a new input stream for reading the bitstream content.
*
* @return an input stream containing the bitstream data
* @throws IOException if there is an error retrieving the bitstream,
* including SQL or authorization errors
*/
@Override
public InputStream openStream() throws IOException {
try {
return bitstreamService.retrieve(new Context(), bitstream);
} catch (SQLException | AuthorizeException e) {
throw new IOException(e.getMessage(), e);
}
}
/**
* Gets the size of the bitstream in bytes.
*
* @return the size of the bitstream in bytes
* @throws IOException if there is an error accessing the size
*/
@Override
public long size() throws IOException {
return bitstream.getSizeBytes();
}
}

View File

@@ -91,6 +91,11 @@ public class BitstreamStorageServiceImpl implements BitstreamStorageService, Ini
} }
@Override
public void setIncomingExternal(int incoming) {
this.incoming = incoming;
}
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
for (Map.Entry<Integer, BitStoreService> storeEntry : stores.entrySet()) { for (Map.Entry<Integer, BitStoreService> storeEntry : stores.entrySet()) {

View File

@@ -0,0 +1,582 @@
/**
* 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.storage.bitstore;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.google.common.hash.HashCode;
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import com.google.common.net.MediaType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Bitstream;
import org.dspace.content.BitstreamFormat;
import org.dspace.core.Context;
import org.dspace.core.Utils;
import org.dspace.storage.bitstore.factory.StorageServiceFactory;
import org.dspace.storage.bitstore.service.BitstreamStorageService;
import org.jclouds.ContextBuilder;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.options.ListContainerOptions;
import org.jclouds.blobstore.options.PutOptions.Builder;
import org.jclouds.io.ContentMetadata;
import org.jclouds.javax.annotation.Nullable;
/**
* JCloudBitstream asset store service
*
* This class provides an implementation of the BitstreamStorageService using JClouds for cloud storage.
* It supports storing, retrieving, and removing bitstreams in a cloud storage container.
* The class also handles initialization and configuration of the JClouds BlobStoreContext.
*
* Additional details regarding configuration can be found at:
* Blobstore Configuration https://jclouds.apache.org/start/blobstore/
* Providers and API https://jclouds.apache.org/reference/providers/#blobstore
*
* Author: Mark Diggory, Nathan Buckingham
*/
public class JCloudBitStoreService extends BaseBitStoreService {
/** Logger for this class */
private static final Logger log = LogManager.getLogger(JCloudBitStoreService.class);
/** Properties for configuring the cloud storage provider */
private Properties properties;
/** The cloud storage provider or API to use (e.g. "aws-s3", "openstack-swift") */
private String providerOrApi;
/** JClouds ContextBuilder for creating the storage context */
private ContextBuilder builder;
/** JClouds BlobStoreContext for interacting with the cloud storage */
private BlobStoreContext blobStoreContext;
/**
* Container/bucket name where assets are stored.
* Required for cloud storage providers.
*/
private String container;
/**
* Optional subfolder path within the container/bucket.
* Allows organizing assets in a subfolder hierarchy.
*/
private String subfolder = null;
/** Authentication identity/access key for the cloud provider */
private String identity;
/** Authentication credential/secret key for the cloud provider */
private String credential;
/** Optional endpoint URL for the cloud storage service */
private String endpoint;
/** Whether to use relative paths when storing assets */
private boolean useRelativePath;
/** Whether this storage service is enabled */
private boolean enabled = false;
/** Counter for tracking context refreshes */
private int counter = 0;
/** Maximum value for context refresh counter before forcing refresh */
private int maxCounter = -1;
/** Checksum algorithm used (MD5) */
private static final String CSA = "MD5";
/**
* Default constructor.
*/
public JCloudBitStoreService() {
}
/**
* Constructor with provider or API.
*
* @param providerOrApi the provider or API to use for cloud storage
*/
public JCloudBitStoreService(String providerOrApi) {
this.providerOrApi = providerOrApi;
}
/**
* Protected constructor with BlobStoreContext and provider or API.
*
* @param blobStoreContext the BlobStoreContext to use
* @param providerOrApi the provider or API to use for cloud storage
*/
protected JCloudBitStoreService(BlobStoreContext blobStoreContext, String providerOrApi) {
this.blobStoreContext = blobStoreContext;
this.providerOrApi = providerOrApi;
}
/**
* Sets whether to use relative paths for storing bitstreams.
*
* @param useRelativePath true to use relative paths, false otherwise
*/
public void setUseRelativePath(boolean useRelativePath) {
this.useRelativePath = useRelativePath;
}
/**
* Sets whether the service is enabled.
*
* @param enabled true to enable the service, false otherwise
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* Sets the container name for storing bitstreams.
*
* @param container the container name
*/
public void setContainer(String container) {
this.container = container;
}
/**
* Gets the subfolder within the bucket where objects are stored.
*
* @return the subfolder name
*/
public String getSubfolder() {
return subfolder;
}
/**
* Sets the subfolder within the bucket where objects are stored.
*
* @param subfolder the subfolder name
*/
public void setSubfolder(String subfolder) {
this.subfolder = subfolder;
}
/**
* Sets the identity for cloud storage authentication.
*
* @param identity the identity
*/
public void setIdentity(String identity) {
this.identity = identity;
}
/**
* Sets the credentials for cloud storage authentication.
*
* @param credential the credentials
*/
public void setCredentials(@Nullable String credential) {
this.credential = credential;
}
/**
* Sets the provider or API for cloud storage.
*
* @param providerOrApi the provider or API
*/
public void setProviderOrApi(String providerOrApi) {
this.providerOrApi = providerOrApi;
}
/**
* Sets the endpoint for cloud storage.
*
* @param endpoint the endpoint
*/
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
/**
* Sets the maximum counter value for refreshing the context.
*
* @param maxCounter the maximum counter value
*/
public void setMaxCounter(int maxCounter) {
this.maxCounter = maxCounter;
}
/**
* Sets the properties for cloud storage configuration.
*
* @param overrides the properties
*/
public void setOverrides(Properties overrides) {
this.properties = overrides;
}
/**
* Checks if the service is enabled.
*
* @return true if the service is enabled, false otherwise
*/
@Override
public boolean isEnabled() {
return this.enabled;
}
/**
* Initializes the cloud storage context.
*
* @throws IOException if an error occurs during initialization
*/
@Override
public void init() throws IOException {
if (this.isInitialized()) {
return;
}
try {
this.builder = ContextBuilder.newBuilder(providerOrApi);
if (StringUtils.isNotEmpty(endpoint)) {
this.builder = this.builder.endpoint(endpoint);
}
if (properties != null && !properties.isEmpty()) {
this.builder = this.builder.overrides(properties);
}
if (StringUtils.isNotEmpty(identity) && StringUtils.isNotEmpty(credential)) {
this.builder = this.builder.credentials(identity, credential);
}
blobStoreContext = this.builder.buildView(BlobStoreContext.class);
this.initialized = true;
} catch (Exception e) {
log.error(e.getMessage(),e);
this.initialized = false;
}
}
/**
* Refreshes the cloud storage context if needed. Can be used to reset connection pool every
* {@code @maxCounter} requests if thrid party service start to show connection pooling issues.
* Defaults to never reset the connection pool.
*/
private synchronized void refreshContextIfNeeded() {
// do not reset context if maxCounter set to -1
if (maxCounter < 0) {
return;
}
counter++;
// Close and Recreate connection between JClouds and remote service
if (counter == maxCounter) {
counter = 0;
blobStoreContext.close();
blobStoreContext = this.builder.buildView(BlobStoreContext.class);
}
}
/**
* Generates a unique identifier for a bitstream.
*
* @return the generated identifier
*/
@Override
public String generateId() {
return Utils.generateKey();
}
/**
* Retrieves a bitstream as an InputStream.
*
* @param bitstream the bitstream to retrieve
* @return the InputStream of the bitstream
* @throws IOException if an error occurs during retrieval
*/
@Override
public InputStream get(final Bitstream bitstream) throws IOException {
final File file = getFile(bitstream);
return get(file);
}
/**
* Retrieves a file as an InputStream.
*
* @param file the file to retrieve
* @return the InputStream of the file
* @throws IOException if an error occurs during retrieval
*/
private InputStream get(File file) throws IOException {
BlobStore blobStore = blobStoreContext.getBlobStore();
if (blobStore.blobExists(getContainer(), file.toString())) {
Blob blob = blobStore.getBlob(getContainer(), file.toString());
refreshContextIfNeeded();
return blob.getPayload().openStream();
}
throw new IOException("File not found: " + file);
}
/**
* Removes a bitstream from the cloud storage.
*
* @param bitstream the bitstream to remove
* @throws IOException if an error occurs during removal
*/
@Override
public void remove(Bitstream bitstream) throws IOException {
File file = getFile(bitstream);
BlobStore blobStore = blobStoreContext.getBlobStore();
blobStore.removeBlob(getContainer(), file.toString());
deleteParents(file);
}
/**
* Utility Method: Prefix the key with a subfolder, if this instance assets are stored within subfolder
*
* @param id DSpace bitstream internal ID
* @return full key prefixed with a subfolder, if applicable
*/
public String getFullKey(String id) {
StringBuilder bufFilename = new StringBuilder();
if (StringUtils.isNotEmpty(this.subfolder)) {
bufFilename.append(this.subfolder);
appendSeparator(bufFilename);
}
if (this.useRelativePath) {
bufFilename.append(getRelativePath(id));
} else {
bufFilename.append(id);
}
if (log.isDebugEnabled()) {
log.debug("Container filepath for " + id + " is "
+ bufFilename.toString());
}
return bufFilename.toString();
}
/**
* Computes the relative path for a bitstream.
*
* there are 2 cases:
* - conventional bitstream, conventional storage
* - registered bitstream, conventional storage
* conventional bitstream: dspace ingested, dspace random name/path
* registered bitstream: registered to dspace, any name/path
*
* @param sInternalId the internal ID of the bitstream
* @return the computed relative path
*/
private String getRelativePath(String sInternalId) {
BitstreamStorageService bitstreamStorageService = StorageServiceFactory.getInstance()
.getBitstreamStorageService();
String sIntermediatePath = StringUtils.EMPTY;
if (bitstreamStorageService.isRegisteredBitstream(sInternalId)) {
sInternalId = sInternalId.substring(2);
} else {
sInternalId = sanitizeIdentifier(sInternalId);
sIntermediatePath = getIntermediatePath(sInternalId);
}
return sIntermediatePath + sInternalId;
}
/**
* Deletes parent directories if they are empty.
*
* @param file the file whose parent directories to delete
*/
private void deleteParents(File file) {
if (file == null) {
return;
}
final BlobStore blobStore = blobStoreContext.getBlobStore();
for (int i = 0; i < directoryLevels; i++) {
final File directory = file.getParentFile();
final ListContainerOptions options = new ListContainerOptions();
options.inDirectory(directory.getPath());
long blobs = blobStore.countBlobs(getContainer(), options);
if (blobs != 0) {
break;
}
blobStore.deleteDirectory(getContainer(), directory.getPath());
file = directory;
}
}
/**
* Stores a byte source as a bitstream.
*
* @param byteSource the byte source to store
* @param bitstream the bitstream to store
* @throws IOException if an error occurs during storage
*/
public void put(ByteSource byteSource, Bitstream bitstream) throws IOException {
String key = getFullKey(bitstream.getInternalId());
/* set type to sane default */
String type = MediaType.OCTET_STREAM.toString();
/* attempt to get type if the source is a Bitstream */
if (byteSource instanceof BitstreamByteSource) {
type = getMIMEType(((BitstreamByteSource) byteSource).getBitstream());
}
BlobStore blobStore = blobStoreContext.getBlobStore();
String container = getContainer();
if (!blobStore.containerExists(container)) {
blobStore.createContainerInLocation(null, container);
}
Blob blob = blobStore.blobBuilder(key)
.payload(byteSource)
.contentDisposition(key)
.contentLength(byteSource.size())
.contentType(type)
.build();
/* Utilize large file transfer to S3 via multipart post */
blobStore.putBlob(container, blob, Builder.multipart());
}
/**
* Stores a stream of bits.
*
* <p>
* If this method returns successfully, the bits have been stored.
* If an exception is thrown, the bits have not been stored.
* </p>
*
* @param bitstream the bitstream to store
* @param in the stream of bits to store
* @throws IOException if a problem occurs while storing the bits
*/
@Override
public void put(Bitstream bitstream, InputStream in) throws IOException {
String key = getFullKey(bitstream.getInternalId());
//Copy istream to temp file, and send the file, with some metadata
File scratchFile = File.createTempFile(bitstream.getInternalId(), "s3bs");
try {
FileUtils.copyInputStreamToFile(in, scratchFile);
long contentLength = scratchFile.length();
// The ETag may or may not be and MD5 digest of the object data.
// Therefore, we precalculate before uploading
String localChecksum = org.dspace.curate.Utils.checksum(scratchFile, CSA);
put(Files.asByteSource(scratchFile), bitstream);
bitstream.setSizeBytes(contentLength);
bitstream.setChecksum(localChecksum);
bitstream.setChecksumAlgorithm(CSA);
} catch (Exception e) {
log.error("put(" + bitstream.getInternalId() + ", is)", e);
throw new IOException(e);
} finally {
if (!scratchFile.delete()) {
scratchFile.deleteOnExit();
}
}
}
/**
* Gets the MIME type of a bitstream.
*
* @param bitstream the bitstream to get the MIME type for
* @return the MIME type of the bitstream
*/
public static String getMIMEType(final Bitstream bitstream) {
try {
BitstreamFormat format = bitstream.getFormat(new Context());
return format == null ? null : format.getMIMEType();
} catch (SQLException ignored) {
throw new RuntimeException(ignored);
}
}
/**
* Retrieves metadata about a bitstream.
*
* @param bitstream the bitstream to retrieve metadata for
* @param attrs the list of attributes to retrieve
* @return a map of metadata attributes and their values
* @throws IOException if an error occurs during retrieval
*/
@SuppressWarnings("unchecked")
public Map<String, Object> about(Bitstream bitstream, List<String> attrs) throws IOException {
File file = getFile(bitstream);
BlobStore blobStore = blobStoreContext.getBlobStore();
BlobMetadata blobMetadata = blobStore.blobMetadata(getContainer(), file.toString());
Map<String, Object> metadata = new HashMap<>();
if (blobMetadata != null) {
ContentMetadata contentMetadata = blobMetadata.getContentMetadata();
if (contentMetadata != null) {
metadata.put("size_bytes", String.valueOf(contentMetadata.getContentLength()));
final HashCode hashCode = contentMetadata.getContentMD5AsHashCode();
if (hashCode != null) {
metadata.put("checksum", Utils.toHex(contentMetadata.getContentMD5AsHashCode().asBytes()));
metadata.put("checksum_algorithm", CSA);
}
metadata.put("modified", String.valueOf(blobMetadata.getLastModified().getTime()));
metadata.put("ContentDisposition", contentMetadata.getContentDisposition());
metadata.put("ContentEncoding", contentMetadata.getContentEncoding());
metadata.put("ContentLanguage", contentMetadata.getContentLanguage());
metadata.put("ContentType", contentMetadata.getContentType());
if (contentMetadata.getExpires() != null) {
metadata.put("Expires", contentMetadata.getExpires().getTime());
}
}
return metadata;
}
return null;
}
/**
* Gets the file corresponding to a bitstream.
*
* @param bitstream the bitstream to get the file for
* @return the file corresponding to the bitstream
* @throws IOException if an error occurs during retrieval
*/
public File getFile(Bitstream bitstream) throws IOException {
String id = bitstream.getInternalId();
id = getFullKey(id);
if (log.isDebugEnabled()) {
log.debug("Local filename for " + bitstream.getInternalId() + " is " + id);
}
return new File(id);
}
/**
* Gets the container name for storing bitstreams.
*
* @return the container name
*/
private String getContainer() {
return container;
}
}

View File

@@ -191,4 +191,11 @@ public interface BitstreamStorageService {
@Nullable @Nullable
Long getLastModified(Bitstream bitstream) throws IOException; Long getLastModified(Bitstream bitstream) throws IOException;
/**
* Sets the number for the incoming store
* @param incoming
*/
public void setIncomingExternal(int incoming);
} }

View File

@@ -29,6 +29,7 @@
<name-map collection-handle="123456789/collection-test" submission-name="collectiontest"/> <name-map collection-handle="123456789/collection-test" submission-name="collectiontest"/>
<name-map collection-entity-type="CustomEntityType" submission-name="entitytypetest"/> <name-map collection-entity-type="CustomEntityType" submission-name="entitytypetest"/>
<name-map collection-handle="123456789/test-duplicate-detection" submission-name="test-duplicate-detection"/> <name-map collection-handle="123456789/test-duplicate-detection" submission-name="test-duplicate-detection"/>
<name-map collection-handle="123456789/collection-test-patch" submission-name="publicationTestPatch"/>
<name-map collection-handle="123456789/enforced-relation" submission-name="enforcedRelation"/> <name-map collection-handle="123456789/enforced-relation" submission-name="enforcedRelation"/>
</submission-map> </submission-map>
@@ -195,6 +196,11 @@
<processing-class>org.dspace.app.rest.submit.step.NotifyStep</processing-class> <processing-class>org.dspace.app.rest.submit.step.NotifyStep</processing-class>
<type>coarnotify</type> <type>coarnotify</type>
</step-definition> </step-definition>
<step-definition id="upload-no-required-metadata" mandatory="true">
<heading>submit.progressbar.upload-no-required-metadata</heading>
<processing-class>org.dspace.app.rest.submit.step.UploadStep</processing-class>
<type>upload</type>
</step-definition>
<step-definition id="publicationStep" mandatory="true"> <step-definition id="publicationStep" mandatory="true">
<heading>submit.progressbar.describe.stepone</heading> <heading>submit.progressbar.describe.stepone</heading>
@@ -311,6 +317,12 @@
<step id="publicationStep"></step> <step id="publicationStep"></step>
</submission-process> </submission-process>
<submission-process name="publicationTestPatch">
<step id="collection" />
<step id="traditionalpageone" />
<step id="upload-no-required-metadata" />
<step id="license" />
</submission-process>
</submission-definitions> </submission-definitions>
</item-submission> </item-submission>

View File

@@ -158,6 +158,7 @@ proxies.trusted.include_ui_ip = true
# For the tests we have to disable this health indicator because there isn't a mock server and the calculated status was DOWN # For the tests we have to disable this health indicator because there isn't a mock server and the calculated status was DOWN
management.health.solrOai.enabled = false management.health.solrOai.enabled = false
management.health.seo.enabled = false
# Enable researcher profiles and orcid synchronization for tests # Enable researcher profiles and orcid synchronization for tests
researcher-profile.entity-type = Person researcher-profile.entity-type = Person
@@ -192,4 +193,13 @@ ldn.notify.inbox.block-untrusted-ip = true
# ERROR LOGGING # # ERROR LOGGING #
########################################### ###########################################
# Log full stacktrace of other common 4xx errors (for easier debugging of these errors in tests) # Log full stacktrace of other common 4xx errors (for easier debugging of these errors in tests)
logging.server.include-stacktrace-for-httpcode = 422, 400 logging.server.include-stacktrace-for-httpcode = 422, 400
### JCloudSettings
# Enabled the JCloudStore
assetstore.jcloud.enabled = true
assetstore.jcloud.subfolder = assetstore
assetstore.jcloud.provider = filesystem
assetstore.jcloud.container = assetstore-jclouds-container
assetstore.jcloud.basedir = target/testing/dspace

View File

@@ -55,6 +55,7 @@
<property name="map"> <property name="map">
<map> <map>
<entry key="upload" value-ref="uploadConfigurationDefault" /> <entry key="upload" value-ref="uploadConfigurationDefault" />
<entry key="upload-no-required-metadata" value-ref="uploadConfigurationPublicationTestPatch" />
</map> </map>
</property> </property>
</bean> </bean>
@@ -116,4 +117,16 @@
</property> </property>
</bean> </bean>
<bean id="uploadConfigurationPublicationTestPatch" class="org.dspace.submit.model.UploadConfiguration">
<property name="name" value="upload-no-required-metadata"/>
<property name="metadata" value="bitstream-metadata" />
<property name="options">
<list>
<ref bean="administrator"/>
<ref bean="openAccess"/>
<ref bean="embargoed" />
</list>
</property>
</bean>
</beans> </beans>

View File

@@ -16,7 +16,7 @@
<bean id="dspace.DSpaceAuthorityIndexer" class="org.dspace.authority.indexer.DSpaceAuthorityIndexer"/> <bean id="dspace.DSpaceAuthorityIndexer" class="org.dspace.authority.indexer.DSpaceAuthorityIndexer"/>
<alias name="OrcidSource" alias="AuthoritySource"/> <alias name="OrcidSource" alias="AuthoritySource"/>
<bean name="OrcidSource" class="org.dspace.authority.orcid.MockOrcid" /> <bean name="OrcidSource" class="org.dspace.authority.orcid.MockOrcid" init-method="init" />
<bean name="AuthorityTypes" class="org.dspace.authority.AuthorityTypes"> <bean name="AuthorityTypes" class="org.dspace.authority.AuthorityTypes">
<property name="types"> <property name="types">

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