diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7b5068a31792..f7239f819325 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -45,24 +45,15 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# https://github.com/actions/setup-java
- name: Install JDK ${{ matrix.java }}
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
-
- # https://github.com/actions/cache
- - name: Cache Maven dependencies
- uses: actions/cache@v3
- with:
- # Cache entire ~/.m2/repository
- path: ~/.m2/repository
- # Cache key is hash of all pom.xml files. Therefore any changes to POMs will invalidate cache
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: ${{ runner.os }}-maven-
+ cache: 'maven'
#- name: Install Grobid (only IT)
# run: ./dspace-api/src/test/data/dspaceFolder/bin/install_grobid.sh
@@ -83,14 +74,14 @@ jobs:
# (This artifact is downloadable at the bottom of any job's summary page)
- name: Upload Results of ${{ matrix.type }} to Artifact
if: ${{ failure() }}
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.type }} results
path: ${{ matrix.resultsdir }}
# Upload code coverage report to artifact, so that it can be shared with the 'codecov' job (see below)
- name: Upload code coverage report to Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: ${{ matrix.type }} coverage report
path: 'dspace/target/site/jacoco-aggregate/jacoco.xml'
@@ -105,11 +96,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# Download artifacts from previous 'tests' job
- name: Download coverage artifacts
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
# Now attempt upload to Codecov using its action.
# NOTE: We use a retry action to retry the Codecov upload if it fails the first time.
@@ -117,10 +108,14 @@ jobs:
# Retry action: https://github.com/marketplace/actions/retry-action
# Codecov action: https://github.com/codecov/codecov-action
- name: Upload coverage to Codecov.io
- uses: Wandalen/wretry.action@v1.0.36
+ uses: Wandalen/wretry.action@v1.3.0
with:
- action: codecov/codecov-action@v3
- # Try upload 5 times max
+ action: codecov/codecov-action@v4
+ # Ensure codecov-action throws an error when it fails to upload
+ with: |
+ fail_ci_if_error: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+ # Try re-running action 5 times max
attempt_limit: 5
# Run again in 30 seconds
attempt_delay: 30000
diff --git a/.github/workflows/codescan.yml b/.github/workflows/codescan.yml
index 9e6dcc0b23af..1e3d835e2713 100644
--- a/.github/workflows/codescan.yml
+++ b/.github/workflows/codescan.yml
@@ -35,11 +35,11 @@ jobs:
steps:
# https://github.com/actions/checkout
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
# https://github.com/actions/setup-java
- name: Install JDK
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: 11
distribution: 'temurin'
diff --git a/.github/workflows/issue_opened.yml b/.github/workflows/issue_opened.yml
index b4436dca3aad..0a35a6a95044 100644
--- a/.github/workflows/issue_opened.yml
+++ b/.github/workflows/issue_opened.yml
@@ -16,7 +16,7 @@ jobs:
# Only add to project board if issue is flagged as "needs triage" or has no labels
# NOTE: By default we flag new issues as "needs triage" in our issue template
if: (contains(github.event.issue.labels.*.name, 'needs triage') || join(github.event.issue.labels.*.name) == '')
- uses: actions/add-to-project@v0.5.0
+ uses: actions/add-to-project@v1.0.0
# Note, the authentication token below is an ORG level Secret.
# It must be created/recreated manually via a personal access token with admin:org, project, public_repo permissions
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token
diff --git a/.github/workflows/port_merged_pull_request.yml b/.github/workflows/port_merged_pull_request.yml
index 109835d14d3c..857f22755e49 100644
--- a/.github/workflows/port_merged_pull_request.yml
+++ b/.github/workflows/port_merged_pull_request.yml
@@ -23,11 +23,11 @@ jobs:
if: github.event.pull_request.merged
steps:
# Checkout code
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
# Port PR to other branch (ONLY if labeled with "port to")
# See https://github.com/korthout/backport-action
- name: Create backport pull requests
- uses: korthout/backport-action@v1
+ uses: korthout/backport-action@v2
with:
# Trigger based on a "port to [branch]" label on PR
# (This label must specify the branch name to port to)
diff --git a/.github/workflows/pull_request_opened.yml b/.github/workflows/pull_request_opened.yml
index 9b61af72d187..bbac52af2438 100644
--- a/.github/workflows/pull_request_opened.yml
+++ b/.github/workflows/pull_request_opened.yml
@@ -21,4 +21,4 @@ jobs:
# Assign the PR to whomever created it. This is useful for visualizing assignments on project boards
# See https://github.com/toshimaru/auto-author-assign
- name: Assign PR to creator
- uses: toshimaru/auto-author-assign@v1.6.2
+ uses: toshimaru/auto-author-assign@v2.1.0
diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml
new file mode 100644
index 000000000000..12aa0cfe2864
--- /dev/null
+++ b/.github/workflows/reusable-docker-build.yml
@@ -0,0 +1,235 @@
+#
+# DSpace's reusable Docker build/push workflow.
+#
+# This is used by docker.yml for all Docker image builds
+name: Reusable DSpace Docker Build
+
+on:
+ workflow_call:
+ # Possible Inputs to this reusable job
+ inputs:
+ # Build name/id for this Docker build. Used for digest storage to avoid digest overlap between builds.
+ build_id:
+ required: true
+ type: string
+ # Requires the image name to build (e.g dspace/dspace-test)
+ image_name:
+ required: true
+ type: string
+ # Optionally the path to the Dockerfile to use for the build. (Default is [dockerfile_context]/Dockerfile)
+ dockerfile_path:
+ required: false
+ type: string
+ # Optionally the context directory to build the Dockerfile within. Defaults to "." (current directory)
+ dockerfile_context:
+ required: false
+ type: string
+ default: '.'
+ # Optionally a list of "additional_contexts" to pass to Dockerfile. Defaults to empty
+ dockerfile_additional_contexts:
+ required: false
+ type: string
+ default: ''
+ # If Docker image should have additional tag flavor details (e.g. a suffix), it may be passed in.
+ tags_flavor:
+ required: false
+ type: string
+ secrets:
+ # Requires that Docker login info be passed in as secrets.
+ DOCKER_USERNAME:
+ required: true
+ DOCKER_ACCESS_TOKEN:
+ required: true
+ # These URL secrets are optional. When specified & branch checks match, the redeployment code below will trigger.
+ # Therefore builds which need to trigger redeployment MUST specify these URLs. All others should leave them empty.
+ REDEPLOY_SANDBOX_URL:
+ required: false
+ REDEPLOY_DEMO_URL:
+ required: false
+
+# Define shared default settings as environment variables
+env:
+ IMAGE_NAME: ${{ inputs.image_name }}
+ # Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
+ # For a new commit on default branch (main), use the literal tag 'latest' on Docker image.
+ # For a new commit on other branches, use the branch name as the tag for Docker image.
+ # For a new tag, copy that tag name as the tag for Docker image.
+ IMAGE_TAGS: |
+ type=raw,value=latest,enable=${{ github.ref_name == github.event.repository.default_branch }}
+ type=ref,event=branch,enable=${{ github.ref_name != github.event.repository.default_branch }}
+ type=ref,event=tag
+ # Define default tag "flavor" for docker/metadata-action per
+ # https://github.com/docker/metadata-action#flavor-input
+ # We manage the 'latest' tag ourselves to the 'main' branch (see settings above)
+ TAGS_FLAVOR: |
+ latest=false
+ ${{ inputs.tags_flavor }}
+ # When these URL variables are specified & required branch matches, then the sandbox or demo site will be redeployed.
+ # See "Redeploy" steps below for more details.
+ REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }}
+ REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }}
+ # Current DSpace maintenance branch (and architecture) which is deployed to demo.dspace.org / sandbox.dspace.org
+ # (NOTE: No deployment branch specified for sandbox.dspace.org as it uses the default_branch)
+ DEPLOY_DEMO_BRANCH: 'dspace-8_x'
+ DEPLOY_ARCH: 'linux/amd64'
+
+jobs:
+ docker-build:
+
+ strategy:
+ matrix:
+ # Architectures / Platforms for which we will build Docker images
+ arch: [ 'linux/amd64', 'linux/arm64' ]
+ os: [ ubuntu-latest ]
+ isPr:
+ - ${{ 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.
+ # The below exclude therefore ensures we do NOT build ARM64 for PRs.
+ exclude:
+ - isPr: true
+ os: ubuntu-latest
+ arch: linux/arm64
+
+ runs-on: ${{ matrix.os }}
+
+ steps:
+ # This step converts the slashes in the "arch" matrix values above into dashes & saves to env.ARCH_NAME
+ # E.g. "linux/amd64" becomes "linux-amd64"
+ # This is necessary because all upload artifacts CANNOT have special chars (like slashes)
+ - name: Prepare
+ run: |
+ platform=${{ matrix.arch }}
+ echo "ARCH_NAME=${platform//\//-}" >> $GITHUB_ENV
+
+ # https://github.com/actions/checkout
+ - name: Checkout codebase
+ uses: actions/checkout@v4
+
+ # https://github.com/docker/setup-buildx-action
+ - name: Setup Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ # 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/login-action
+ - name: Login to DockerHub
+ # Only login if not a PR, as PRs only trigger a Docker build and not a push
+ if: ${{ ! matrix.isPr }}
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
+
+ # https://github.com/docker/metadata-action
+ # Get Metadata for docker_build_deps step below
+ - name: Sync metadata (tags, labels) from GitHub to Docker for image
+ id: meta_build
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.IMAGE_NAME }}
+ tags: ${{ env.IMAGE_TAGS }}
+ flavor: ${{ env.TAGS_FLAVOR }}
+
+ # https://github.com/docker/build-push-action
+ - name: Build and push image
+ id: docker_build
+ uses: docker/build-push-action@v5
+ with:
+ build-contexts: |
+ ${{ inputs.dockerfile_additional_contexts }}
+ context: ${{ inputs.dockerfile_context }}
+ file: ${{ inputs.dockerfile_path }}
+ platforms: ${{ matrix.arch }}
+ # For pull requests, we run the Docker build (to ensure no PR changes break the build),
+ # but we ONLY do an image push to DockerHub if it's NOT a PR
+ push: ${{ ! matrix.isPr }}
+ # Use tags / labels provided by 'docker/metadata-action' above
+ tags: ${{ steps.meta_build.outputs.tags }}
+ labels: ${{ steps.meta_build.outputs.labels }}
+
+ # Export the digest of Docker build locally (for non PRs only)
+ - name: Export Docker build digest
+ if: ${{ ! matrix.isPr }}
+ run: |
+ mkdir -p /tmp/digests
+ digest="${{ steps.docker_build.outputs.digest }}"
+ touch "/tmp/digests/${digest#sha256:}"
+
+ # Upload digest to an artifact, so that it can be used in manifest below
+ - name: Upload Docker build digest to artifact
+ if: ${{ ! matrix.isPr }}
+ uses: actions/upload-artifact@v4
+ with:
+ name: digests-${{ inputs.build_id }}-${{ env.ARCH_NAME }}
+ path: /tmp/digests/*
+ if-no-files-found: error
+ retention-days: 1
+
+ # If this build is NOT a PR and passed in a REDEPLOY_SANDBOX_URL secret,
+ # Then redeploy https://sandbox.dspace.org if this build is for our deployment architecture and 'main' branch.
+ - name: Redeploy sandbox.dspace.org (based on main branch)
+ if: |
+ !matrix.isPR &&
+ env.REDEPLOY_SANDBOX_URL != '' &&
+ matrix.arch == env.DEPLOY_ARCH &&
+ github.ref_name == github.event.repository.default_branch
+ run: |
+ curl -X POST $REDEPLOY_SANDBOX_URL
+
+ # If this build is NOT a PR and passed in a REDEPLOY_DEMO_URL secret,
+ # Then redeploy https://demo.dspace.org if this build is for our deployment architecture and demo branch.
+ - name: Redeploy demo.dspace.org (based on maintenance branch)
+ if: |
+ !matrix.isPR &&
+ env.REDEPLOY_DEMO_URL != '' &&
+ matrix.arch == env.DEPLOY_ARCH &&
+ github.ref_name == env.DEPLOY_DEMO_BRANCH
+ run: |
+ curl -X POST $REDEPLOY_DEMO_URL
+
+ # Merge Docker digests (from various architectures) into a manifest.
+ # This runs after all Docker builds complete above, and it tells hub.docker.com
+ # that these builds should be all included in the manifest for this tag.
+ # (e.g. AMD64 and ARM64 should be listed as options under the same tagged Docker image)
+ docker-build_manifest:
+ if: ${{ github.event_name != 'pull_request' }}
+ runs-on: ubuntu-latest
+ needs:
+ - docker-build
+ steps:
+ - name: Download Docker build digests
+ uses: actions/download-artifact@v4
+ with:
+ path: /tmp/digests
+ # Download digests for both AMD64 and ARM64 into same directory
+ pattern: digests-${{ inputs.build_id }}-*
+ merge-multiple: true
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Add Docker metadata for image
+ id: meta
+ uses: docker/metadata-action@v5
+ with:
+ images: ${{ env.IMAGE_NAME }}
+ tags: ${{ env.IMAGE_TAGS }}
+ flavor: ${{ env.TAGS_FLAVOR }}
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
+
+ - name: Create manifest list from digests and push
+ working-directory: /tmp/digests
+ run: |
+ docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
+ $(printf '${{ env.IMAGE_NAME }}@sha256:%s ' *)
+
+ - name: Inspect image
+ run: |
+ docker buildx imagetools inspect ${{ env.IMAGE_NAME }}:${{ steps.meta.outputs.version }}
diff --git a/Dockerfile b/Dockerfile
index 9c32ecb50cd4..ee48dec5083c 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -20,12 +20,15 @@ USER dspace
ADD --chown=dspace . /app/
# Build DSpace (note: this build doesn't include the optional, deprecated "dspace-rest" webapp)
# Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
-RUN mvn --no-transfer-progress package && \
+# Maven flags here ensure that we skip building test environment and skip all code verification checks.
+# These flags speed up this compilation as much as reasonably possible.
+ENV MAVEN_FLAGS="-P-test-environment -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true"
+RUN mvn --no-transfer-progress package ${MAVEN_FLAGS} && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
-FROM openjdk:${JDK_VERSION}-slim as ant_build
+FROM eclipse-temurin:${JDK_VERSION} as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
diff --git a/Dockerfile.cli b/Dockerfile.cli
index 62e83b79ef02..53040a2fad89 100644
--- a/Dockerfile.cli
+++ b/Dockerfile.cli
@@ -24,7 +24,7 @@ RUN mvn --no-transfer-progress package && \
mvn clean
# Step 2 - Run Ant Deploy
-FROM openjdk:${JDK_VERSION}-slim as ant_build
+FROM eclipse-temurin:${JDK_VERSION} as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
@@ -33,9 +33,9 @@ WORKDIR /dspace-src
ENV ANT_VERSION 1.10.13
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
-# Need wget to install ant, and unzip for managing AIPs
+# Need wget to install ant
RUN apt-get update \
- && apt-get install -y --no-install-recommends wget unzip \
+ && apt-get install -y --no-install-recommends wget \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
# Download and install 'ant'
@@ -45,10 +45,15 @@ RUN mkdir $ANT_HOME && \
RUN ant init_installation update_configs update_code
# Step 3 - Run jdk
-FROM openjdk:${JDK_VERSION}
+FROM eclipse-temurin:${JDK_VERSION}
# NOTE: DSPACE_INSTALL must align with the "dspace.dir" default configuration.
ENV DSPACE_INSTALL=/dspace
# Copy the /dspace directory from 'ant_build' container to /dspace in this container
COPY --from=ant_build /dspace $DSPACE_INSTALL
# Give java extra memory (1GB)
ENV JAVA_OPTS=-Xmx1000m
+# Install unzip for AIPs
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends unzip \
+ && apt-get purge -y --auto-remove \
+ && rm -rf /var/lib/apt/lists/*
diff --git a/Dockerfile.dependencies b/Dockerfile.dependencies
index a55b323339dc..1400b356d418 100644
--- a/Dockerfile.dependencies
+++ b/Dockerfile.dependencies
@@ -7,7 +7,7 @@
ARG JDK_VERSION=11
# Step 1 - Run Maven Build
-FROM maven:3-openjdk-${JDK_VERSION}-slim as build
+FROM maven:3-eclipse-temurin-${JDK_VERSION} as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# Create the 'dspace' user account & home directory
@@ -15,11 +15,6 @@ RUN useradd dspace \
&& mkdir -p /home/dspace \
&& chown -Rv dspace: /home/dspace
RUN chown -Rv dspace: /app
-# Need git to support buildnumber-maven-plugin, which lets us know what version of DSpace is being run.
-RUN apt-get update \
- && apt-get install -y --no-install-recommends git \
- && apt-get purge -y --auto-remove \
- && rm -rf /var/lib/apt/lists/*
# Switch to dspace user & run below commands as that user
USER dspace
@@ -28,7 +23,10 @@ USER dspace
ADD --chown=dspace . /app/
# Trigger the installation of all maven dependencies (hide download progress messages)
-RUN mvn --no-transfer-progress package
+# Maven flags here ensure that we skip final assembly, skip building test environment and skip all code verification checks.
+# These flags speed up this installation as much as reasonably possible.
+ENV MAVEN_FLAGS="-P-assembly -P-test-environment -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true"
+RUN mvn --no-transfer-progress install ${MAVEN_FLAGS}
# Clear the contents of the /app directory (including all maven builds), so no artifacts remain.
# This ensures when dspace:dspace is built, it will use the Maven local cache (~/.m2) for dependencies
diff --git a/Dockerfile.test b/Dockerfile.test
index 4e9b2b5b4343..f6f8c1a290f9 100644
--- a/Dockerfile.test
+++ b/Dockerfile.test
@@ -27,7 +27,7 @@ RUN mvn --no-transfer-progress package -Pdspace-rest && \
mvn clean
# Step 2 - Run Ant Deploy
-FROM openjdk:${JDK_VERSION}-slim as ant_build
+FROM eclipse-temurin:${JDK_VERSION} as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
diff --git a/LICENSES_THIRD_PARTY b/LICENSES_THIRD_PARTY
index e494c80c5d6e..791009e4c3ae 100644
--- a/LICENSES_THIRD_PARTY
+++ b/LICENSES_THIRD_PARTY
@@ -26,24 +26,23 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.261 - https://aws.amazon.com/sdkforjava)
* JMES Path Query library (com.amazonaws:jmespath-java:1.12.261 - https://aws.amazon.com/sdkforjava)
* HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc)
- * com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.18.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)
- * Esri Geometry API for Java (com.esri.geometry:esri-geometry-api:2.2.0 - https://github.com/Esri/geometry-api-java)
- * ClassMate (com.fasterxml:classmate:1.3.0 - http://github.com/cowtowncoder/java-classmate)
- * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.13.4 - http://github.com/FasterXML/jackson)
- * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.13.4 - https://github.com/FasterXML/jackson-core)
- * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.13.4.2 - http://github.com/FasterXML/jackson)
+ * ClassMate (com.fasterxml:classmate:1.6.0 - https://github.com/FasterXML/java-classmate)
+ * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.16.0 - https://github.com/FasterXML/jackson)
+ * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.16.0 - https://github.com/FasterXML/jackson-core)
+ * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.16.0 - https://github.com/FasterXML/jackson)
* Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.6 - http://github.com/FasterXML/jackson-dataformats-binary)
- * Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.13.3 - http://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-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.1 - https://github.com/FasterXML/jackson-dataformats-text)
* Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8)
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.1 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.5 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
* Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.5 - 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)
- * Woodstox (com.fasterxml.woodstox:woodstox-core:6.2.4 - https://github.com/FasterXML/woodstox)
- * zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.6 - https://github.com/flipkart-incubator/zjsonpatch/)
- * Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.2 - https://github.com/ben-manes/caffeine)
+ * 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/)
+ * Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.3 - https://github.com/ben-manes/caffeine)
* 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-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
@@ -54,7 +53,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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.1 - 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.9.0 - https://github.com/google/gson/gson)
* error-prone annotations (com.google.errorprone:error_prone_annotations:2.18.0 - https://errorprone.info/error_prone_annotations)
* Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
@@ -64,25 +63,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* 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)
* 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: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)
* libphonenumber (com.googlecode.libphonenumber:libphonenumber:8.11.1 - https://github.com/google/libphonenumber/)
- * Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.2 - https://jackcess.sourceforge.io)
- * Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.1 - http://jackcessencrypt.sf.net)
- * project ':json-path' (com.jayway.jsonpath:json-path:2.6.0 - https://github.com/jayway/JsonPath)
- * project ':json-path-assert' (com.jayway.jsonpath:json-path-assert:2.6.0 - https://github.com/jayway/JsonPath)
+ * Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.5 - https://jackcess.sourceforge.io)
+ * 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-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)
- * builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons)
- * MaxMind DB Reader (com.maxmind.db:maxmind-db:1.2.2 - http://dev.maxmind.com/)
- * MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.11.0 - http://dev.maxmind.com/geoip/geoip2/web-services)
+ * 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)
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:7.9 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
- * opencsv (com.opencsv:opencsv:5.6 - http://opencsv.sf.net)
+ * opencsv (com.opencsv:opencsv:5.9 - http://opencsv.sf.net)
* 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-modules (com.rometools:rome-modules:1.19.0 - http://rometools.com/rome-modules)
* rome-utils (com.rometools:rome-utils:1.19.0 - http://rometools.com/rome-utils)
- * fastinfoset (com.sun.xml.fastinfoset:FastInfoset:1.2.15 - http://fi.java.net)
* T-Digest (com.tdunning:t-digest:3.1 - https://github.com/tdunning/t-digest)
* config (com.typesafe:config:1.3.3 - https://github.com/lightbend/config)
* ssl-config-core (com.typesafe:ssl-config-core_2.13:0.3.8 - https://github.com/lightbend/ssl-config)
@@ -94,17 +92,17 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* akka-stream (com.typesafe.akka:akka-stream_2.13:2.5.31 - https://akka.io/)
* 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)
- * SparseBitSet (com.zaxxer:SparseBitSet:1.2 - 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 CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
- * Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/)
+ * Apache Commons CLI (commons-cli:commons-cli:1.6.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 Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/)
- * Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/)
+ * Commons Digester (commons-digester:commons-digester:2.1 - http://commons.apache.org/digester/)
* Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.5 - https://commons.apache.org/proper/commons-fileupload/)
- * Apache Commons IO (commons-io:commons-io:2.7 - https://commons.apache.org/proper/commons-io/)
+ * Apache Commons IO (commons-io:commons-io:2.15.1 - https://commons.apache.org/proper/commons-io/)
* Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/)
- * Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
- * Apache Commons Validator (commons-validator:commons-validator:1.5.0 - http://commons.apache.org/proper/commons-validator/)
+ * Apache Commons Logging (commons-logging:commons-logging:1.3.0 - https://commons.apache.org/proper/commons-logging/)
+ * Apache Commons Validator (commons-validator:commons-validator:1.7 - 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)
* 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)
@@ -112,18 +110,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* JVM Integration for Metrics (io.dropwizard.metrics:metrics-jvm:4.1.5 - https://metrics.dropwizard.io/metrics-jvm)
- * micrometer-core (io.micrometer:micrometer-core:1.9.11 - https://github.com/micrometer-metrics/micrometer)
- * Netty/Buffer (io.netty:netty-buffer:4.1.68.Final - https://netty.io/netty-buffer/)
- * Netty/Codec (io.netty:netty-codec:4.1.68.Final - https://netty.io/netty-codec/)
+ * micrometer-core (io.micrometer:micrometer-core:1.9.17 - 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/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/HTTP (io.netty:netty-codec-http:4.1.53.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/Common (io.netty:netty-common:4.1.68.Final - https://netty.io/netty-common/)
- * Netty/Handler (io.netty:netty-handler:4.1.68.Final - https://netty.io/netty-handler/)
+ * Netty/Common (io.netty:netty-common:4.1.106.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/Proxy (io.netty:netty-handler-proxy:4.1.53.Final - https://netty.io/netty-handler-proxy/)
- * Netty/Resolver (io.netty:netty-resolver:4.1.68.Final - https://netty.io/netty-resolver/)
- * Netty/Transport (io.netty:netty-transport:4.1.68.Final - https://netty.io/netty-transport/)
- * Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.68.Final - https://netty.io/netty-transport-native-epoll/)
- * Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.68.Final - https://netty.io/netty-transport-native-unix-common/)
+ * 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/Transport (io.netty:netty-transport:4.1.99.Final - https://netty.io/netty-transport/)
+ * 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/)
* 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-util (io.opentracing:opentracing-util:0.33.0 - https://github.com/opentracing/opentracing-java/opentracing-util)
@@ -141,52 +145,57 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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-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)
* Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:2.0.2 - https://beanvalidation.org)
- * JSR107 API and SPI (javax.cache:cache-api:1.1.0 - 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:2.0.1.Final - http://beanvalidation.org)
* jdbm (jdbm:jdbm:1.0 - no url defined)
- * Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/)
+ * Joda-Time (joda-time:joda-time:2.12.5 - https://www.joda.org/joda-time/)
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy)
* 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)
* json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.19.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/)
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/)
- * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.4.7 - https://urielch.github.io/)
+ * ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.0 - https://urielch.github.io/)
* JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/)
- * JSON Small and Fast Parser (net.minidev:json-smart:2.4.7 - https://urielch.github.io/)
+ * JSON Small and Fast Parser (net.minidev:json-smart:2.5.0 - https://urielch.github.io/)
* 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)
- * Apache Ant Core (org.apache.ant:ant:1.10.11 - https://ant.apache.org/)
- * Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.11 - https://ant.apache.org/)
- * Apache Commons BCEL (org.apache.bcel:bcel:6.6.0 - https://commons.apache.org/proper/commons-bcel)
- * Calcite Core (org.apache.calcite:calcite-core:1.27.0 - https://calcite.apache.org)
- * Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.27.0 - https://calcite.apache.org)
- * Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.18.0 - https://calcite.apache.org/avatica)
- * Apache Commons Collections (org.apache.commons:commons-collections4:4.1 - http://commons.apache.org/proper/commons-collections/)
- * Apache Commons Compress (org.apache.commons:commons-compress:1.21 - https://commons.apache.org/proper/commons-compress/)
- * Apache Commons Configuration (org.apache.commons:commons-configuration2:2.8.0 - https://commons.apache.org/proper/commons-configuration/)
- * Apache Commons CSV (org.apache.commons:commons-csv:1.9.0 - https://commons.apache.org/proper/commons-csv/)
- * Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.9.0 - https://commons.apache.org/dbcp/)
+ * Apache Ant Core (org.apache.ant:ant:1.10.14 - https://ant.apache.org/)
+ * Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.14 - https://ant.apache.org/)
+ * Apache Commons BCEL (org.apache.bcel:bcel:6.7.0 - https://commons.apache.org/proper/commons-bcel)
+ * 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)
+ * 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 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 Configuration (org.apache.commons:commons-configuration2:2.10.1 - 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 DBCP (org.apache.commons:commons-dbcp2:2.11.0 - https://commons.apache.org/dbcp/)
* Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/)
- * Apache Commons Lang (org.apache.commons:commons-lang3:3.12.0 - https://commons.apache.org/proper/commons-lang/)
+ * 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 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.11.1 - https://commons.apache.org/proper/commons-pool/)
+ * Apache Commons Pool (org.apache.commons:commons-pool2:2.12.0 - 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)
* 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 Recipes (org.apache.curator:curator-recipes:2.13.0 - http://curator.apache.org/curator-recipes)
- * Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:3.2.2 - no url defined)
- * Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:3.2.2 - no url defined)
- * Apache Hadoop Common (org.apache.hadoop:hadoop-common:3.2.2 - no url defined)
- * Apache Hadoop HDFS Client (org.apache.hadoop:hadoop-hdfs-client:3.2.2 - no url defined)
+ * Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:3.2.4 - no url defined)
+ * Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:3.2.4 - no url defined)
+ * Apache Hadoop Common (org.apache.hadoop:hadoop-common:3.2.4 - no url defined)
+ * Apache Hadoop HDFS Client (org.apache.hadoop:hadoop-hdfs-client:3.2.4 - no url defined)
* htrace-core4 (org.apache.htrace:htrace-core4:4.1.0-incubating - http://incubator.apache.org/projects/htrace.html)
- * Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.13 - http://hc.apache.org/httpcomponents-client)
+ * Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.14 - http://hc.apache.org/httpcomponents-client-ga)
* Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client)
- * Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.15 - http://hc.apache.org/httpcomponents-core-ga)
- * Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.13 - http://hc.apache.org/httpcomponents-client)
- * Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.4 - http://james.apache.org/mime4j/apache-mime4j-core)
- * Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.4 - http://james.apache.org/mime4j/apache-mime4j-dom)
+ * 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 (org.apache.httpcomponents.client5:httpclient5:5.1.3 - https://hc.apache.org/httpcomponents-client-5.0.x/5.1.3/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/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 James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.10 - 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 Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/)
* Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/)
* Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/)
@@ -196,86 +205,86 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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 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.20.0 - https://logging.apache.org/log4j/2.x/log4j-1.2-api/)
- * Apache Log4j API (org.apache.logging.log4j:log4j-api:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-api/)
- * Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-core/)
- * Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-jul/)
- * Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/)
- * Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/)
- * Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.20.0 - https://logging.apache.org/log4j/2.x/log4j-web/)
- * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common)
- * Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
- * Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
- * Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori)
- * Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
- * Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
- * Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
- * Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs)
- * Lucene Classification (org.apache.lucene:lucene-classification:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-classification)
- * Lucene codecs (org.apache.lucene:lucene-codecs:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-codecs)
- * Lucene Core (org.apache.lucene:lucene-core:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-core)
- * Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-expressions)
- * Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-grouping)
- * Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-highlighter)
- * Lucene Join (org.apache.lucene:lucene-join:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-join)
- * Lucene Memory (org.apache.lucene:lucene-memory:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-memory)
- * Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-misc)
- * Lucene Queries (org.apache.lucene:lucene-queries:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-queries)
- * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-queryparser)
- * Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-sandbox)
- * Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras)
- * Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-spatial3d)
- * Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.2 - https://lucene.apache.org/lucene-parent/lucene-suggest)
- * Apache FontBox (org.apache.pdfbox:fontbox:2.0.28 - http://pdfbox.apache.org/)
+ * 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 API (org.apache.logging.log4j:log4j-api:2.23.1 - 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 JUL Adapter (org.apache.logging.log4j:log4j-jul:2.23.1 - 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 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 Web (org.apache.logging.log4j:log4j-web:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-web/)
+ * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.3 - 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 Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.3 - 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 Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.3 - 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 Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.3 - 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 Classification (org.apache.lucene:lucene-classification:8.11.3 - 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 Core (org.apache.lucene:lucene-core:8.11.3 - 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 Grouping (org.apache.lucene:lucene-grouping:8.11.3 - 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 Join (org.apache.lucene:lucene-join:8.11.3 - 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 Miscellaneous (org.apache.lucene:lucene-misc:8.11.3 - 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 QueryParsers (org.apache.lucene:lucene-queryparser:8.11.3 - 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 Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.3 - 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 Suggest (org.apache.lucene:lucene-suggest:8.11.3 - https://lucene.apache.org/lucene-parent/lucene-suggest)
+ * Apache FontBox (org.apache.pdfbox:fontbox:2.0.31 - http://pdfbox.apache.org/)
* 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 PDFBox (org.apache.pdfbox:pdfbox:2.0.28 - https://www.apache.org/pdfbox-parent/pdfbox/)
- * Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.27 - https://www.apache.org/pdfbox-parent/pdfbox-tools/)
- * Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.27 - https://www.apache.org/pdfbox-parent/xmpbox/)
- * Apache POI - Common (org.apache.poi:poi:5.2.3 - https://poi.apache.org/)
- * Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.2.3 - https://poi.apache.org/)
- * Apache POI (org.apache.poi:poi-ooxml-lite:5.2.3 - https://poi.apache.org/)
- * Apache POI (org.apache.poi:poi-scratchpad:5.2.3 - https://poi.apache.org/)
- * Apache Solr Core (org.apache.solr:solr-core:8.11.2 - https://lucene.apache.org/solr-parent/solr-core)
- * Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.2 - https://lucene.apache.org/solr-parent/solr-solrj)
+ * Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.31 - 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 XmpBox (org.apache.pdfbox:xmpbox:2.0.31 - https://www.apache.org/pdfbox-parent/xmpbox/)
+ * Apache POI - Common (org.apache.poi:poi:5.2.5 - 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 (org.apache.poi:poi-ooxml-lite:5.2.5 - https://poi.apache.org/)
+ * Apache POI (org.apache.poi:poi-scratchpad:5.2.5 - https://poi.apache.org/)
+ * Apache Solr Core (org.apache.solr:solr-core:8.11.3 - https://lucene.apache.org/solr-parent/solr-core)
+ * Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.3 - 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 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.9.2 - http://thrift.apache.org)
- * Apache Tika core (org.apache.tika:tika-core:2.5.0 - https://tika.apache.org/)
- * Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.5.0 - https://tika.apache.org/tika-parser-apple-module/)
- * Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.5.0 - https://tika.apache.org/tika-parser-audiovideo-module/)
- * Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.5.0 - https://tika.apache.org/tika-parser-cad-module/)
- * Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.5.0 - https://tika.apache.org/tika-parser-code-module/)
- * Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.5.0 - https://tika.apache.org/tika-parser-crypto-module/)
- * Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.5.0 - https://tika.apache.org/tika-parser-digest-commons/)
- * Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.5.0 - https://tika.apache.org/tika-parser-font-module/)
- * Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.5.0 - https://tika.apache.org/tika-parser-html-module/)
- * Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.5.0 - https://tika.apache.org/tika-parser-image-module/)
- * Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.5.0 - https://tika.apache.org/tika-parser-mail-commons/)
- * Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.5.0 - https://tika.apache.org/tika-parser-mail-module/)
- * Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.5.0 - https://tika.apache.org/tika-parser-microsoft-module/)
- * Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.5.0 - https://tika.apache.org/tika-parser-miscoffice-module/)
- * Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.5.0 - https://tika.apache.org/tika-parser-news-module/)
- * Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.5.0 - https://tika.apache.org/tika-parser-ocr-module/)
- * Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.5.0 - https://tika.apache.org/tika-parser-pdf-module/)
- * Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.5.0 - https://tika.apache.org/tika-parser-pkg-module/)
- * Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.5.0 - https://tika.apache.org/tika-parser-text-module/)
- * Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.5.0 - https://tika.apache.org/tika-parser-webarchive-module/)
- * Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.5.0 - https://tika.apache.org/tika-parser-xml-module/)
- * Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.5.0 - https://tika.apache.org/tika-parser-xmp-commons/)
- * Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.5.0 - https://tika.apache.org/tika-parser-zip-commons/)
- * Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.5.0 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/)
- * tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.75 - https://tomcat.apache.org/)
- * tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.75 - https://tomcat.apache.org/)
- * tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.75 - https://tomcat.apache.org/)
+ * Apache Tika core (org.apache.tika:tika-core:2.9.2 - 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 audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.9.2 - 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 code parser module (org.apache.tika:tika-parser-code-module:2.9.2 - 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 digest commons (org.apache.tika:tika-parser-digest-commons:2.9.2 - 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 html parser module (org.apache.tika:tika-parser-html-module:2.9.2 - 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 mail commons (org.apache.tika:tika-parser-mail-commons:2.9.2 - 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 Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.9.2 - 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 news parser module (org.apache.tika:tika-parser-news-module:2.9.2 - 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 PDF parser module (org.apache.tika:tika-parser-pdf-module:2.9.2 - 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 text parser module (org.apache.tika:tika-parser-text-module:2.9.2 - 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 XML parser module (org.apache.tika:tika-parser-xml-module:2.9.2 - 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 ZIP commons (org.apache.tika:tika-parser-zip-commons:2.9.2 - 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/)
+ * tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.83 - https://tomcat.apache.org/)
+ * tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.83 - https://tomcat.apache.org/)
+ * tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.83 - 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 - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.2 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/)
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.22 - http://ws.apache.org/axiom/)
* Abdera Model (FOM) Implementation (org.apache.ws.commons.axiom:fom-impl:1.2.22 - http://ws.apache.org/axiom/implementations/fom-impl/)
- * XmlBeans (org.apache.xmlbeans:xmlbeans:5.1.1 - https://xmlbeans.apache.org/)
+ * XmlBeans (org.apache.xmlbeans:xmlbeans:5.2.0 - https://xmlbeans.apache.org/)
* 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)
- * org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.0 - https://github.com/apiguardian-team/apiguardian)
+ * org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.2 - https://github.com/apiguardian-team/apiguardian)
* AssertJ fluent assertions (org.assertj:assertj-core:3.22.0 - https://assertj.github.io/doc/assertj-core/)
* Evo Inflector (org.atteo:evo-inflector:1.3 - http://atteo.org/static/evo-inflector)
* jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/)
@@ -284,49 +293,50 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/)
- * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client)
- * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client)
- * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server)
- * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
- * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
+ * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client)
+ * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client)
+ * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server)
+ * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
+ * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
* Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty)
- * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-client)
- * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-continuation)
- * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-continuation)
- * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-deploy)
- * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-http)
- * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-io)
- * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-jmx)
+ * 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.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
+ * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-continuation)
+ * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy)
+ * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http)
+ * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io)
+ * 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 :: 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.44.v20210927 - https://eclipse.org/jetty/jetty-rewrite)
- * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-security)
- * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-security)
- * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-server)
- * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlet)
- * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlets)
- * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util)
- * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util-ajax)
- * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-webapp)
- * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-xml)
- * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-client)
- * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-common)
- * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-hpack)
- * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
- * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-server)
+ * 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.54.v20240208 - https://eclipse.org/jetty/jetty-security)
+ * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server)
+ * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet)
+ * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.54.v20240208 - 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 :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax)
+ * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp)
+ * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml)
+ * 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 :: 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 :: Server (org.eclipse.jetty.http2:http2-server:9.4.54.v20240208 - 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)
- * Ehcache (org.ehcache:ehcache:3.4.0 - http://ehcache.org)
- * flyway-core (org.flywaydb:flyway-core:8.4.4 - https://flywaydb.org/flyway-core)
+ * Ehcache (org.ehcache:ehcache:3.10.8 - http://ehcache.org)
+ * flyway-core (org.flywaydb:flyway-core:8.5.13 - https://flywaydb.org/flyway-core)
* 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)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:6.2.5.Final - http://hibernate.org/validator/hibernate-validator)
* Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:6.2.5.Final - http://hibernate.org/validator/hibernate-validator-cdi)
+ * 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-api (org.iq80.leveldb:leveldb-api:0.12 - http://github.com/dain/leveldb/leveldb-api)
- * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/)
+ * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/)
* Java Annotation Indexer (org.jboss:jandex:2.4.2.Final - http://www.jboss.org/jandex)
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.3.Final - http://www.jboss.org)
* JDOM (org.jdom:jdom2:2.0.6.1 - http://www.jdom.org)
@@ -335,6 +345,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* 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 Core (org.mock-server:mockserver-core:5.11.2 - http://www.mock-server.com)
@@ -346,12 +357,12 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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.19.0 - https://github.com/iipc/jwarc)
+ * jwarc (org.netpreserve:jwarc:0.29.0 - https://github.com/iipc/jwarc)
* Objenesis (org.objenesis:objenesis:3.2 - http://objenesis.org/objenesis)
* parboiled-core (org.parboiled:parboiled-core:1.3.1 - http://parboiled.org)
* parboiled-java (org.parboiled:parboiled-java:1.3.1 - http://parboiled.org)
* RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/)
- * Scala Library (org.scala-lang:scala-library:2.13.9 - https://www.scala-lang.org/)
+ * Scala Library (org.scala-lang:scala-library:2.13.11 - 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-java8-compat (org.scala-lang.modules:scala-java8-compat_2.13:0.9.0 - http://www.scala-lang.org/)
@@ -359,58 +370,55 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.36 - http://www.slf4j.org)
- * Spring AOP (org.springframework:spring-aop:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Beans (org.springframework:spring-beans:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Context (org.springframework:spring-context:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Context Support (org.springframework:spring-context-support:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Core (org.springframework:spring-core:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring JDBC (org.springframework:spring-jdbc:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Object/Relational Mapping (org.springframework:spring-orm:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring TestContext Framework (org.springframework:spring-test:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Transaction (org.springframework:spring-tx:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Web (org.springframework:spring-web:5.3.27 - https://github.com/spring-projects/spring-framework)
- * Spring Web MVC (org.springframework:spring-webmvc:5.3.27 - https://github.com/spring-projects/spring-framework)
- * spring-boot (org.springframework.boot:spring-boot:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-actuator (org.springframework.boot:spring-boot-actuator:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot)
+ * Spring AOP (org.springframework:spring-aop:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Beans (org.springframework:spring-beans:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Context (org.springframework:spring-context:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Context Support (org.springframework:spring-context-support:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Core (org.springframework:spring-core:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Expression Language (SpEL) (org.springframework:spring-expression:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Commons Logging Bridge (org.springframework:spring-jcl:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring JDBC (org.springframework:spring-jdbc:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Object/Relational Mapping (org.springframework:spring-orm:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring TestContext Framework (org.springframework:spring-test:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Transaction (org.springframework:spring-tx:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Web (org.springframework:spring-web:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * Spring Web MVC (org.springframework:spring-webmvc:5.3.34 - https://github.com/spring-projects/spring-framework)
+ * spring-boot (org.springframework.boot:spring-boot:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-actuator (org.springframework.boot:spring-boot-actuator:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:2.7.18 - 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-starter (org.springframework.boot:spring-boot-starter:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-test (org.springframework.boot:spring-boot-test:2.7.12 - https://spring.io/projects/spring-boot)
- * spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.7.12 - https://spring.io/projects/spring-boot)
- * Spring Data Core (org.springframework.data:spring-data-commons:2.7.12 - https://www.spring.io/spring-data/spring-data-commons)
- * Spring Data REST - Core (org.springframework.data:spring-data-rest-core:3.7.12 - 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:3.7.12 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
- * Spring HATEOAS (org.springframework.hateoas:spring-hateoas:1.5.4 - https://github.com/spring-projects/spring-hateoas)
+ * spring-boot-starter (org.springframework.boot:spring-boot-starter:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-test (org.springframework.boot:spring-boot-test:2.7.18 - https://spring.io/projects/spring-boot)
+ * spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:2.7.18 - https://spring.io/projects/spring-boot)
+ * Spring Data Core (org.springframework.data:spring-data-commons:2.7.18 - https://www.spring.io/spring-data/spring-data-commons)
+ * Spring Data REST - Core (org.springframework.data:spring-data-rest-core:3.7.18 - 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:3.7.18 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
+ * Spring HATEOAS (org.springframework.hateoas:spring-hateoas:1.5.6 - https://github.com/spring-projects/spring-hateoas)
* Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE - https://github.com/spring-projects/spring-plugin/spring-plugin-core)
- * spring-security-config (org.springframework.security:spring-security-config:5.7.8 - https://spring.io/projects/spring-security)
- * spring-security-core (org.springframework.security:spring-security-core:5.7.8 - https://spring.io/projects/spring-security)
- * spring-security-crypto (org.springframework.security:spring-security-crypto:5.7.8 - https://spring.io/projects/spring-security)
- * spring-security-test (org.springframework.security:spring-security-test:5.7.8 - https://spring.io/projects/spring-security)
- * spring-security-web (org.springframework.security:spring-security-web:5.7.8 - https://spring.io/projects/spring-security)
+ * spring-security-config (org.springframework.security:spring-security-config:5.7.11 - https://spring.io/projects/spring-security)
+ * spring-security-core (org.springframework.security:spring-security-core:5.7.11 - https://spring.io/projects/spring-security)
+ * spring-security-crypto (org.springframework.security:spring-security-crypto:5.7.11 - https://spring.io/projects/spring-security)
+ * spring-security-test (org.springframework.security:spring-security-test:5.7.11 - https://spring.io/projects/spring-security)
+ * spring-security-web (org.springframework.security:spring-security-web:5.7.11 - https://spring.io/projects/spring-security)
* SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/)
- * snappy-java (org.xerial.snappy:snappy-java:1.1.7.6 - 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/)
- * org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.8.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.8.0 - https://www.xmlunit.org/xmlunit-placeholders/)
* SnakeYAML (org.yaml:snakeyaml:1.30 - https://bitbucket.org/snakeyaml/snakeyaml)
* software.amazon.ion:ion-java (software.amazon.ion:ion-java:1.0.2 - https://github.com/amznlabs/ion-java/)
- * Xalan Java Serializer (xalan:serializer:2.7.2 - http://xml.apache.org/xalan-j/)
- * xalan (xalan:xalan:2.7.0 - no url defined)
- * Xalan Java (xalan:xalan:2.7.2 - http://xml.apache.org/xalan-j/)
* Xerces2-j (xerces:xercesImpl:2.12.2 - https://xerces.apache.org/xerces2-j/)
* XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/)
@@ -421,29 +429,28 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security)
* Java Advanced Imaging Image I/O Tools API core (standalone) (com.github.jai-imageio:jai-imageio-core:1.4.0 - https://github.com/jai-imageio/jai-imageio-core)
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
- * curvesapi (com.github.virtuald:curvesapi:1.07 - https://github.com/virtuald/curvesapi)
- * Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.11.0 - https://developers.google.com/protocol-buffers/protobuf-java/)
+ * 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/)
* JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/)
- * dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org)
- * jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/)
+ * dnsjava (dnsjava:dnsjava:2.1.9 - http://www.dnsjava.org)
+ * jaxen (jaxen:jaxen:2.0.0 - http://www.cafeconleche.org/jaxen/jaxen)
* ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.5.1-1 - http://www.antlr.org/antlr4-runtime)
- * commons-compiler (org.codehaus.janino:commons-compiler:3.0.9 - http://janino-compiler.github.io/commons-compiler/)
- * janino (org.codehaus.janino:janino:3.0.9 - http://janino-compiler.github.io/janino/)
+ * 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/)
* Stax2 API (org.codehaus.woodstox:stax2-api:4.2.1 - http://github.com/FasterXML/stax2-api)
- * Hamcrest Date (org.exparity:hamcrest-date:2.0.7 - https://github.com/exparity/hamcrest-date)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * Hamcrest Date (org.exparity:hamcrest-date:2.0.8 - https://github.com/exparity/hamcrest-date)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/)
- * Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
- * Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core)
+ * Hamcrest Core (org.hamcrest:hamcrest-core:2.2 - http://hamcrest.org/JavaHamcrest/)
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/)
* JBibTeX (org.jbibtex:jbibtex:1.0.20 - http://www.jbibtex.org)
* asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/)
* asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
- * asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/)
+ * asm-commons (org.ow2.asm:asm-commons:9.3 - http://asm.ow2.io/)
* asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
* asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
- * PostgreSQL JDBC Driver (org.postgresql:postgresql:42.6.0 - https://jdbc.postgresql.org)
+ * PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.3 - https://jdbc.postgresql.org)
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections)
* JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio)
* XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/)
@@ -454,12 +461,12 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Common Development and Distribution License (CDDL):
- * istack common utility code runtime (com.sun.istack:istack-commons-runtime:3.0.7 - http://java.net/istack-commons/istack-commons-runtime/)
* JavaMail API (com.sun.mail:javax.mail:1.6.2 - http://javaee.github.io/javamail/javax.mail)
* JavaMail API (no providers) (com.sun.mail:mailapi:1.6.2 - http://javaee.github.io/javamail/mailapi)
* Old JAXB Core (com.sun.xml.bind:jaxb-core:2.3.0.1 - http://jaxb.java.net/jaxb-bundles/jaxb-core)
* 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:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca)
+ * javax.transaction API (jakarta.transaction:jakarta.transaction-api:1.3.3 - https://projects.eclipse.org/projects/ee4j.jta)
* jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api)
* JavaBeans Activation Framework (JAF) (javax.activation:activation:1.1 - http://java.sun.com/products/javabeans/jaf/index.jsp)
* JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/)
@@ -474,12 +481,9 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject)
- * JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:2.3.1 - http://jaxb.java.net/jaxb-runtime-parent/jaxb-runtime)
- * TXW2 Runtime (org.glassfish.jaxb:txw2:2.3.1 - http://jaxb.java.net/jaxb-txw-parent/txw2)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final - http://www.jboss.org/jboss-transaction-api_1.2_spec)
- * Extended StAX API (org.jvnet.staxex:stax-ex:1.8 - http://stax-ex.java.net/)
Cordra (Version 2) License Agreement:
@@ -489,55 +493,62 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Eclipse Distribution License, Version 1.0:
+ * Jakarta Activation (com.sun.activation:jakarta.activation:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation)
+ * istack common utility code runtime (com.sun.istack:istack-commons-runtime:3.0.12 - https://projects.eclipse.org/projects/ee4j/istack-commons/istack-commons-runtime)
* Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api)
* Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api)
* javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:2.3.9 - https://eclipse-ee4j.github.io/jaxb-ri/)
+ * TXW2 Runtime (org.glassfish.jaxb:txw2:2.3.9 - https://eclipse-ee4j.github.io/jaxb-ri/)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final - http://hibernate.org)
+ * 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)
Eclipse Public License:
* System Rules (com.github.stefanbirkner:system-rules:1.19.0 - http://stefanbirkner.github.io/system-rules/)
- * H2 Database Engine (com.h2database:h2:2.1.210 - https://h2database.com)
+ * H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com)
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca)
+ * javax.transaction API (jakarta.transaction:jakarta.transaction-api:1.3.3 - https://projects.eclipse.org/projects/ee4j.jta)
* jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api)
* javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec)
- * JUnit (junit:junit:4.13.1 - http://junit.org)
+ * JUnit (junit:junit:4.13.2 - http://junit.org)
* AspectJ Weaver (org.aspectj:aspectjweaver:1.9.7 - https://www.eclipse.org/aspectj/)
* Eclipse Compiler for Java(TM) (org.eclipse.jdt:ecj:3.14.0 - http://www.eclipse.org/jdt)
* 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/)
- * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client)
- * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client)
- * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server)
- * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
- * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
+ * Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client)
+ * Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client)
+ * Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server)
+ * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
+ * Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
* Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty)
- * Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-client)
- * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-continuation)
- * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-continuation)
- * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-deploy)
- * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-http)
- * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-io)
- * Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-jmx)
+ * 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.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
+ * Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-continuation)
+ * Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-deploy)
+ * Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-http)
+ * Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-io)
+ * 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 :: 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.44.v20210927 - https://eclipse.org/jetty/jetty-rewrite)
- * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.44.v20210927 - https://eclipse.org/jetty/jetty-security)
- * Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-security)
- * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-server)
- * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlet)
- * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-servlets)
- * Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util)
- * Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-util-ajax)
- * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-webapp)
- * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.51.v20230217 - https://eclipse.org/jetty/jetty-xml)
- * Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-client)
- * Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-common)
- * Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-hpack)
- * Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.44.v20210927 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
- * Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.51.v20230217 - https://eclipse.org/jetty/http2-parent/http2-server)
+ * 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.54.v20240208 - https://eclipse.org/jetty/jetty-security)
+ * Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-server)
+ * Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-servlet)
+ * Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.54.v20240208 - 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 :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util-ajax)
+ * Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-webapp)
+ * Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml)
+ * 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 :: 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 :: Server (org.eclipse.jetty.http2:http2-server:9.4.54.v20240208 - 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)
* HK2 API module (org.glassfish.hk2:hk2-api:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
@@ -545,14 +556,24 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.2.Final - http://hibernate.org)
+ * 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)
* 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)
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
+ GENERAL PUBLIC LICENSE, version 3 (GPL-3.0):
+
+ * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet)
+
+ GNU LESSER GENERAL PUBLIC LICENSE, version 3 (LGPL-3.0):
+
+ * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet)
+
GNU Lesser General Public License (LGPL):
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
@@ -569,9 +590,8 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* Hibernate ORM - hibernate-jpamodelgen (org.hibernate:hibernate-jpamodelgen:5.6.15.Final - https://hibernate.org/orm)
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:5.1.2.Final - http://hibernate.org)
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
- * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/)
- * XOM (xom:xom:1.2.5 - http://xom.nu)
- * XOM (xom:xom:1.3.7 - https://xom.nu)
+ * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/)
+ * XOM (xom:xom:1.3.9 - https://xom.nu)
Go License:
@@ -579,25 +599,29 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
Handle.Net Public License Agreement (Ver.2):
- * Handle Server (net.handle:handle:9.3.0 - https://www.handle.net)
+ * Handle Server (net.handle:handle:9.3.1 - https://www.handle.net)
+
+ ISC License:
+
+ * Simple Magic (com.j256.simplemagic:simplemagic:1.17 - https://256stuff.com/sources/simplemagic/)
MIT License:
* 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)
- * dd-plist (com.googlecode.plist:dd-plist:1.25 - http://www.github.com/3breadt/dd-plist)
- * DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.9 - https://github.com/dbmdz/iiif-apis)
+ * 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)
* s3mock (io.findify:s3mock_2.13:0.2.6 - https://github.com/findify/s3mock)
* 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-jdk15on:1.70 - https://www.bouncycastle.org/java.html)
- * Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk15on:1.70 - https://www.bouncycastle.org/java.html)
- * Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.70 - https://www.bouncycastle.org/java.html)
- * Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk15on:1.70 - https://www.bouncycastle.org/java.html)
+ * Bouncy Castle S/MIME API (org.bouncycastle:bcmail-jdk18on:1.77 - https://www.bouncycastle.org/java.html)
+ * 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.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)
- * Checker Qual (org.checkerframework:checker-qual:3.10.0 - https://checkerframework.org)
- * Checker Qual (org.checkerframework:checker-qual:3.31.0 - https://checkerframework.org)
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * Checker Qual (org.checkerframework:checker-qual:3.23.0 - https://checkerframework.org)
+ * Checker Qual (org.checkerframework:checker-qual:3.42.0 - https://checkerframework.org/)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* 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)
* ORCID - Model (org.orcid:orcid-model:3.0.2 - http://github.com/ORCID/orcid-model)
@@ -608,34 +632,34 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
* 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)
* underscore (org.webjars.bowergithub.jashkenas:underscore:1.13.2 - https://www.webjars.org)
- * jquery (org.webjars.bowergithub.jquery:jquery-dist:3.6.0 - https://www.webjars.org)
- * urijs (org.webjars.bowergithub.medialize:uri.js:1.19.10 - https://www.webjars.org)
- * bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.6.1 - https://www.webjars.org)
- * core-js (org.webjars.npm:core-js:3.30.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)
+ * 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)
* @json-editor/json-editor (org.webjars.npm:json-editor__json-editor:2.6.1 - https://www.webjars.org)
Mozilla Public License:
- * juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/)
- * H2 Database Engine (com.h2database:h2:2.1.210 - https://h2database.com)
+ * juniversalchardet (com.github.albfernandez:juniversalchardet:2.4.0 - https://github.com/albfernandez/juniversalchardet)
+ * H2 Database Engine (com.h2database:h2:2.2.224 - https://h2database.com)
* Saxon-HE (net.sf.saxon:Saxon-HE:9.8.0-14 - http://www.saxonica.com/)
- * Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/)
+ * Javassist (org.javassist:javassist:3.29.0-GA - http://www.javassist.org/)
* Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino)
Public Domain:
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-core-common (org.glassfish.jersey.core:jersey-common:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/)
- * JSON in Java (org.json:json:20230227 - 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/)
* 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:
- * Java Unrar (com.github.junrar:junrar:7.5.3 - https://github.com/junrar/junrar)
+ * Java Unrar (com.github.junrar:junrar:7.5.5 - https://github.com/junrar/junrar)
Unicode/ICU License:
@@ -643,10 +667,10 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
W3C license:
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
jQuery license:
- * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
- * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.35 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
+ * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
+ * jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.39.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
diff --git a/docker-compose-cli.yml b/docker-compose-cli.yml
index 9c66fed6835b..d6a194617e02 100644
--- a/docker-compose-cli.yml
+++ b/docker-compose-cli.yml
@@ -1,5 +1,9 @@
-version: "3.7"
-
+networks:
+ # Default to using network named 'dspacenet' from docker-compose.yml.
+ # Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet")
+ default:
+ name: ${COMPOSE_PROJECT_NAME}_dspacenet
+ external: true
services:
dspace-cli:
image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}"
@@ -26,13 +30,8 @@ services:
- ./dspace/config:/dspace/config
entrypoint: /dspace/bin/dspace
command: help
- networks:
- - dspacenet
tty: true
stdin_open: true
volumes:
assetstore:
-
-networks:
- dspacenet:
diff --git a/docker-compose.yml b/docker-compose.yml
index 6c1615040722..23fce37db245 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,3 @@
-version: '3.7'
networks:
dspacenet:
ipam:
@@ -36,7 +35,7 @@ services:
depends_on:
- dspacedb
networks:
- dspacenet:
+ - dspacenet
ports:
- published: 8080
target: 8080
@@ -89,8 +88,10 @@ services:
container_name: dspacesolr
image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-dspace-7_x}"
build:
- context: .
- dockerfile: ./dspace/src/main/docker/dspace-solr/Dockerfile
+ context: ./dspace/src/main/docker/dspace-solr/
+ # Provide path to Solr configs necessary to build Docker image
+ additional_contexts:
+ solrconfigs: ./dspace/solr/
args:
SOLR_VERSION: "${SOLR_VER:-8.11}"
networks:
diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml
index db1b4d2ac2aa..ee31a039f4aa 100644
--- a/dspace-api/pom.xml
+++ b/dspace-api/pom.xml
@@ -495,12 +495,6 @@
jaxenjaxen
-
-
- xom
- xom
-
- org.jdom
@@ -534,7 +528,7 @@
org.hamcrest
- hamcrest-all
+ hamcresttest
@@ -592,6 +586,12 @@
solr-coretest${solr.client.version}
+
+
+ com.google.j2objc
+ j2objc-annotations
+
+ org.apache.lucene
@@ -626,7 +626,7 @@
com.maxmind.geoip2geoip2
- 2.11.0
+ 2.17.0org.apache.ant
@@ -635,7 +635,7 @@
dnsjavadnsjava
- 2.1.7
+ 2.1.9
@@ -671,7 +671,7 @@
org.flywaydbflyway-core
- 8.4.4
+ 8.5.13
@@ -809,7 +809,7 @@
com.opencsvopencsv
- 5.6
+ 5.9
@@ -827,7 +827,7 @@
org.apache.bcelbcel
- 6.6.0
+ 6.7.0test
@@ -884,6 +884,13 @@
eu.openairefunders-model2.0.0
+
+
+
+ org.javassist
+ javassist
+
+
@@ -927,32 +934,32 @@
io.nettynetty-buffer
- 4.1.94.Final
+ 4.1.106.Finalio.nettynetty-transport
- 4.1.94.Final
+ 4.1.106.Finalio.nettynetty-transport-native-unix-common
- 4.1.94.Final
+ 4.1.106.Finalio.nettynetty-common
- 4.1.94.Final
+ 4.1.106.Finalio.nettynetty-handler
- 4.1.94.Final
+ 4.1.106.Finalio.nettynetty-codec
- 4.1.94.Final
+ 4.1.106.Finalorg.apache.velocity
@@ -962,7 +969,7 @@
org.xmlunitxmlunit-core
- 2.8.0
+ 2.10.0test
@@ -988,7 +995,7 @@
org.scala-langscala-library
- 2.13.9
+ 2.13.11test
diff --git a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
index 81250e9c8259..58b85493915a 100644
--- a/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
+++ b/dspace-api/src/main/java/org/dspace/administer/CreateAdministrator.java
@@ -116,6 +116,17 @@ public static void main(String[] argv)
protected CreateAdministrator()
throws Exception {
context = new Context();
+ try {
+ context.getDBConfig();
+ } catch (NullPointerException npr) {
+ // if database is null, there is no point in continuing. Prior to this exception and catch,
+ // NullPointerException was thrown, that wasn't very helpful.
+ throw new IllegalStateException("Problem connecting to database. This " +
+ "indicates issue with either network or version (or possibly some other). " +
+ "If you are running this in docker-compose, please make sure dspace-cli was " +
+ "built from the same sources as running dspace container AND that they are in " +
+ "the same project/network.");
+ }
groupService = EPersonServiceFactory.getInstance().getGroupService();
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
}
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
index 503fb90df1d7..50572457dffb 100644
--- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
@@ -827,8 +827,10 @@ protected void compareAndUpdate(Context c, Item item, String[] fromCSV, boolean
addRelationships(c, item, element, values);
} else {
itemService.clearMetadata(c, item, schema, element, qualifier, language);
- itemService.addMetadata(c, item, schema, element, qualifier,
- language, values, authorities, confidences);
+ if (!values.isEmpty()) {
+ itemService.addMetadata(c, item, schema, element, qualifier,
+ language, values, authorities, confidences);
+ }
itemService.update(c, item);
}
}
@@ -1123,8 +1125,8 @@ protected void add(Context c, String[] fromCSV, String md, BulkEditChange change
.getAuthoritySeparator() + dcv.getConfidence();
}
- // Add it
- if ((value != null) && (!"".equals(value))) {
+ // Add it, if value is not blank
+ if (value != null && StringUtils.isNotBlank(value)) {
changes.registerAdd(dcv);
}
}
diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java
index 255f4bdcbb15..1e219ee6314c 100644
--- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImportServiceImpl.java
@@ -1743,7 +1743,8 @@ protected void processOptions(Context c, Item myItem, List options)
} else {
logInfo("\tSetting special permissions for "
+ bitstreamName);
- setPermission(c, myGroup, actionID, bs);
+ String rpType = useWorkflow ? ResourcePolicy.TYPE_SUBMISSION : ResourcePolicy.TYPE_INHERITED;
+ setPermission(c, myGroup, rpType, actionID, bs);
}
}
@@ -1801,24 +1802,25 @@ protected void processOptions(Context c, Item myItem, List options)
*
* @param c DSpace Context
* @param g Dspace Group
+ * @param rpType resource policy type string
* @param actionID action identifier
* @param bs Bitstream
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
* @see org.dspace.core.Constants
*/
- protected void setPermission(Context c, Group g, int actionID, Bitstream bs)
+ protected void setPermission(Context c, Group g, String rpType, int actionID, Bitstream bs)
throws SQLException, AuthorizeException {
if (!isTest) {
// remove the default policy
authorizeService.removeAllPolicies(c, bs);
// add the policy
- ResourcePolicy rp = resourcePolicyService.create(c);
+ ResourcePolicy rp = resourcePolicyService.create(c, null, g);
rp.setdSpaceObject(bs);
rp.setAction(actionID);
- rp.setGroup(g);
+ rp.setRpType(rpType);
resourcePolicyService.update(c, rp);
} else {
@@ -1957,58 +1959,57 @@ public String unzip(File zipfile, String destDir) throws IOException {
try {
while (entries.hasMoreElements()) {
entry = entries.nextElement();
+ String entryName = entry.getName();
+ File outFile = new File(zipDir + entryName);
+ // Verify that this file/directory will be extracted into our zipDir (and not somewhere else!)
+ if (!outFile.toPath().normalize().startsWith(zipDir)) {
+ throw new IOException("Bad zip entry: '" + entryName
+ + "' in file '" + zipfile.getAbsolutePath() + "'!"
+ + " Cannot process this file or directory.");
+ }
if (entry.isDirectory()) {
- if (!new File(zipDir + entry.getName()).mkdirs()) {
+ if (!outFile.mkdirs()) {
logError("Unable to create contents directory: " + zipDir + entry.getName());
}
} else {
- String entryName = entry.getName();
- File outFile = new File(zipDir + entryName);
- // Verify that this file will be extracted into our zipDir (and not somewhere else!)
- if (!outFile.toPath().normalize().startsWith(zipDir)) {
- throw new IOException("Bad zip entry: '" + entryName
- + "' in file '" + zipfile.getAbsolutePath() + "'!"
- + " Cannot process this file.");
- } else {
- logInfo("Extracting file: " + entryName);
+ logInfo("Extracting file: " + entryName);
- int index = entryName.lastIndexOf('/');
- if (index == -1) {
- // Was it created on Windows instead?
- index = entryName.lastIndexOf('\\');
+ int index = entryName.lastIndexOf('/');
+ if (index == -1) {
+ // Was it created on Windows instead?
+ index = entryName.lastIndexOf('\\');
+ }
+ if (index > 0) {
+ File dir = new File(zipDir + entryName.substring(0, index));
+ if (!dir.exists() && !dir.mkdirs()) {
+ logError("Unable to create directory: " + dir.getAbsolutePath());
}
- if (index > 0) {
- File dir = new File(zipDir + entryName.substring(0, index));
- if (!dir.exists() && !dir.mkdirs()) {
- logError("Unable to create directory: " + dir.getAbsolutePath());
- }
- //Entries could have too many directories, and we need to adjust the sourcedir
- // file1.zip (SimpleArchiveFormat / item1 / contents|dublin_core|...
- // SimpleArchiveFormat / item2 / contents|dublin_core|...
- // or
- // file2.zip (item1 / contents|dublin_core|...
- // item2 / contents|dublin_core|...
-
- //regex supports either windows or *nix file paths
- String[] entryChunks = entryName.split("/|\\\\");
- if (entryChunks.length > 2) {
- if (StringUtils.equals(sourceDirForZip, sourcedir)) {
- sourceDirForZip = sourcedir + "/" + entryChunks[0];
- }
+ //Entries could have too many directories, and we need to adjust the sourcedir
+ // file1.zip (SimpleArchiveFormat / item1 / contents|dublin_core|...
+ // SimpleArchiveFormat / item2 / contents|dublin_core|...
+ // or
+ // file2.zip (item1 / contents|dublin_core|...
+ // item2 / contents|dublin_core|...
+
+ //regex supports either windows or *nix file paths
+ String[] entryChunks = entryName.split("/|\\\\");
+ if (entryChunks.length > 2) {
+ if (StringUtils.equals(sourceDirForZip, sourcedir)) {
+ sourceDirForZip = sourcedir + "/" + entryChunks[0];
}
}
- byte[] buffer = new byte[1024];
- int len;
- InputStream in = zf.getInputStream(entry);
- BufferedOutputStream out = new BufferedOutputStream(
- new FileOutputStream(outFile));
- while ((len = in.read(buffer)) >= 0) {
- out.write(buffer, 0, len);
- }
- in.close();
- out.close();
}
+ byte[] buffer = new byte[1024];
+ int len;
+ InputStream in = zf.getInputStream(entry);
+ BufferedOutputStream out = new BufferedOutputStream(
+ new FileOutputStream(outFile));
+ while ((len = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, len);
+ }
+ in.close();
+ out.close();
}
}
} finally {
@@ -2233,7 +2234,7 @@ public void emailSuccessMessage(Context context, EPerson eperson,
String fileName) throws MessagingException {
try {
Locale supportedLocale = I18nUtil.getEPersonLocale(eperson);
- Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_success"));
+ Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "batch_import_success"));
email.addRecipient(eperson.getEmail());
email.addArgument(fileName);
@@ -2249,7 +2250,7 @@ public void emailErrorMessage(EPerson eperson, String error)
logError("An error occurred during item import, the user will be notified. " + error);
try {
Locale supportedLocale = I18nUtil.getEPersonLocale(eperson);
- Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_error"));
+ Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "batch_import_error"));
email.addRecipient(eperson.getEmail());
email.addArgument(error);
email.addArgument(configurationService.getProperty("dspace.ui.url") + "/feedback");
diff --git a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java
index cb5dcfb75dc0..65157f5207e7 100644
--- a/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java
+++ b/dspace-api/src/main/java/org/dspace/app/itemupdate/DeleteBitstreamsAction.java
@@ -70,16 +70,19 @@ public void execute(Context context, ItemArchive itarch, boolean isTest,
}
}
- if (alterProvenance) {
+ if (alterProvenance && !bundles.isEmpty()) {
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
String append = "Bitstream " + bs.getName() + " deleted on " + DCDate
.getCurrent() + "; ";
- Item item = bundles.iterator().next().getItems().iterator().next();
- ItemUpdate.pr("Append provenance with: " + append);
+ List items = bundles.iterator().next().getItems();
+ if (!items.isEmpty()) {
+ Item item = items.iterator().next();
+ ItemUpdate.pr("Append provenance with: " + append);
- if (!isTest) {
- MetadataUtilities.appendMetadata(context, item, dtom, false, append);
+ if (!isTest) {
+ MetadataUtilities.appendMetadata(context, item, dtom, false, append);
+ }
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java
index 974dc784bd4f..a6ba9fde88d9 100644
--- a/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/MediaFilterServiceImpl.java
@@ -180,6 +180,7 @@ public void applyFiltersItem(Context c, Item item) throws Exception {
}
// clear item objects from context cache and internal cache
c.uncacheEntity(currentItem);
+ // commit after each item to release DB resources
c.commit();
currentItem = null;
}
diff --git a/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCli.java b/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCli.java
index 44fc07694cd3..958013263462 100644
--- a/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCli.java
+++ b/dspace-api/src/main/java/org/dspace/app/solrdatabaseresync/SolrDatabaseResyncCli.java
@@ -105,36 +105,17 @@ private void performStatusUpdate(Context context) throws SearchServiceException,
solrQuery.addFilterQuery(dateRangeFilter);
solrQuery.addField(SearchUtils.RESOURCE_ID_FIELD);
solrQuery.addField(SearchUtils.RESOURCE_UNIQUE_ID);
+ solrQuery.setRows(0);
QueryResponse response = solrSearchCore.getSolr().query(solrQuery, solrSearchCore.REQUEST_METHOD);
-
- if (response != null) {
- logInfoAndOut(response.getResults().size() + " items found to process");
-
- for (SolrDocument doc : response.getResults()) {
- String uuid = (String) doc.getFirstValue(SearchUtils.RESOURCE_ID_FIELD);
- String uniqueId = (String) doc.getFirstValue(SearchUtils.RESOURCE_UNIQUE_ID);
- logDebugAndOut("Processing item with UUID: " + uuid);
-
- Optional indexableObject = Optional.empty();
- try {
- indexableObject = indexObjectServiceFactory
- .getIndexableObjectFactory(uniqueId).findIndexableObject(context, uuid);
- } catch (SQLException e) {
- log.warn("An exception occurred when attempting to retrieve item with UUID \"" + uuid +
- "\" from the database, removing related solr document", e);
- }
-
- try {
- if (indexableObject.isPresent()) {
- logDebugAndOut("Item exists in DB, updating solr document");
- updateItem(context, indexableObject.get());
- context.uncacheEntity(indexableObject.get().getIndexedObject());
- } else {
- logDebugAndOut("Item doesn't exist in DB, removing solr document");
- removeItem(context, uniqueId);
- }
- } catch (SQLException | IOException e) {
- log.error(e.getMessage(), e);
+ if (response != null && response.getResults() != null) {
+ long nrOfPreDBResults = response.getResults().getNumFound();
+ if (nrOfPreDBResults > 0) {
+ logInfoAndOut(nrOfPreDBResults + " items found to process");
+ int batchSize = configurationService.getIntProperty("script.solr-database-resync.batch-size", 100);
+ for (int start = 0; start < nrOfPreDBResults; start += batchSize) {
+ solrQuery.setStart(start);
+ solrQuery.setRows(batchSize);
+ performStatusUpdateOnNextBatch(context, solrQuery);
}
}
}
@@ -142,6 +123,41 @@ private void performStatusUpdate(Context context) throws SearchServiceException,
indexingService.commit();
}
+ private void performStatusUpdateOnNextBatch(Context context, SolrQuery solrQuery)
+ throws SolrServerException, IOException {
+ QueryResponse response = solrSearchCore.getSolr().query(solrQuery, solrSearchCore.REQUEST_METHOD);
+
+ logInfoAndOut(response.getResults().size() + " items found to process");
+
+ for (SolrDocument doc : response.getResults()) {
+ String uuid = (String) doc.getFirstValue(SearchUtils.RESOURCE_ID_FIELD);
+ String uniqueId = (String) doc.getFirstValue(SearchUtils.RESOURCE_UNIQUE_ID);
+ logDebugAndOut("Processing item with UUID: " + uuid);
+
+ Optional indexableObject = Optional.empty();
+ try {
+ indexableObject =
+ indexObjectServiceFactory.getIndexableObjectFactory(uniqueId).findIndexableObject(context, uuid);
+ } catch (SQLException e) {
+ log.warn("An exception occurred when attempting to retrieve item with UUID \"" + uuid +
+ "\" from the database, removing related solr document", e);
+ }
+
+ try {
+ if (indexableObject.isPresent()) {
+ logDebugAndOut("Item exists in DB, updating solr document");
+ updateItem(context, indexableObject.get());
+ context.uncacheEntity(indexableObject.get().getIndexedObject());
+ } else {
+ logDebugAndOut("Item doesn't exist in DB, removing solr document");
+ removeItem(context, uniqueId);
+ }
+ } catch (SQLException | IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+ }
+
private void updateItem(Context context, IndexableObject indexableObject) throws SolrServerException, IOException {
Map fieldModifier = new HashMap<>(1);
fieldModifier.put("remove", STATUS_FIELD_PREDB);
diff --git a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
index 6c7ee651d930..3fd7089de705 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/DCInputsReader.java
@@ -22,7 +22,6 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
-import javax.servlet.ServletException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
@@ -160,10 +159,9 @@ public List getPairs(String name) {
* Returns the set of DC inputs used for a particular collection, or the default
* set if no inputs defined for the collection
*
- * @param collection collection
- * @return DC input set
+ * @param collection collection for which search the set of DC inputs
+ * @return DC input set
* @throws DCInputsReaderException if no default set defined
- * @throws ServletException
*/
public List getInputsByCollection(Collection collection)
throws DCInputsReaderException {
diff --git a/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java b/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java
index 514143c93ea0..bff741b5ca42 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/OpenSearchServiceImpl.java
@@ -155,7 +155,7 @@ protected SyndicationFeed getResults(Context context, String format, String quer
format = "atom_1.0";
}
- SyndicationFeed feed = new SyndicationFeed(labels.get(SyndicationFeed.MSG_UITYPE));
+ SyndicationFeed feed = new SyndicationFeed();
feed.populate(null, context, scope, results, labels);
feed.setType(format);
feed.addModule(openSearchMarkup(query, totalResults, start, pageSize));
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
index 402059493976..0d48f7c1d480 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SubmissionConfigReader.java
@@ -11,9 +11,11 @@
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
@@ -28,7 +30,6 @@
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.core.Context;
-import org.dspace.discovery.SearchServiceException;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.services.RequestService;
import org.dspace.services.factory.DSpaceServicesFactory;
@@ -106,6 +107,13 @@ public class SubmissionConfigReader {
*/
private Map> stepDefns = null;
+ /**
+ * Hashmap which stores which submission process configuration is used by
+ * which entityType, computed from the item submission config file
+ * (specifically, the 'submission-map' tag)
+ */
+ private Map entityTypeToSubmissionConfig = null;
+
/**
* Reference to the item submission definitions defined in the
* "submission-definitions" section
@@ -147,6 +155,7 @@ public SubmissionConfigReader() throws SubmissionConfigReaderException {
public void reload() throws SubmissionConfigReaderException {
collectionToSubmissionConfig = null;
+ entityTypeToSubmissionConfig = null;
stepDefns = null;
submitDefns = null;
buildInputs(configDir + SUBMIT_DEF_FILE_PREFIX + SUBMIT_DEF_FILE_SUFFIX);
@@ -165,7 +174,8 @@ public void reload() throws SubmissionConfigReaderException {
*/
private void buildInputs(String fileName) throws SubmissionConfigReaderException {
collectionToSubmissionConfig = new HashMap();
- submitDefns = new HashMap>>();
+ entityTypeToSubmissionConfig = new HashMap();
+ submitDefns = new LinkedHashMap>>();
String uri = "file:" + new File(fileName).getAbsolutePath();
@@ -182,9 +192,6 @@ private void buildInputs(String fileName) throws SubmissionConfigReaderException
} catch (FactoryConfigurationError fe) {
throw new SubmissionConfigReaderException(
"Cannot create Item Submission Configuration parser", fe);
- } catch (SearchServiceException se) {
- throw new SubmissionConfigReaderException(
- "Cannot perform a discovery search for Item Submission Configuration", se);
} catch (Exception e) {
throw new SubmissionConfigReaderException(
"Error creating Item Submission Configuration: " + e);
@@ -311,10 +318,11 @@ public SubmissionConfig getSubmissionConfigByCollection(Collection collection) {
}
}
- submitName = collService.getMetadataFirstValue(collection, "dspace", "entity", "type", null);
+ // get entity-type based configuration
+ submitName = getEntityTypeSubmission(collection, collService);
if (submitName != null) {
try {
- SubmissionConfig subConfig = getSubmissionConfigByName(submitName.toLowerCase());
+ SubmissionConfig subConfig = getSubmissionConfigByName(submitName);
if (subConfig != null) {
return subConfig;
}
@@ -336,6 +344,27 @@ public SubmissionConfig getSubmissionConfigByCollection(Collection collection) {
+ "in 'submission-map' section of 'item-submission.xml'.");
}
+ /**
+ * Returns the submission name for the given collection based on the entity type.
+ * It checks for the {@code collection-entity-type} configuration (standard DSpace), otherwise defaults to the
+ * {@code entityType} in lowercase (standard CRIS).
+ *
+ * @param collection Collection of which check the submission configuration
+ * @param collService CollectionService
+ * @return Submission Definition found.
+ */
+ private String getEntityTypeSubmission(Collection collection, CollectionService collService) {
+ String submitName = null;
+ String entityType = collService.getMetadataFirstValue(collection, "dspace", "entity", "type", Item.ANY);
+ if (entityType != null) {
+ // collection-entity-type configuration (DSpace configuration)
+ submitName = Optional.ofNullable(entityTypeToSubmissionConfig.get(entityType))
+ // entity-type lowercase configuration (CRIS configuration)
+ .orElseGet(entityType::toLowerCase);
+ }
+ return submitName;
+ }
+
/**
* Returns the Item Submission process config
*
@@ -343,8 +372,7 @@ public SubmissionConfig getSubmissionConfigByCollection(Collection collection) {
* @return the SubmissionConfig representing the item submission config
*/
public SubmissionConfig getSubmissionConfigByName(String submitName) {
- log.debug("Loading submission process config named '" + submitName
- + "'");
+ log.debug("Loading submission process config named '" + submitName + "'");
// check mini-cache, and return if match
if (lastSubmissionConfig != null
@@ -367,8 +395,8 @@ public SubmissionConfig getSubmissionConfigByName(String submitName) {
log.debug("Submission process config '" + submitName
+ "' not in cache. Reloading from scratch.");
- lastSubmissionConfig = new SubmissionConfig(StringUtils.equals(getDefaultSubmissionConfigName(), submitName),
- submitName, steps);
+ lastSubmissionConfig =
+ new SubmissionConfig(StringUtils.equals(getDefaultSubmissionConfigName(), submitName), submitName, steps);
log.debug("Submission process config has "
+ lastSubmissionConfig.getNumberOfSteps() + " steps listed.");
@@ -406,7 +434,7 @@ public SubmissionStepConfig getStepConfig(String stepID)
* should correspond to the collection-form maps, the form definitions, and
* the display/storage word pairs.
*/
- private void doNodes(Node n) throws SAXException, SearchServiceException, SubmissionConfigReaderException {
+ private void doNodes(Node n) throws SAXException, SubmissionConfigReaderException {
if (n == null) {
return;
}
@@ -456,7 +484,7 @@ private void doNodes(Node n) throws SAXException, SearchServiceException, Submis
* the collection handle and item submission name, put name in hashmap keyed
* by the collection handle.
*/
- private void processMap(Node e) throws SAXException, SearchServiceException {
+ private void processMap(Node e) throws SAXException {
NodeList nl = e.getChildNodes();
int len = nl.getLength();
for (int i = 0; i < len; i++) {
@@ -475,14 +503,14 @@ private void processMap(Node e) throws SAXException, SearchServiceException {
throw new SAXException(
"name-map element is missing submission-name attribute in 'item-submission.xml'");
}
- if (content != null && content.length() > 0) {
+ if (content != null && !content.isEmpty()) {
throw new SAXException(
"name-map element has content in 'item-submission.xml', it should be empty.");
}
if (id != null) {
collectionToSubmissionConfig.put(id, value);
} else {
- collectionToSubmissionConfig.putIfAbsent(entityType, value);
+ entityTypeToSubmissionConfig.putIfAbsent(entityType, value);
}
} // ignore any child node that isn't a "name-map"
}
diff --git a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
index c1402499c444..d37e6d802fe1 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/SyndicationFeed.java
@@ -84,11 +84,6 @@ public class SyndicationFeed {
public static final String MSG_FEED_TITLE = "feed.title";
public static final String MSG_FEED_DESCRIPTION = "general-feed.description";
public static final String MSG_METADATA = "metadata.";
- public static final String MSG_UITYPE = "ui.type";
-
- // UI keywords
- public static final String UITYPE_XMLUI = "xmlui";
- public static final String UITYPE_JSPUI = "jspui";
// default DC fields for entry
protected String defaultTitleField = "dc.title";
@@ -145,10 +140,6 @@ public class SyndicationFeed {
// the feed object we are building
protected SyndFeed feed = null;
- // memory of UI that called us, "xmlui" or "jspui"
- // affects Bitstream retrieval URL and I18N keys
- protected String uiType = null;
-
protected HttpServletRequest request = null;
protected CollectionService collectionService;
@@ -157,12 +148,9 @@ public class SyndicationFeed {
/**
* Constructor.
- *
- * @param ui either "xmlui" or "jspui"
*/
- public SyndicationFeed(String ui) {
+ public SyndicationFeed() {
feed = new SyndFeedImpl();
- uiType = ui;
ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
itemService = contentServiceFactory.getItemService();
collectionService = contentServiceFactory.getCollectionService();
@@ -518,8 +506,7 @@ protected static String getDefaultedConfiguration(String key, String dfl) {
protected String urlOfBitstream(HttpServletRequest request, Bitstream logo) {
String name = logo.getName();
return resolveURL(request, null) +
- (uiType.equalsIgnoreCase(UITYPE_XMLUI) ? "/bitstream/id/" : "/retrieve/") +
- logo.getID() + "/" + (name == null ? "" : name);
+ "/bitstreams/" + logo.getID() + "/download";
}
protected String baseURL = null; // cache the result for null
diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
index b5b53963eab6..d375c5148b34 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
@@ -572,13 +572,11 @@ public void addPolicies(Context c, List policies, DSpaceObject d
List newPolicies = new ArrayList<>(policies.size());
for (ResourcePolicy srp : policies) {
- ResourcePolicy rp = resourcePolicyService.create(c);
+ ResourcePolicy rp = resourcePolicyService.create(c, srp.getEPerson(), srp.getGroup());
// copy over values
rp.setdSpaceObject(dest);
rp.setAction(srp.getAction());
- rp.setEPerson(srp.getEPerson());
- rp.setGroup(srp.getGroup());
rp.setStartDate(srp.getStartDate());
rp.setEndDate(srp.getEndDate());
rp.setRpName(srp.getRpName());
@@ -692,11 +690,9 @@ public ResourcePolicy createResourcePolicy(Context context, DSpaceObject dso, Gr
"We need at least an eperson or a group in order to create a resource policy.");
}
- ResourcePolicy myPolicy = resourcePolicyService.create(context);
+ ResourcePolicy myPolicy = resourcePolicyService.create(context, eperson, group);
myPolicy.setdSpaceObject(dso);
myPolicy.setAction(type);
- myPolicy.setGroup(group);
- myPolicy.setEPerson(eperson);
myPolicy.setRpType(rpType);
myPolicy.setRpName(rpName);
myPolicy.setRpDescription(rpDescription);
@@ -918,7 +914,7 @@ private boolean performCheck(Context context, String query) throws SQLException
return true;
}
} catch (SearchServiceException e) {
- log.error("Failed getting getting community/collection admin status for "
+ log.error("Failed getting community/collection admin status for "
+ context.getCurrentUser().getEmail() + " The search error is: " + e.getMessage()
+ " The search resourceType filter was: " + query);
}
diff --git a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java
index 61e783920ae5..b430a2635fd9 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/FixDefaultPolicies.java
@@ -126,10 +126,9 @@ private static void addAnonymousPolicy(Context c, DSpaceObject t,
// now create the default policies for submitted items
ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance().getResourcePolicyService();
- ResourcePolicy myPolicy = resourcePolicyService.create(c);
+ ResourcePolicy myPolicy = resourcePolicyService.create(c, null, anonymousGroup);
myPolicy.setdSpaceObject(t);
myPolicy.setAction(myaction);
- myPolicy.setGroup(anonymousGroup);
resourcePolicyService.update(c, myPolicy);
}
}
diff --git a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java
index 72998b9fd18a..e22b8e9df026 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/PolicySet.java
@@ -229,11 +229,10 @@ public static void setPoliciesFilter(Context c, int containerType,
// before create a new policy check if an identical policy is already in place
if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, myitem, group, actionID, -1)) {
// now add the policy
- ResourcePolicy rp = resourcePolicyService.create(c);
+ ResourcePolicy rp = resourcePolicyService.create(c, null, group);
rp.setdSpaceObject(myitem);
rp.setAction(actionID);
- rp.setGroup(group);
rp.setRpName(name);
rp.setRpDescription(description);
@@ -262,11 +261,10 @@ public static void setPoliciesFilter(Context c, int containerType,
// before create a new policy check if an identical policy is already in place
if (!authorizeService.isAnIdenticalPolicyAlreadyInPlace(c, bundle, group, actionID, -1)) {
// now add the policy
- ResourcePolicy rp = resourcePolicyService.create(c);
+ ResourcePolicy rp = resourcePolicyService.create(c, null, group);
rp.setdSpaceObject(bundle);
rp.setAction(actionID);
- rp.setGroup(group);
rp.setRpName(name);
rp.setRpDescription(description);
@@ -305,11 +303,10 @@ public static void setPoliciesFilter(Context c, int containerType,
if (!authorizeService
.isAnIdenticalPolicyAlreadyInPlace(c, bitstream, group, actionID, -1)) {
// now add the policy
- ResourcePolicy rp = resourcePolicyService.create(c);
+ ResourcePolicy rp = resourcePolicyService.create(c, null, group);
rp.setdSpaceObject(bitstream);
rp.setAction(actionID);
- rp.setGroup(group);
rp.setRpName(name);
rp.setRpDescription(description);
diff --git a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java
index d633e303bf66..25875dbdb366 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/ResourcePolicyServiceImpl.java
@@ -71,14 +71,22 @@ public ResourcePolicy find(Context context, int id) throws SQLException {
* Create a new ResourcePolicy
*
* @param context DSpace context object
+ * @param ePerson
+ * @param group
* @return ResourcePolicy
* @throws SQLException if database error
*/
@Override
- public ResourcePolicy create(Context context) throws SQLException {
+ public ResourcePolicy create(Context context, EPerson ePerson, Group group) throws SQLException {
// FIXME: Check authorisation
// Create a table row
- ResourcePolicy resourcePolicy = resourcePolicyDAO.create(context, new ResourcePolicy());
+ ResourcePolicy policyToBeCreated = new ResourcePolicy();
+ if (ePerson == null && group == null) {
+ throw new IllegalArgumentException("A resource policy must contain a valid eperson or group");
+ }
+ policyToBeCreated.setEPerson(ePerson);
+ policyToBeCreated.setGroup(group);
+ ResourcePolicy resourcePolicy = resourcePolicyDAO.create(context, policyToBeCreated);
return resourcePolicy;
}
@@ -210,9 +218,7 @@ public boolean isDateValid(ResourcePolicy resourcePolicy) {
@Override
public ResourcePolicy clone(Context context, ResourcePolicy resourcePolicy)
throws SQLException, AuthorizeException {
- ResourcePolicy clone = create(context);
- clone.setGroup(resourcePolicy.getGroup());
- clone.setEPerson(resourcePolicy.getEPerson());
+ ResourcePolicy clone = create(context, resourcePolicy.getEPerson(), resourcePolicy.getGroup());
clone.setStartDate((Date) ObjectUtils.clone(resourcePolicy.getStartDate()));
clone.setEndDate((Date) ObjectUtils.clone(resourcePolicy.getEndDate()));
clone.setRpType((String) ObjectUtils.clone(resourcePolicy.getRpType()));
diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
index 662b14b18b2e..f099f72d65ce 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/service/ResourcePolicyService.java
@@ -18,7 +18,6 @@
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
-import org.dspace.service.DSpaceCRUDService;
/**
* Service interface class for the ResourcePolicy object.
@@ -27,7 +26,34 @@
*
* @author kevinvandevelde at atmire.com
*/
-public interface ResourcePolicyService extends DSpaceCRUDService {
+public interface ResourcePolicyService {
+
+ public ResourcePolicy create(Context context, EPerson eperson, Group group) throws SQLException, AuthorizeException;
+
+ public ResourcePolicy find(Context context, int id) throws SQLException;
+
+ /**
+ * Persist a model object.
+ *
+ * @param context
+ * @param resourcePolicy object to be persisted.
+ * @throws SQLException passed through.
+ * @throws AuthorizeException passed through.
+ */
+ public void update(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException;
+
+
+ /**
+ * Persist a collection of model objects.
+ *
+ * @param context
+ * @param resourcePolicies object to be persisted.
+ * @throws SQLException passed through.
+ * @throws AuthorizeException passed through.
+ */
+ public void update(Context context, List resourcePolicies) throws SQLException, AuthorizeException;
+
+ public void delete(Context context, ResourcePolicy resourcePolicy) throws SQLException, AuthorizeException;
public List find(Context c, DSpaceObject o) throws SQLException;
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java
index ab16f68d3569..6438b5745bdb 100644
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java
+++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAO.java
@@ -13,26 +13,17 @@
/**
* Interface for data access of cached community and collection item count
* information
- *
- * @author Richard Jones
*/
public interface ItemCountDAO {
- /**
- * Set the DSpace Context to use during data access
- *
- * @param context DSpace Context
- * @throws ItemCountException if count error
- */
- public void setContext(Context context) throws ItemCountException;
/**
* Get the number of items in the given DSpaceObject container. This method will
* only succeed if the DSpaceObject is an instance of either a Community or a
* Collection. Otherwise it will throw an exception.
*
+ * @param context DSpace context
* @param dso Dspace Object
* @return count
- * @throws ItemCountException if count error
*/
- public int getCount(DSpaceObject dso) throws ItemCountException;
+ int getCount(Context context, DSpaceObject dso);
}
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java
deleted file mode 100644
index 722be645fdaa..000000000000
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOFactory.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-package org.dspace.browse;
-
-import java.lang.reflect.InvocationTargetException;
-
-import org.dspace.core.Context;
-import org.dspace.services.ConfigurationService;
-import org.dspace.services.factory.DSpaceServicesFactory;
-
-/**
- * Factory class to allow us to load the correct DAO for registering
- * item count information
- *
- * @author Richard Jones
- * @author Ivan Masár
- */
-public class ItemCountDAOFactory {
-
- /**
- * Default constructor
- */
- private ItemCountDAOFactory() { }
-
- /**
- * Get an instance of ItemCountDAO which supports the correct storage backend
- * for the specific DSpace instance.
- *
- * @param context DSpace Context
- * @return DAO
- * @throws ItemCountException if count error
- */
- public static ItemCountDAO getInstance(Context context)
- throws ItemCountException {
-
- /** Log4j logger */
- ItemCountDAO dao = null;
-
- ConfigurationService configurationService
- = DSpaceServicesFactory.getInstance().getConfigurationService();
- String className = configurationService.getProperty("ItemCountDAO.class");
-
- // SOLR implementation is the default since DSpace 4.0
- if (className == null) {
- dao = new ItemCountDAOSolr();
- } else {
- try {
- dao = (ItemCountDAO) Class.forName(className.trim())
- .getDeclaredConstructor()
- .newInstance();
- } catch (ClassNotFoundException | IllegalAccessException
- | InstantiationException | NoSuchMethodException
- | SecurityException | IllegalArgumentException
- | InvocationTargetException e) {
- throw new ItemCountException("The configuration for ItemCountDAO is invalid: " + className, e);
- }
- }
-
- dao.setContext(context);
- return dao;
- }
-}
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java
index d233270d813c..e4d0079fe20b 100644
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java
+++ b/dspace-api/src/main/java/org/dspace/browse/ItemCountDAOSolr.java
@@ -24,14 +24,12 @@
import org.dspace.discovery.SearchServiceException;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.indexobject.IndexableItem;
-import org.dspace.services.factory.DSpaceServicesFactory;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* Discovery (Solr) driver implementing ItemCountDAO interface to look up item
* count information in communities and collections. Caching operations are
* intentionally not implemented because Solr already is our cache.
- *
- * @author Ivan Masár, Andrea Bollini
*/
public class ItemCountDAOSolr implements ItemCountDAO {
/**
@@ -39,11 +37,6 @@ public class ItemCountDAOSolr implements ItemCountDAO {
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemCountDAOSolr.class);
- /**
- * DSpace context
- */
- private Context context;
-
/**
* Hold the communities item count obtained from SOLR after the first query. This only works
* well if the ItemCountDAO lifecycle is bound to the request lifecycle as
@@ -61,41 +54,28 @@ public class ItemCountDAOSolr implements ItemCountDAO {
/**
* Solr search service
*/
- SearchService searcher = DSpaceServicesFactory.getInstance().getServiceManager()
- .getServiceByName(SearchService.class.getName(), SearchService.class);
-
- /**
- * Set the dspace context to use
- *
- * @param context DSpace Context
- * @throws ItemCountException if count error
- */
- @Override
- public void setContext(Context context) throws ItemCountException {
- this.context = context;
- }
+ @Autowired
+ protected SearchService searchService;
/**
* Get the count of the items in the given container.
*
- * @param dso Dspace Context
+ * @param context DSpace context
+ * @param dso DspaceObject
* @return count
- * @throws ItemCountException if count error
*/
@Override
- public int getCount(DSpaceObject dso) throws ItemCountException {
- loadCount();
- Integer val;
+ public int getCount(Context context, DSpaceObject dso) {
+ loadCount(context);
+ Integer val = null;
if (dso instanceof Collection) {
- val = collectionsCount.get(String.valueOf(((Collection) dso).getID()));
+ val = collectionsCount.get(dso.getID().toString());
} else if (dso instanceof Community) {
- val = communitiesCount.get(String.valueOf(((Community) dso).getID()));
- } else {
- throw new ItemCountException("We can only count items in Communities or Collections");
+ val = communitiesCount.get(dso.getID().toString());
}
if (val != null) {
- return val.intValue();
+ return val;
} else {
return 0;
}
@@ -105,15 +85,15 @@ public int getCount(DSpaceObject dso) throws ItemCountException {
* make sure that the counts are actually fetched from Solr (if haven't been
* cached in a Map yet)
*
- * @throws ItemCountException if count error
+ * @param context DSpace Context
*/
- private void loadCount() throws ItemCountException {
+ private void loadCount(Context context) {
if (communitiesCount != null || collectionsCount != null) {
return;
}
- communitiesCount = new HashMap();
- collectionsCount = new HashMap();
+ communitiesCount = new HashMap<>();
+ collectionsCount = new HashMap<>();
DiscoverQuery query = new DiscoverQuery();
query.setFacetMinCount(1);
@@ -125,11 +105,13 @@ private void loadCount() throws ItemCountException {
DiscoveryConfigurationParameters.SORT.COUNT));
query.addFilterQueries("search.resourcetype:" + IndexableItem.TYPE); // count only items
query.addFilterQueries("NOT(discoverable:false)"); // only discoverable
+ query.addFilterQueries("withdrawn:false"); // only not withdrawn
+ query.addFilterQueries("archived:true"); // only archived
query.setMaxResults(0);
- DiscoverResult sResponse = null;
+ DiscoverResult sResponse;
try {
- sResponse = searcher.search(context, query);
+ sResponse = searchService.search(context, query);
List commCount = sResponse.getFacetResult("location.comm");
List collCount = sResponse.getFacetResult("location.coll");
for (FacetResult c : commCount) {
@@ -139,8 +121,7 @@ private void loadCount() throws ItemCountException {
collectionsCount.put(c.getAsFilterQuery(), (int) c.getCount());
}
} catch (SearchServiceException e) {
- log.error("caught exception: ", e);
- throw new ItemCountException(e);
+ log.error("Could not initialize Community/Collection Item Counts from Solr: ", e);
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java b/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java
deleted file mode 100644
index 533e6ecceb97..000000000000
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCountException.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-package org.dspace.browse;
-
-/**
- * Exception type to handle item count specific problems
- *
- * @author Richard Jones
- */
-public class ItemCountException extends Exception {
-
- public ItemCountException() {
- }
-
- public ItemCountException(String message) {
- super(message);
- }
-
- public ItemCountException(Throwable cause) {
- super(cause);
- }
-
- public ItemCountException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
diff --git a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
index 20c43fc37298..b5a695566976 100644
--- a/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
+++ b/dspace-api/src/main/java/org/dspace/browse/ItemCounter.java
@@ -13,26 +13,18 @@
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
-import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
-import org.dspace.web.ContextUtil;
+import org.springframework.beans.factory.annotation.Autowired;
/**
* This class provides a standard interface to all item counting
- * operations for communities and collections. It can be run from the
- * command line to prepare the cached data if desired, simply by
- * running:
+ * operations for communities and collections.
*
- * java org.dspace.browse.ItemCounter
- *
- * It can also be invoked via its standard API. In the event that
- * the data cache is not being used, this class will return direct
+ * In the event that the data cache is not being used, this class will return direct
* real time counts of content.
- *
- * @author Richard Jones
*/
public class ItemCounter {
/**
@@ -40,57 +32,15 @@ public class ItemCounter {
*/
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemCounter.class);
- /**
- * DAO to use to store and retrieve data
- */
- private ItemCountDAO dao;
-
- /**
- * DSpace Context
- */
- private Context context;
-
- /**
- * This field is used to hold singular instance of a class.
- * Singleton pattern is used but this class should be
- * refactored to modern DSpace approach (injectible service).
- */
-
- private static ItemCounter instance;
-
+ @Autowired
protected ItemService itemService;
+ @Autowired
protected ConfigurationService configurationService;
- private boolean showStrengths;
- private boolean useCache;
-
- /**
- * Construct a new item counter which will use the given DSpace Context
- *
- * @param context current context
- * @throws ItemCountException if count error
- */
- public ItemCounter(Context context) throws ItemCountException {
- this.context = context;
- this.dao = ItemCountDAOFactory.getInstance(this.context);
- this.itemService = ContentServiceFactory.getInstance().getItemService();
- this.configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
- this.showStrengths = configurationService.getBooleanProperty("webui.strengths.show", false);
- this.useCache = configurationService.getBooleanProperty("webui.strengths.cache", true);
- }
-
/**
- * Get the singular instance of a class.
- * It creates a new instance at the first usage of this method.
- *
- * @return instance af a class
- * @throws ItemCountException when error occurs
+ * Construct a new item counter
*/
- public static ItemCounter getInstance() throws ItemCountException {
- if (instance == null) {
- instance = new ItemCounter(ContextUtil.obtainCurrentRequestContext());
- }
- return instance;
+ protected ItemCounter() {
}
/**
@@ -103,17 +53,24 @@ public static ItemCounter getInstance() throws ItemCountException {
* If it is equal to 'false' it will count the number of items
* in the container in real time.
*
+ * @param context DSpace Context
* @param dso DSpaceObject
- * @return count
- * @throws ItemCountException when error occurs
+ * @return count (-1 is returned if count could not be determined or is disabled)
*/
- public int getCount(DSpaceObject dso) throws ItemCountException {
+ public int getCount(Context context, DSpaceObject dso) {
+ boolean showStrengths = configurationService.getBooleanProperty("webui.strengths.show", false);
+ boolean useCache = configurationService.getBooleanProperty("webui.strengths.cache", true);
if (!showStrengths) {
return -1;
}
if (useCache) {
- return dao.getCount(dso);
+ // NOTE: This bean is NOT Autowired above because it's a "prototype" bean which we want to reload
+ // occasionally. Each time the bean reloads it will update the cached item counts.
+ ItemCountDAO dao =
+ DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName("itemCountDAO",
+ ItemCountDAO.class);
+ return dao.getCount(context, dso);
}
// if we make it this far, we need to manually count
@@ -121,8 +78,8 @@ public int getCount(DSpaceObject dso) throws ItemCountException {
try {
return itemService.countItems(context, (Collection) dso);
} catch (SQLException e) {
- log.error("caught exception: ", e);
- throw new ItemCountException(e);
+ log.error("Error counting number of Items in Collection {} :", dso.getID(), e);
+ return -1;
}
}
@@ -130,8 +87,8 @@ public int getCount(DSpaceObject dso) throws ItemCountException {
try {
return itemService.countItems(context, ((Community) dso));
} catch (SQLException e) {
- log.error("caught exception: ", e);
- throw new ItemCountException(e);
+ log.error("Error counting number of Items in Community {} :", dso.getID(), e);
+ return -1;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/Bitstream.java b/dspace-api/src/main/java/org/dspace/content/Bitstream.java
index 451a3b75784d..5485735a2816 100644
--- a/dspace-api/src/main/java/org/dspace/content/Bitstream.java
+++ b/dspace-api/src/main/java/org/dspace/content/Bitstream.java
@@ -307,10 +307,18 @@ public Collection getCollection() {
return collection;
}
+ public void setCollection(Collection collection) {
+ this.collection = collection;
+ }
+
public Community getCommunity() {
return community;
}
+ public void setCommunity(Community community) {
+ this.community = community;
+ }
+
/**
* Get the asset store number where this bitstream is stored
*
diff --git a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
index a993959b7843..07b4f4073634 100644
--- a/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/BitstreamServiceImpl.java
@@ -500,10 +500,15 @@ public int countTotal(Context context) throws SQLException {
@Override
public Bitstream findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
index e70af09bb610..05097f2996c8 100644
--- a/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/BundleServiceImpl.java
@@ -563,10 +563,15 @@ public int getSupportsTypeConstant() {
@Override
public Bundle findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/Collection.java b/dspace-api/src/main/java/org/dspace/content/Collection.java
index dbe2d35efe1e..eecf2ddb4633 100644
--- a/dspace-api/src/main/java/org/dspace/content/Collection.java
+++ b/dspace-api/src/main/java/org/dspace/content/Collection.java
@@ -29,7 +29,6 @@
import javax.persistence.Transient;
import org.dspace.authorize.AuthorizeException;
-import org.dspace.browse.ItemCountException;
import org.dspace.content.comparator.NameAscendingComparator;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
@@ -140,6 +139,9 @@ public Bitstream getLogo() {
protected void setLogo(Bitstream logo) {
this.logo = logo;
+ if (logo != null) {
+ logo.setCollection(this);
+ }
setModified();
}
@@ -341,18 +343,4 @@ private CollectionService getCollectionService() {
}
return collectionService;
}
-
- /**
- * return count of the collection items
- *
- * @return int
- */
- public int countArchivedItems() {
- try {
- return collectionService.countArchivedItems(this);
- } catch (ItemCountException e) {
- throw new RuntimeException(e);
- }
- }
-
}
diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
index eaf26ca0501a..b4e52e8d5746 100644
--- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
@@ -35,7 +35,6 @@
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
-import org.dspace.browse.ItemCountException;
import org.dspace.browse.ItemCounter;
import org.dspace.content.dao.CollectionDAO;
import org.dspace.content.service.BitstreamService;
@@ -136,6 +135,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i
@Autowired(required = true)
protected WorkflowItemService> workflowItemService;
+ @Autowired
+ protected ItemCounter itemCounter;
+
protected CollectionServiceImpl() {
super();
}
@@ -908,10 +910,15 @@ public void updateLastModified(Context context, Collection collection) throws SQ
@Override
public Collection findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
@@ -1241,13 +1248,13 @@ public List findAllCollectionsByEntityType(Context context, String e
/**
* Returns total collection archived items
*
+ * @param context DSpace Context
* @param collection Collection
* @return total collection archived items
- * @throws ItemCountException
*/
@Override
- public int countArchivedItems(Collection collection) throws ItemCountException {
- return ItemCounter.getInstance().getCount(collection);
+ public int countArchivedItems(Context context, Collection collection) {
+ return itemCounter.getCount(context, collection);
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/content/Community.java b/dspace-api/src/main/java/org/dspace/content/Community.java
index dd6d978936df..4503b24cfa82 100644
--- a/dspace-api/src/main/java/org/dspace/content/Community.java
+++ b/dspace-api/src/main/java/org/dspace/content/Community.java
@@ -25,7 +25,6 @@
import javax.persistence.Transient;
import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.dspace.browse.ItemCountException;
import org.dspace.content.comparator.NameAscendingComparator;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
@@ -123,6 +122,9 @@ public Bitstream getLogo() {
void setLogo(Bitstream logo) {
this.logo = logo;
+ if (logo != null) {
+ logo.setCommunity(this);
+ }
setModified();
}
@@ -264,17 +266,4 @@ private CommunityService getCommunityService() {
}
return communityService;
}
-
- /**
- * return count of the community items
- *
- * @return int
- */
- public int countArchivedItems() {
- try {
- return communityService.countArchivedItems(this);
- } catch (ItemCountException e) {
- throw new RuntimeException(e);
- }
- }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
index 61e28fae1475..4435189768a9 100644
--- a/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/CommunityServiceImpl.java
@@ -25,7 +25,6 @@
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
-import org.dspace.browse.ItemCountException;
import org.dspace.browse.ItemCounter;
import org.dspace.content.dao.CommunityDAO;
import org.dspace.content.service.BitstreamService;
@@ -81,6 +80,8 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl imp
protected SubscribeService subscribeService;
@Autowired(required = true)
protected CrisMetricsService crisMetricsService;
+ @Autowired
+ protected ItemCounter itemCounter;
protected CommunityServiceImpl() {
super();
@@ -696,10 +697,15 @@ public void updateLastModified(Context context, Community community) {
@Override
public Community findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
@@ -716,13 +722,13 @@ public int countTotal(Context context) throws SQLException {
/**
* Returns total community archived items
*
+ * @param context DSpace context
* @param community Community
* @return total community archived items
- * @throws ItemCountException
*/
@Override
- public int countArchivedItems(Community community) throws ItemCountException {
- return ItemCounter.getInstance().getCount(community);
+ public int countArchivedItems(Context context, Community community) {
+ return itemCounter.getCount(context, community);
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java
index f520bbfbfdce..04d6cc2b2d38 100644
--- a/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/DSpaceObjectServiceImpl.java
@@ -250,6 +250,20 @@ public List addMetadata(Context context, T dso, MetadataField met
}
+ /**
+ * Add metadata value(s) to a MetadataField of a DSpace Object
+ * @param context current DSpace context
+ * @param dso DSpaceObject to modify
+ * @param metadataField MetadataField to add values to
+ * @param lang Language code to add
+ * @param values One or more metadata values to add
+ * @param authorities One or more authorities to add
+ * @param confidences One or more confidences to add (for authorities)
+ * @param placeSupplier Supplier of "place" for new metadata values
+ * @return List of newly added metadata values
+ * @throws SQLException if database error occurs
+ * @throws IllegalArgumentException for an empty list of values
+ */
public List addMetadata(Context context, T dso, MetadataField metadataField, String lang,
List values, List authorities, List confidences, Supplier placeSupplier)
throws SQLException {
@@ -261,6 +275,13 @@ public List addMetadata(Context context, T dso, MetadataField met
List values, List authorities, List confidences, Supplier placeSupplier,
Integer securityLevel) throws SQLException {
+ // Throw an error if we are attempting to add empty values
+ if (values == null || values.isEmpty()) {
+ throw new IllegalArgumentException("Cannot add empty values to a new metadata field " +
+ metadataField.toString() + " on object with uuid = " +
+ dso.getID().toString() + " and type = " + getTypeText(dso));
+ }
+
Collection collection = getCollection(context, dso);
boolean authorityControlled = metadataAuthorityService.isAuthorityAllowed(metadataField,
dso.getType(), collection);
@@ -432,20 +453,26 @@ public void addAndShiftRightSecuredMetadata(Context context, T dso, String schem
@Override
public MetadataValue addMetadata(Context context, T dso, MetadataField metadataField, String language,
String value, String authority, int confidence) throws SQLException {
- return addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority),
- Arrays.asList(confidence)).get(0);
+ List metadataValues =
+ addMetadata(context, dso, metadataField, language, Arrays.asList(value), Arrays.asList(authority),
+ Arrays.asList(confidence));
+ return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null;
}
@Override
public MetadataValue addMetadata(Context context, T dso, String schema, String element, String qualifier,
String lang, String value) throws SQLException {
- return addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value)).get(0);
+ List metadataValues =
+ addMetadata(context, dso, schema, element, qualifier, lang, Arrays.asList(value));
+ return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null;
}
@Override
public MetadataValue addMetadata(Context context, T dso, MetadataField metadataField, String language, String value)
throws SQLException {
- return addMetadata(context, dso, metadataField, language, Arrays.asList(value)).get(0);
+ List metadataValues =
+ addMetadata(context, dso, metadataField, language, Arrays.asList(value));
+ return CollectionUtils.isNotEmpty(metadataValues) ? metadataValues.get(0) : null;
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java
index 6666ad6f802c..babbb9efc7f6 100644
--- a/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/EntityTypeServiceImpl.java
@@ -158,7 +158,7 @@ public List getSubmitAuthorizedTypes(Context context)
sQuery.setFacetMinCount(1);
sQuery.setFacetLimit(Integer.MAX_VALUE);
sQuery.setFacetSort(FacetParams.FACET_SORT_INDEX);
- QueryResponse qResp = solrSearchCore.getSolr().query(sQuery);
+ QueryResponse qResp = solrSearchCore.getSolr().query(sQuery, solrSearchCore.REQUEST_METHOD);
FacetField facetField = qResp.getFacetField("search.entitytype");
if (Objects.nonNull(facetField)) {
for (Count c : facetField.getValues()) {
diff --git a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
index 7cdd5e1bae51..4d3e40f56c5f 100644
--- a/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/ItemServiceImpl.java
@@ -59,7 +59,9 @@
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.content.template.TemplateItemValueService;
import org.dspace.content.virtual.VirtualMetadataPopulator;
+import org.dspace.content.vo.MetadataValueVO;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
@@ -160,6 +162,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl implements It
protected WorkspaceItemService workspaceItemService;
@Autowired(required = true)
protected WorkflowItemService workflowItemService;
+ @Autowired
+ private TemplateItemValueService templateItemValueService;
@Autowired(required = true)
protected RelationshipService relationshipService;
@@ -396,9 +400,64 @@ public Item createTemplateItem(Context context, Collection collection) throws SQ
+ template.getID()));
return template;
- } else {
- return collection.getTemplateItem();
}
+ return collection.getTemplateItem();
+ }
+
+ @Override
+ public void populateWithTemplateItemMetadata(Context context, Collection collection, boolean template, Item item)
+ throws SQLException {
+
+ Item templateItem = collection.getTemplateItem();
+
+ Optional colEntityType = getDSpaceEntityType(collection);
+ Optional templateItemEntityType = getDSpaceEntityType(templateItem);
+
+ if (colEntityType.isPresent() && templateItemEntityType.isPresent() &&
+ !StringUtils.equals(colEntityType.get().getValue(), templateItemEntityType.get().getValue())) {
+ throw new IllegalStateException("The template item has entity type : (" +
+ templateItemEntityType.get().getValue() + ") different than collection entity type : " +
+ colEntityType.get().getValue());
+ }
+
+ if (colEntityType.isPresent() && templateItemEntityType.isEmpty()) {
+ MetadataValue original = colEntityType.get();
+ MetadataField metadataField = original.getMetadataField();
+ MetadataSchema metadataSchema = metadataField.getMetadataSchema();
+ // NOTE: dspace.entity.type = does not make sense
+ // the collection entity type is by default blank when a collection is first created
+ if (StringUtils.isNotBlank(original.getValue())) {
+ addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(),
+ metadataField.getQualifier(), original.getLanguage(), original.getValue());
+ }
+ }
+
+ if (template && (templateItem != null)) {
+ List md = getMetadata(templateItem, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
+
+ for (MetadataValue aMd : md) {
+ MetadataField metadataField = aMd.getMetadataField();
+ MetadataSchema metadataSchema = metadataField.getMetadataSchema();
+ List metadataValueFromTemplateList = templateItemValueService.value(context, item,
+ templateItem, aMd);
+
+ for (MetadataValueVO metadataValueFromTemplate : metadataValueFromTemplateList) {
+ addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(),
+ metadataField.getQualifier(), aMd.getLanguage(),
+ metadataValueFromTemplate.getValue(), metadataValueFromTemplate.getAuthority(),
+ metadataValueFromTemplate.getConfidence());
+ }
+ }
+ }
+ }
+
+ private Optional getDSpaceEntityType(DSpaceObject dSpaceObject) {
+ return Objects.nonNull(dSpaceObject) ? dSpaceObject.getMetadata()
+ .stream()
+ .filter(x -> x.getMetadataField().toString('.')
+ .equalsIgnoreCase("dspace.entity.type"))
+ .findFirst()
+ : Optional.empty();
}
@Override
@@ -1582,8 +1641,8 @@ private void addCustomPoliciesNotInPlace(Context context, DSpaceObject dso, List
}
/**
- * Check whether or not there is already an RP on the given dso, which has actionId={@link Constants.READ} and
- * resourceTypeId={@link ResourcePolicy.TYPE_CUSTOM}
+ * Check whether or not there is already an RP on the given dso, which has actionId={@link Constants#READ} and
+ * resourceTypeId={@link ResourcePolicy#TYPE_CUSTOM}
*
* @param context DSpace context
* @param dso DSpace object to check for custom read RP
@@ -1697,6 +1756,45 @@ public Iterator findUnfilteredByMetadataField(Context context, String sche
}
}
+ /**
+ * Returns an iterator of Items possessing the passed metadata field, or only
+ * those matching the passed value, if value is not Item.ANY
+ *
+ * @param context DSpace context object
+ * @param schema metadata field schema
+ * @param element metadata field element
+ * @param qualifier metadata field qualifier
+ * @param value field value or Item.ANY to match any value
+ * @return an iterator over the items matching that authority value
+ * @throws SQLException if database error
+ * An exception that provides information on a database access error or other errors.
+ * @throws AuthorizeException if authorization error
+ * Exception indicating the current user of the context does not have permission
+ * to perform a particular action.
+ * @throws IOException if IO error
+ * A general class of exceptions produced by failed or interrupted I/O operations.
+ */
+ @Override
+ public Iterator findByMetadataField(Context context,
+ String schema, String element, String qualifier, String value)
+ throws SQLException, AuthorizeException, IOException {
+ MetadataSchema mds = metadataSchemaService.find(context, schema);
+ if (mds == null) {
+ throw new IllegalArgumentException("No such metadata schema: " + schema);
+ }
+ MetadataField mdf = metadataFieldService.findByElement(context, mds, element, qualifier);
+ if (mdf == null) {
+ throw new IllegalArgumentException(
+ "No such metadata field: schema=" + schema + ", element=" + element + ", qualifier=" + qualifier);
+ }
+
+ if (Item.ANY.equals(value)) {
+ return itemDAO.findByMetadataField(context, mdf, null, true);
+ }
+ return itemDAO.findByMetadataField(context, mdf, value, true);
+ }
+
+
@Override
public Iterator findByMetadataQuery(Context context, List> listFieldList,
List query_op, List query_val, List collectionUuids,
@@ -1854,13 +1952,13 @@ public Iterator findByIds(Context context, List ids) throws SQLExc
@Override
public int countItems(Context context, Collection collection) throws SQLException {
- return itemDAO.countItems(context, collection, true, false);
+ return itemDAO.countItems(context, collection, true, false, true);
}
@Override
public int countAllItems(Context context, Collection collection) throws SQLException {
- return itemDAO.countItems(context, collection, true, false) + itemDAO.countItems(context, collection,
- false, true);
+ return itemDAO.countItems(context, collection, true, false, true) + itemDAO.countItems(context, collection,
+ false, true, true);
}
@Override
@@ -1869,7 +1967,7 @@ public int countItems(Context context, Community community) throws SQLException
List collections = communityService.getAllCollections(context, community);
// Now, lets count unique items across that list of collections
- return itemDAO.countItems(context, collections, true, false);
+ return itemDAO.countItems(context, collections, true, false, true);
}
@Override
@@ -1878,16 +1976,21 @@ public int countAllItems(Context context, Community community) throws SQLExcepti
List collections = communityService.getAllCollections(context, community);
// Now, lets count unique items across that list of collections
- return itemDAO.countItems(context, collections, true, false) + itemDAO.countItems(context, collections,
- false, true);
+ return itemDAO.countItems(context, collections, true, false, true) + itemDAO.countItems(context, collections,
+ false, false, true);
}
@Override
public Item findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
@@ -1910,19 +2013,19 @@ public int countTotal(Context context) throws SQLException {
@Override
public int countNotArchivedItems(Context context) throws SQLException {
// return count of items not in archive and also not withdrawn
- return itemDAO.countItems(context, false, false);
+ return itemDAO.countItems(context, false, false, true);
}
@Override
public int countArchivedItems(Context context) throws SQLException {
// return count of items in archive and also not withdrawn
- return itemDAO.countItems(context, true, false);
+ return itemDAO.countItems(context, true, false, true);
}
@Override
public int countWithdrawnItems(Context context) throws SQLException {
// return count of items that are not in archive and withdrawn
- return itemDAO.countItems(context, false, true);
+ return itemDAO.countItems(context, false, true, true );
}
@Override
@@ -2046,12 +2149,14 @@ public void setEntityType(Context context, Item item, String entityType) {
*/
@Override
protected void moveSingleMetadataValue(Context context, Item dso, int place, MetadataValue rr) {
+ // If this is a (virtual) metadata value representing a relationship,
+ // then we must also update the corresponding Relationship with the new place
if (rr instanceof RelationshipMetadataValue) {
try {
//Retrieve the applicable relationship
Relationship rs = relationshipService.find(context,
((RelationshipMetadataValue) rr).getRelationshipId());
- if (rs.getLeftItem() == dso) {
+ if (rs.getLeftItem().getID().equals(dso.getID())) {
rs.setLeftPlace(place);
} else {
rs.setRightPlace(place);
diff --git a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java
index f1a8e546ebb1..67e15a61249f 100644
--- a/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/WorkspaceItemServiceImpl.java
@@ -12,11 +12,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
import java.util.UUID;
-import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.DCInputsReaderException;
import org.dspace.app.util.Util;
@@ -32,7 +29,6 @@
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.content.template.TemplateItemValueService;
-import org.dspace.content.vo.MetadataValueVO;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
@@ -109,11 +105,18 @@ public WorkspaceItem find(Context context, int id) throws SQLException {
@Override
public WorkspaceItem create(Context context, Collection collection, boolean template)
throws AuthorizeException, SQLException {
- return create(context, collection, null, template);
+ return create(context, collection, null, template, false);
}
@Override
- public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template)
+ public WorkspaceItem create(Context context, Collection collection, boolean template, boolean isNewVersion)
+ throws AuthorizeException, SQLException {
+ return create(context, collection, null, template, isNewVersion);
+ }
+
+ @Override
+ public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template,
+ boolean isNewVersion)
throws AuthorizeException, SQLException {
// Check the user has permission to ADD to the collection
authorizeService.authorizeAction(context, collection, Constants.ADD);
@@ -142,57 +145,16 @@ public WorkspaceItem create(Context context, Collection collection, UUID uuid, b
}
// Copy template if appropriate
- Item templateItem = collection.getTemplateItem();
-
- Optional colEntityType = getDSpaceEntityType(collection);
- Optional templateItemEntityType = getDSpaceEntityType(templateItem);
-
- if (colEntityType.isPresent() && templateItemEntityType.isPresent() &&
- !StringUtils.equals(colEntityType.get().getValue(), templateItemEntityType.get().getValue())) {
- throw new IllegalStateException("The template item has entity type : (" +
- templateItemEntityType.get().getValue() + ") different than collection entity type : " +
- colEntityType.get().getValue());
- }
-
- if (colEntityType.isPresent() && templateItemEntityType.isEmpty()) {
- MetadataValue original = colEntityType.get();
- MetadataField metadataField = original.getMetadataField();
- MetadataSchema metadataSchema = metadataField.getMetadataSchema();
- // NOTE: dspace.entity.type = does not make sense
- // the collection entity type is by default blank when a collection is first created
- if (StringUtils.isNotBlank(original.getValue())) {
- itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(),
- metadataField.getQualifier(), original.getLanguage(), original.getValue());
- }
- }
-
- if (template && (templateItem != null)) {
- List templateMetadataValues = itemService.getMetadata(templateItem, Item.ANY, Item.ANY,
- Item.ANY, Item.ANY);
-
- for (MetadataValue templateMetadataValue : templateMetadataValues) {
-
- MetadataField metadataField = templateMetadataValue.getMetadataField();
- MetadataSchema metadataSchema = metadataField.getMetadataSchema();
-
- List metadataValueFromTemplateList = templateItemValueService.value(context, item,
- templateItem, templateMetadataValue);
-
- for (MetadataValueVO metadataValueFromTemplate : metadataValueFromTemplateList) {
- itemService.addMetadata(context, item, metadataSchema.getName(), metadataField.getElement(),
- metadataField.getQualifier(), templateMetadataValue.getLanguage(),
- metadataValueFromTemplate.getValue(), metadataValueFromTemplate.getAuthority(),
- metadataValueFromTemplate.getConfidence());
- }
- }
- }
+ itemService.populateWithTemplateItemMetadata(context, collection, template, item);
itemService.update(context, item);
// If configured, register identifiers (eg handle, DOI) now. This is typically used with the Show Identifiers
// submission step which previews minted handles and DOIs during the submission process. Default: false
+ // Additional check needed: if we are creating a new version of an existing item we skip the identifier
+ // generation here, as this will be performed when the new version is created in VersioningServiceImpl
if (DSpaceServicesFactory.getInstance().getConfigurationService()
- .getBooleanProperty("identifiers.submission.register", false)) {
+ .getBooleanProperty("identifiers.submission.register", false) && !isNewVersion) {
try {
// Get map of filters to use for identifier types, while the item is in progress
Map, Filter> filters = FilterUtils.getIdentifierFilters(true);
@@ -221,15 +183,6 @@ public WorkspaceItem create(Context context, Collection collection, UUID uuid, b
return workspaceItem;
}
- private Optional getDSpaceEntityType(DSpaceObject dSpaceObject) {
- return Objects.nonNull(dSpaceObject) ? dSpaceObject.getMetadata()
- .stream()
- .filter(x -> x.getMetadataField().toString('.')
- .equalsIgnoreCase("dspace.entity.type"))
- .findFirst()
- : Optional.empty();
- }
-
@Override
public WorkspaceItem create(Context c, WorkflowItem workflowItem) throws SQLException, AuthorizeException {
WorkspaceItem workspaceItem = workspaceItemDAO.create(c, new WorkspaceItem());
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
index 058f550cc8c6..9947a61c5ada 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/DCInputAuthority.java
@@ -163,8 +163,8 @@ public Choices getMatches(String query, int start, int limit, String locale) {
int found = 0;
List v = new ArrayList();
for (int i = 0; i < valuesLocale.length; ++i) {
- if (query == null || StringUtils.containsIgnoreCase(valuesLocale[i], query) ||
- StringUtils.containsIgnoreCase(labelsLocale[i], query)) {
+ // In a DCInputAuthority context, a user will want to query the labels, not the values
+ if (query == null || StringUtils.containsIgnoreCase(labelsLocale[i], query)) {
if (found >= start && v.size() < limit) {
v.add(new Choice(null, valuesLocale[i], labelsLocale[i]));
if (valuesLocale[i].equalsIgnoreCase(query)) {
diff --git a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java
index 65d0f25c3062..24a8f2ec2375 100644
--- a/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java
+++ b/dspace-api/src/main/java/org/dspace/content/authority/DSpaceControlledVocabulary.java
@@ -113,8 +113,9 @@ public boolean accept(File dir, String name) {
}
}
String vocabulariesPath = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getProperty(
- "dspace.dir") + "/config/controlled-vocabularies/";
+ .getProperty("dspace.dir") +
+ File.separator + "config" +
+ File.separator + "controlled-vocabularies";
String[] xmlFiles = (new File(vocabulariesPath)).list(new xmlFilter());
List names = new ArrayList();
for (String filename : xmlFiles) {
@@ -252,6 +253,7 @@ public Choice getChoice(String authKey, String locale) {
@Override
public boolean isHierarchical() {
+ init();
return true;
}
diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java
index 9042a3a7f523..0528c0c20570 100644
--- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java
+++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsRDFStreamDisseminationCrosswalk.java
@@ -59,7 +59,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out)
Bitstream cc = creativeCommonsService.getLicenseRdfBitstream((Item) dso);
if (cc != null) {
Utils.copy(bitstreamService.retrieve(context, cc), out);
- out.close();
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java
index edb9d60a623e..cd26b4d19cee 100644
--- a/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java
+++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/CreativeCommonsTextStreamDisseminationCrosswalk.java
@@ -65,7 +65,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out)
Bitstream cc = creativeCommonsService.getLicenseTextBitstream((Item) dso);
if (cc != null) {
Utils.copy(bitstreamService.retrieve(context, cc), out);
- out.close();
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java
index 75b884613db9..46858747870d 100644
--- a/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java
+++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/LicenseStreamDisseminationCrosswalk.java
@@ -57,7 +57,6 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out)
if (licenseBs != null) {
Utils.copy(bitstreamService.retrieve(context, licenseBs), out);
- out.close();
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java
index 7f6622841ba7..bd424598771c 100644
--- a/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java
+++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/METSRightsCrosswalk.java
@@ -432,31 +432,7 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean
//get what class of context this is
String contextClass = element.getAttributeValue("CONTEXTCLASS");
- ResourcePolicy rp = resourcePolicyService.create(context);
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-
- // get reference to the element
- // Note: we are assuming here that there will only ever be ONE
- // element. Currently there are no known use cases for multiple.
- Element permsElement = element.getChild("Permissions", METSRights_NS);
- if (permsElement == null) {
- log.error("No element was found. Skipping this element.");
- continue;
- }
-
- if (element.getAttributeValue("rpName") != null) {
- rp.setRpName(element.getAttributeValue("rpName"));
- }
- try {
- if (element.getAttributeValue("start-date") != null) {
- rp.setStartDate(sdf.parse(element.getAttributeValue("start-date")));
- }
- if (element.getAttributeValue("end-date") != null) {
- rp.setEndDate(sdf.parse(element.getAttributeValue("end-date")));
- }
- } catch (ParseException ex) {
- log.error("Failed to parse embargo date. The date needs to be in the format 'yyyy-MM-dd'.", ex);
- }
+ ResourcePolicy rp = null;
//Check if this permission pertains to Anonymous users
if (ANONYMOUS_CONTEXTCLASS.equals(contextClass)) {
@@ -464,22 +440,23 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean
Group anonGroup = groupService.findByName(context, Group.ANONYMOUS);
if (anonGroup == null) {
throw new CrosswalkInternalException(
- "The DSpace database has not been properly initialized. The Anonymous Group is " +
- "missing from the database.");
+ "The DSpace database has not been properly initialized. The Anonymous Group is " +
+ "missing from the database.");
}
- rp.setGroup(anonGroup);
+ rp = resourcePolicyService.create(context, null, anonGroup);
} else if (ADMIN_CONTEXTCLASS.equals(contextClass)) {
// else if this permission declaration pertains to Administrators
// get DSpace Administrator group
Group adminGroup = groupService.findByName(context, Group.ADMIN);
if (adminGroup == null) {
throw new CrosswalkInternalException(
- "The DSpace database has not been properly initialized. The Administrator Group is " +
- "missing from the database.");
+ "The DSpace database has not been properly initialized. " +
+ "The Administrator Group is " +
+ "missing from the database.");
}
- rp.setGroup(adminGroup);
+ rp = resourcePolicyService.create(context, null, adminGroup);
} else if (GROUP_CONTEXTCLASS.equals(contextClass)) {
// else if this permission pertains to another DSpace group
try {
@@ -498,18 +475,17 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean
//if not found, throw an error -- user should restore group from the SITE AIP
if (group == null) {
throw new CrosswalkInternalException("Cannot restore Group permissions on object ("
- + "type=" + Constants.typeText[dso
- .getType()] + ", "
- + "handle=" + dso.getHandle() + ", "
- + "ID=" + dso.getID()
- + "). The Group named '" + groupName + "' is" +
- " missing from DSpace. "
- + "Please restore this group using the SITE " +
- "AIP, or recreate it.");
+ + "type=" + Constants.typeText[dso.getType()] + ", "
+ + "handle=" + dso.getHandle() + ", "
+ + "ID=" + dso.getID()
+ + "). The Group named '" + groupName + "' is" +
+ " missing from DSpace. "
+ + "Please restore this group using the SITE " +
+ "AIP, or recreate it.");
}
//assign group to policy
- rp.setGroup(group);
+ rp = resourcePolicyService.create(context, null, group);
} catch (PackageException pe) {
//A PackageException will only be thrown if translateDefaultGroupName() fails
//We'll just wrap it as a CrosswalkException and throw it upwards
@@ -535,25 +511,52 @@ public void ingest(Context context, DSpaceObject dso, List ml, boolean
//if not found, throw an error -- user should restore person from the SITE AIP
if (person == null) {
throw new CrosswalkInternalException("Cannot restore Person permissions on object ("
- + "type=" + Constants.typeText[dso
- .getType()] + ", "
- + "handle=" + dso.getHandle() + ", "
- + "ID=" + dso.getID()
- + "). The Person with email/netid '" +
- personEmail + "' is missing from DSpace. "
- + "Please restore this Person object using the " +
- "SITE AIP, or recreate it.");
+ + "type=" + Constants.typeText[dso.getType()] + ", "
+ + "handle=" + dso.getHandle() + ", "
+ + "ID=" + dso.getID()
+ + "). The Person with email/netid '" +
+ personEmail + "' is missing from DSpace. "
+ + "Please restore this Person object using the " +
+ "SITE AIP, or recreate it.");
}
- //assign person to the policy
- rp.setEPerson(person);
+ //create rp with the person
+ rp = resourcePolicyService.create(context, person, null);
} else {
log.error("Unrecognized CONTEXTCLASS: " + contextClass);
}
+ if (rp != null) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+
+ // get reference to the element
+ // Note: we are assuming here that there will only ever be ONE
+ // element. Currently there are no known use cases for multiple.
+ Element permsElement = element.getChild("Permissions", METSRights_NS);
+ if (permsElement == null) {
+ log.error("No element was found. Skipping this element.");
+ continue;
+ }
+
+ if (element.getAttributeValue("rpName") != null) {
+ rp.setRpName(element.getAttributeValue("rpName"));
+ }
+ try {
+ if (element.getAttributeValue("start-date") != null) {
+ rp.setStartDate(sdf.parse(element.getAttributeValue("start-date")));
+ }
+ if (element.getAttributeValue("end-date") != null) {
+ rp.setEndDate(sdf.parse(element.getAttributeValue("end-date")));
+ }
+ } catch (ParseException ex) {
+ log.error("Failed to parse embargo date. The date needs to be in the format 'yyyy-MM-dd'.",
+ ex);
+ }
- //set permissions on policy add to list of policies
- rp.setAction(parsePermissions(permsElement));
- policies.add(rp);
+ //set permissions and type on policy and add to list of policies
+ rp.setAction(parsePermissions(permsElement));
+ rp.setRpType(ResourcePolicy.TYPE_CUSTOM);
+ policies.add(rp);
+ }
} //end if "Context" element
} //end for loop
diff --git a/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java b/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java
index 05fda2b97475..ad92018b2220 100644
--- a/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java
+++ b/dspace-api/src/main/java/org/dspace/content/crosswalk/SubscriptionDsoMetadataForEmailCompose.java
@@ -49,7 +49,7 @@ public void disseminate(Context context, DSpaceObject dso, OutputStream out) thr
for (String actualMetadata : metadata) {
String[] splitted = actualMetadata.split("\\.");
String qualifier = null;
- if (splitted.length == 1) {
+ if (splitted.length == 3) {
qualifier = splitted[2];
}
var metadataValue = itemService.getMetadataFirstValue(item, splitted[0], splitted[1], qualifier, ANY);
diff --git a/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java b/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java
index 0cae1c7e5192..73f15d1d0586 100644
--- a/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java
+++ b/dspace-api/src/main/java/org/dspace/content/dao/ItemDAO.java
@@ -145,7 +145,8 @@ public Iterator findAllByCollection(Context context, Collection collection
* @return item count
* @throws SQLException if database error
*/
- public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn)
+ int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable)
throws SQLException;
/**
@@ -161,8 +162,8 @@ public int countItems(Context context, Collection collection, boolean includeArc
* @return item count
* @throws SQLException if database error
*/
- public int countItems(Context context, List collections, boolean includeArchived,
- boolean includeWithdrawn) throws SQLException;
+ int countItems(Context context, List collections, boolean includeArchived,
+ boolean includeWithdrawn, boolean discoverable) throws SQLException;
/**
* Get all Items installed or withdrawn, discoverable, and modified since a Date.
@@ -197,7 +198,8 @@ public Iterator findAll(Context context, boolean archived,
* @return count of items
* @throws SQLException if database error
*/
- int countItems(Context context, boolean includeArchived, boolean includeWithdrawn) throws SQLException;
+ int countItems(Context context, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable) throws SQLException;
/**
* Count number of items from the specified submitter based on specific status flags
@@ -209,7 +211,8 @@ public Iterator findAll(Context context, boolean archived,
* @return count of items
* @throws SQLException if database error
*/
- public int countItems(Context context, EPerson submitter, boolean includeArchived, boolean includeWithdrawn)
+ int countItems(Context context, EPerson submitter, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable)
throws SQLException;
/**
diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java
index c0ef6ea42fce..befa1397a8ee 100644
--- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java
@@ -159,7 +159,8 @@ public List findAuthorizedByGroup(Context context, EPerson ePerson,
@Override
public List findCollectionsWithSubscribers(Context context) throws SQLException {
- return list(createQuery(context, "SELECT DISTINCT col FROM Subscription s join s.collection col"));
+ return list(createQuery(context, "SELECT DISTINCT c FROM Collection c JOIN Subscription s ON c.id = " +
+ "s.dSpaceObject"));
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
index 3b12c68dcedd..8e1b9e9b6a8c 100644
--- a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java
@@ -419,30 +419,35 @@ public Iterator findAllByCollection(Context context, Collection collection
}
@Override
- public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn)
+ public int countItems(Context context, Collection collection, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable)
throws SQLException {
Query query = createQuery(context,
"select count(i) from Item i join i.collections c " +
- "WHERE :collection IN c AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn");
+ "WHERE :collection IN c AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn " +
+ "AND discoverable=:discoverable");
query.setParameter("collection", collection);
query.setParameter("in_archive", includeArchived);
query.setParameter("withdrawn", includeWithdrawn);
+ query.setParameter("discoverable", discoverable);
return count(query);
}
@Override
public int countItems(Context context, List collections, boolean includeArchived,
- boolean includeWithdrawn) throws SQLException {
+ boolean includeWithdrawn, boolean discoverable) throws SQLException {
if (collections.size() == 0) {
return 0;
}
Query query = createQuery(context, "select count(distinct i) from Item i " +
"join i.collections collection " +
- "WHERE collection IN (:collections) AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn");
+ "WHERE collection IN (:collections) AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn AND " +
+ "discoverable=:discoverable");
query.setParameter("collections", collections);
query.setParameter("in_archive", includeArchived);
query.setParameter("withdrawn", includeWithdrawn);
+ query.setParameter("discoverable", discoverable);
return count(query);
}
@@ -465,24 +470,29 @@ public int countRows(Context context) throws SQLException {
}
@Override
- public int countItems(Context context, boolean includeArchived, boolean includeWithdrawn) throws SQLException {
+ public int countItems(Context context, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable) throws SQLException {
Query query = createQuery(context,
"SELECT count(*) FROM Item i " +
- "WHERE i.inArchive=:in_archive AND i.withdrawn=:withdrawn");
+ "WHERE i.inArchive=:in_archive AND i.withdrawn=:withdrawn AND discoverable=:discoverable");
query.setParameter("in_archive", includeArchived);
query.setParameter("withdrawn", includeWithdrawn);
+ query.setParameter("discoverable", discoverable);
return count(query);
}
@Override
- public int countItems(Context context, EPerson submitter, boolean includeArchived, boolean includeWithdrawn)
+ public int countItems(Context context, EPerson submitter, boolean includeArchived, boolean includeWithdrawn,
+ boolean discoverable)
throws SQLException {
Query query = createQuery(context,
"SELECT count(*) FROM Item i join i.submitter submitter " +
- "WHERE i.inArchive=:in_archive AND i.withdrawn=:withdrawn AND submitter = :submitter");
+ "WHERE i.inArchive=:in_archive AND i.withdrawn=:withdrawn AND submitter = :submitter AND " +
+ "discoverable=:discoverable");
query.setParameter("submitter", submitter);
query.setParameter("in_archive", includeArchived);
query.setParameter("withdrawn", includeWithdrawn);
+ query.setParameter("discoverable", discoverable);
return count(query);
}
diff --git a/dspace-api/src/main/java/org/dspace/content/edit/service/impl/EditItemServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/edit/service/impl/EditItemServiceImpl.java
index 68cdc0e94aeb..995565f68847 100644
--- a/dspace-api/src/main/java/org/dspace/content/edit/service/impl/EditItemServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/edit/service/impl/EditItemServiceImpl.java
@@ -132,7 +132,7 @@ public List findBySubmitter(Context context, EPerson ep, int pageSize,
*/
@Override
public int countBySubmitter(Context context, EPerson ep) throws SQLException {
- return itemDAO.countItems(context, ep, true, false);
+ return itemDAO.countItems(context, ep, true, false, true);
}
/* (non-Javadoc)
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
index 685fd9000da8..fd50ec8023e2 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSDisseminator.java
@@ -628,6 +628,7 @@ protected MdSec makeMdSec(Context context, DSpaceObject dso, Class mdSecClass,
// Disseminate crosswalk output to an outputstream
ByteArrayOutputStream disseminateOutput = new ByteArrayOutputStream();
sxwalk.disseminate(context, dso, disseminateOutput);
+ disseminateOutput.close();
// Convert output to an inputstream, so we can write to manifest or Zip file
ByteArrayInputStream crosswalkedStream = new ByteArrayInputStream(
disseminateOutput.toByteArray());
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
index 98277c4f9c06..0ed0abe21825 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/AbstractMETSIngester.java
@@ -636,6 +636,9 @@ protected DSpaceObject replaceObject(Context context, DSpaceObject dso,
owningCollection = inProgressSubmission.getCollection();
}
+ itemService.populateWithTemplateItemMetadata(context, owningCollection, params.useCollectionTemplate(),
+ item);
+
addLicense(context, item, license, owningCollection
, params);
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java
index 9e7d870076aa..9a8ae4606487 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/PackageUtils.java
@@ -503,7 +503,7 @@ public static DSpaceObject createDSpaceObject(Context context, DSpaceObject pare
wsi = workspaceItemService.create(context, (Collection)parent, params.useCollectionTemplate());
} else {
wsi = workspaceItemService.create(context, (Collection)parent,
- uuid, params.useCollectionTemplate());
+ uuid, params.useCollectionTemplate(), false);
}
// Please note that we are returning an Item which is *NOT* yet in the Archive,
diff --git a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java
index f627779af8dc..15e9f1b14494 100644
--- a/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java
+++ b/dspace-api/src/main/java/org/dspace/content/packager/RoleDisseminator.java
@@ -431,7 +431,7 @@ protected void writeEPerson(EPerson eperson, XMLStreamWriter writer,
if (emitPassword) {
PasswordHash password = ePersonService.getPasswordHash(eperson);
- if (null != password) {
+ if (null != password && password.getHashString() != null) {
writer.writeStartElement(PASSWORD_HASH);
String algorithm = password.getAlgorithm();
diff --git a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
index f06208e2d151..220831eed00c 100644
--- a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
+++ b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
@@ -15,7 +15,6 @@
import java.util.UUID;
import org.dspace.authorize.AuthorizeException;
-import org.dspace.browse.ItemCountException;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -553,9 +552,9 @@ public List findAllCollectionsByEntityType(Context context, String e
/**
* Returns total collection archived items
*
+ * @param context DSpace context
* @param collection Collection
* @return total collection archived items
- * @throws ItemCountException
*/
- int countArchivedItems(Collection collection) throws ItemCountException;
+ int countArchivedItems(Context context, Collection collection);
}
diff --git a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java
index c089bcec8df1..163baedf5ff2 100644
--- a/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java
+++ b/dspace-api/src/main/java/org/dspace/content/service/CommunityService.java
@@ -14,7 +14,6 @@
import java.util.UUID;
import org.dspace.authorize.AuthorizeException;
-import org.dspace.browse.ItemCountException;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -297,9 +296,9 @@ public void removeSubcommunity(Context context, Community parentCommunity, Commu
/**
* Returns total community archived items
*
+ * @param context DSpace context
* @param community Community
* @return total community archived items
- * @throws ItemCountException
*/
- int countArchivedItems(Community community) throws ItemCountException;
+ int countArchivedItems(Context context, Community community);
}
diff --git a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java
index 5883006a9180..1102d14dc639 100644
--- a/dspace-api/src/main/java/org/dspace/content/service/ItemService.java
+++ b/dspace-api/src/main/java/org/dspace/content/service/ItemService.java
@@ -84,6 +84,18 @@ public interface ItemService
*/
public Item createTemplateItem(Context context, Collection collection) throws SQLException, AuthorizeException;
+ /**
+ * Populate the given item with all template item specified metadata.
+ *
+ * @param context DSpace context object
+ * @param collection Collection (parent)
+ * @param template if true, the item inherits all collection's template item metadata
+ * @param item item to populate with template item specified metadata
+ * @throws SQLException if database error
+ */
+ public void populateWithTemplateItemMetadata (Context context, Collection collection, boolean template, Item item)
+ throws SQLException;
+
/**
* Get all the items in the archive. Only items with the "in archive" flag
* set are included. The order of the list is indeterminate.
@@ -729,11 +741,30 @@ public Iterator findArchivedByMetadataField(Context context, String schema
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
*/
- public Iterator findArchivedByMetadataField(Context context, String metadataField, String value)
+ Iterator findArchivedByMetadataField(Context context, String metadataField, String value)
throws SQLException, AuthorizeException;
- public Iterator findUnfilteredByMetadataField(Context context, String schema, String element,
- String qualifier, String value) throws SQLException, AuthorizeException;
+ Iterator findUnfilteredByMetadataField(
+ Context context, String schema, String element, String qualifier, String value
+ ) throws SQLException, AuthorizeException;
+
+ /**
+ * Returns an iterator of Items possessing the passed metadata field, or only
+ * those matching the passed value, if value is not Item.ANY
+ *
+ * @param context DSpace context object
+ * @param schema metadata field schema
+ * @param element metadata field element
+ * @param qualifier metadata field qualifier
+ * @param value field value or Item.ANY to match any value
+ * @return an iterator over the items matching that authority value
+ * @throws SQLException if database error
+ * @throws AuthorizeException if authorization error
+ * @throws IOException if IO error
+ */
+ Iterator findByMetadataField(
+ Context context, String schema, String element, String qualifier, String value
+ ) throws SQLException, AuthorizeException, IOException;
public Iterator findByMetadataQuery(Context context, List> listFieldList,
List query_op, List query_val, List collectionUuids,
diff --git a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java
index c8df68e43498..8559bcc61402 100644
--- a/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java
+++ b/dspace-api/src/main/java/org/dspace/content/service/WorkspaceItemService.java
@@ -56,6 +56,23 @@ public interface WorkspaceItemService extends InProgressSubmissionServicetrue, the workspace item starts as a copy
+ * of the collection's template item
+ * @param isNewVersion whether we are creating a new workspace item version of an existing item
+ * @return the newly created workspace item
+ * @throws SQLException if database error
+ * @throws AuthorizeException if authorization error
+ */
+ public WorkspaceItem create(Context context, Collection collection, boolean template, boolean isNewVersion)
+ throws AuthorizeException, SQLException;
+
/**
* Create a new workspace item, with a new ID. An Item is also created. The
* submitter is the current user in the context.
@@ -65,11 +82,13 @@ public WorkspaceItem create(Context context, Collection collection, boolean temp
* @param uuid the preferred uuid of the new item (used if restoring an item and retaining old uuid)
* @param template if true, the workspace item starts as a copy
* of the collection's template item
+ * @param isNewVersion whether we are creating a new workspace item version of an existing item
* @return the newly created workspace item
* @throws SQLException if database error
* @throws AuthorizeException if authorization error
*/
- public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template)
+ public WorkspaceItem create(Context context, Collection collection, UUID uuid, boolean template,
+ boolean isNewVersion)
throws AuthorizeException, SQLException;
public WorkspaceItem create(Context c, WorkflowItem wfi) throws SQLException, AuthorizeException;
diff --git a/dspace-api/src/main/java/org/dspace/core/Email.java b/dspace-api/src/main/java/org/dspace/core/Email.java
index 8cbfd6e1deac..96d40b8206cb 100644
--- a/dspace-api/src/main/java/org/dspace/core/Email.java
+++ b/dspace-api/src/main/java/org/dspace/core/Email.java
@@ -439,7 +439,7 @@ public void send() throws MessagingException, IOException {
for (String headerName : templateHeaders) {
String headerValue = (String) vctx.get(headerName);
if ("subject".equalsIgnoreCase(headerName)) {
- if (null != headerValue) {
+ if ((subject == null || subject.isEmpty()) && null != headerValue) {
subject = headerValue;
}
} else if ("charset".equalsIgnoreCase(headerName)) {
diff --git a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java
index afec0b95f69b..038232a247cb 100644
--- a/dspace-api/src/main/java/org/dspace/core/I18nUtil.java
+++ b/dspace-api/src/main/java/org/dspace/core/I18nUtil.java
@@ -101,14 +101,14 @@ private static Locale makeLocale(String localeSpec) {
*/
public static Locale getEPersonLocale(EPerson ep) {
if (ep == null) {
- log.error("No EPerson specified, returning default locale");
+ log.info("No EPerson specified, returning default locale");
return I18nUtil.getDefaultLocale();
}
String lang = ep.getLanguage();
if (StringUtils.isBlank(lang)) {
- log.error("No language specified for EPerson " + ep.getID());
+ log.info("No language specified for EPerson " + ep.getID() + ", returning default locale");
return I18nUtil.getDefaultLocale();
}
@@ -271,7 +271,7 @@ public static String getMessage(String key, Locale locale) {
String message = messages.getString(key.trim());
return message;
} catch (MissingResourceException e) {
- log.error("'" + key + "' translation undefined in locale '"
+ log.warn("'" + key + "' translation undefined in locale '"
+ locale.toString() + "'");
return key;
}
diff --git a/dspace-api/src/main/java/org/dspace/core/UUIDIterator.java b/dspace-api/src/main/java/org/dspace/core/UUIDIterator.java
index 7cd2616ff6e7..5d7c16cf7d1a 100644
--- a/dspace-api/src/main/java/org/dspace/core/UUIDIterator.java
+++ b/dspace-api/src/main/java/org/dspace/core/UUIDIterator.java
@@ -19,10 +19,11 @@
/**
* Iterator implementation which allows to iterate over items and commit while
- * iterating. Using a list of UUID the iterator doesn't get invalidated after a
- * commit
+ * iterating. Using an iterator over previous retrieved UUIDs the iterator doesn't
+ * get invalidated after a commit that would instead close the database ResultSet
*
* @author stefano.maffei at 4science.com
+ * @author Andrea Bollini (andrea.bollini at 4science.com)
* @param class type
*/
public class UUIDIterator extends AbstractIterator {
diff --git a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java
index 59f898627832..6dadcbfc61a7 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/indexobject/IndexFactoryImpl.java
@@ -67,7 +67,14 @@ public SolrInputDocument buildDocument(Context context, T indexableObject) throw
//Do any additional indexing, depends on the plugins
for (SolrServiceIndexPlugin solrServiceIndexPlugin : ListUtils.emptyIfNull(solrServiceIndexPlugins)) {
- solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc);
+ try {
+ solrServiceIndexPlugin.additionalIndex(context, indexableObject, doc);
+ } catch (Exception e) {
+ log.error("An error occurred while indexing additional fields. " +
+ "Could not fully index item with UUID: {}. Plugin: {}",
+ indexableObject.getUniqueIndexID(), solrServiceIndexPlugin.getClass().getSimpleName());
+
+ }
}
return doc;
@@ -85,7 +92,7 @@ public void writeDocument(Context context, T indexableObject, SolrInputDocument
writeDocument(solrInputDocument, null);
} catch (Exception e) {
log.error("Error occurred while writing SOLR document for {} object {}",
- indexableObject.getType(), indexableObject.getID(), e);
+ indexableObject.getType(), indexableObject.getID(), e);
}
}
@@ -105,8 +112,8 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea
&& !streams.isEmpty()) {
// limit full text indexing to first 100,000 characters unless configured otherwise
final int charLimit = DSpaceServicesFactory.getInstance().getConfigurationService()
- .getIntProperty("discovery.solr.fulltext.charLimit",
- 100000);
+ .getIntProperty("discovery.solr.fulltext.charLimit",
+ 100000);
// Use Tika's Text parser as the streams are always from the TEXT bundle (i.e. already extracted text)
TextAndCSVParser tikaParser = new TextAndCSVParser();
@@ -117,6 +124,18 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea
// Use Apache Tika to parse the full text stream(s)
try (InputStream fullTextStreams = streams.getStream()) {
tikaParser.parse(fullTextStreams, tikaHandler, tikaMetadata, tikaContext);
+
+ // Write Tika metadata to "tika_meta_*" fields.
+ // This metadata is not very useful right now,
+ // but we'll keep it just in case it becomes more useful.
+ for (String name : tikaMetadata.names()) {
+ for (String value : tikaMetadata.getValues(name)) {
+ doc.addField("tika_meta_" + name, value);
+ }
+ }
+
+ // Save (parsed) full text to "fulltext" field
+ doc.addField("fulltext", tikaHandler.toString());
} catch (SAXException saxe) {
// Check if this SAXException is just a notice that this file was longer than the character limit.
// Unfortunately there is not a unique, public exception type to catch here. This error is thrown
@@ -125,30 +144,23 @@ protected void writeDocument(SolrInputDocument doc, FullTextContentStreams strea
if (saxe.getMessage().contains("limit has been reached")) {
// log that we only indexed up to that configured limit
log.info("Full text is larger than the configured limit (discovery.solr.fulltext.charLimit)."
- + " Only the first {} characters were indexed.", charLimit);
+ + " Only the first {} characters were indexed.", charLimit);
} else {
log.error("Tika parsing error. Could not index full text.", saxe);
throw new IOException("Tika parsing error. Could not index full text.", saxe);
}
- } catch (TikaException ex) {
+ } catch (TikaException | IOException ex) {
log.error("Tika parsing error. Could not index full text.", ex);
throw new IOException("Tika parsing error. Could not index full text.", ex);
+ } finally {
+ // Add document to index
+ solr.add(doc);
}
-
- // Write Tika metadata to "tika_meta_*" fields.
- // This metadata is not very useful right now, but we'll keep it just in case it becomes more useful.
- for (String name : tikaMetadata.names()) {
- for (String value : tikaMetadata.getValues(name)) {
- doc.addField("tika_meta_" + name, value);
- }
- }
-
- // Save (parsed) full text to "fulltext" field
- doc.addField("fulltext", tikaHandler.toString());
+ return;
}
-
// Add document to index
solr.add(doc);
+
}
}
diff --git a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java
index 2188dcb81579..c5e4c8054b1d 100644
--- a/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/eperson/EPersonServiceImpl.java
@@ -143,10 +143,15 @@ public EPerson getSystemEPerson(Context c)
@Override
public EPerson findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUID.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
index a05c73a070fa..493ed5059f05 100644
--- a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
@@ -881,10 +881,15 @@ protected Set getChildren(Map> parents, UUID parent) {
@Override
public Group findByIdOrLegacyId(Context context, String id) throws SQLException {
- if (org.apache.commons.lang3.StringUtils.isNumeric(id)) {
- return findByLegacyId(context, Integer.parseInt(id));
- } else {
- return find(context, UUIDUtils.fromString(id));
+ try {
+ if (StringUtils.isNumeric(id)) {
+ return findByLegacyId(context, Integer.parseInt(id));
+ } else {
+ return find(context, UUID.fromString(id));
+ }
+ } catch (IllegalArgumentException e) {
+ // Not a valid legacy ID or valid UUID
+ return null;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
index bed8c044dd8a..2fe3f7d93063 100644
--- a/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
+++ b/dspace-api/src/main/java/org/dspace/harvest/OAIHarvester.java
@@ -36,6 +36,7 @@
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
@@ -868,12 +869,12 @@ private Optional getMetadataIdentifier(Element record) {
* @param item a newly created, but not yet installed, DSpace Item
* @return null or the handle to be used.
*/
- private String extractHandle(Item item) {
- String[] acceptedHandleServers = configurationService.getArrayProperty("oai.harvester.acceptedHandleServer",
- new String[] { "hdl.handle.net" });
+ protected String extractHandle(Item item) {
+ String[] acceptedHandleServers = configurationService
+ .getArrayProperty("oai.harvester.acceptedHandleServer", new String[] {"hdl.handle.net"});
- String[] rejectedHandlePrefixes = configurationService.getArrayProperty("oai.harvester.rejectedHandlePrefix",
- new String[] { "123456789" });
+ String[] rejectedHandlePrefixes = configurationService
+ .getArrayProperty("oai.harvester.rejectedHandlePrefix", new String[] {"123456789"});
List values = itemService.getMetadata(item, "dc", "identifier", Item.ANY, Item.ANY);
@@ -891,12 +892,9 @@ private String extractHandle(Item item) {
for (String server : acceptedHandleServers) {
if (urlPieces[2].equals(server)) {
- for (String prefix : rejectedHandlePrefixes) {
- if (!urlPieces[3].equals(prefix)) {
- return urlPieces[3] + "/" + urlPieces[4];
- }
+ if (Arrays.stream(rejectedHandlePrefixes).noneMatch(prefix -> prefix.equals(urlPieces[3]))) {
+ return urlPieces[3] + "/" + urlPieces[4];
}
-
}
}
}
diff --git a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java
index 37c2888e449e..0a37523c5436 100644
--- a/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java
+++ b/dspace-api/src/main/java/org/dspace/identifier/DOIIdentifierProvider.java
@@ -1109,8 +1109,9 @@ protected void removeDOIFromObject(Context context, DSpaceObject dso, String doi
}
itemService.clearMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null);
- itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null,
- remainder);
+ if (!remainder.isEmpty()) {
+ itemService.addMetadata(context, item, MD_SCHEMA, DOI_ELEMENT, DOI_QUALIFIER, null, remainder);
+ }
itemService.update(context, item);
}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java
new file mode 100644
index 000000000000..1b6da9d37b16
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefAbstractProcessor.java
@@ -0,0 +1,123 @@
+/**
+ * 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.crossref;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+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.contributor.JsonPathMetadataProcessor;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+public class CrossRefAbstractProcessor implements JsonPathMetadataProcessor {
+
+ private final static Logger log = LogManager.getLogger();
+
+ private String path;
+
+ @Override
+ public Collection processMetadata(String json) {
+ JsonNode rootNode = convertStringJsonToJsonNode(json);
+ JsonNode abstractNode = rootNode.at(path);
+ Collection values = new ArrayList<>();
+ if (!abstractNode.isMissingNode()) {
+ String abstractValue = abstractNode.textValue();
+ if (StringUtils.isNotEmpty(abstractValue)) {
+ abstractValue = prettifyAbstract(abstractValue);
+ if (abstractValue != null) {
+ values.add(abstractValue);
+ }
+ }
+ }
+ return values;
+ }
+
+ /**
+ * remove JATS markup from abstract
+ *
+ * @param abstractValue abstract with JATS markup
+ * @return abstract without JATS markup
+ */
+ private String prettifyAbstract(String abstractValue) {
+ if (!abstractValue.contains("";
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ Document xmlDoc;
+ try {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ InputSource is = new InputSource(new StringReader(xmlString));
+ xmlDoc = builder.parse(is);
+ } catch (SAXException | IOException | ParserConfigurationException e) {
+ log.warn("unable to parse XML markup in CrossRef abstract field: " + e.getMessage());
+ return null;
+ }
+
+ StringBuilder sb = new StringBuilder();
+
+ NodeList rootElements = xmlDoc.getElementsByTagName("root");
+ Node rootElement = rootElements.item(0);
+ NodeList childElements = rootElement.getChildNodes();
+ for (int i = 0; i < childElements.getLength(); i++) {
+ Node childElement = childElements.item(i);
+ String nodeName = childElement.getNodeName();
+ if (StringUtils.equals(nodeName, "jats:title")) {
+ if (! StringUtils.equals(childElement.getTextContent(), "Abstract")) {
+ sb.append(childElement.getTextContent());
+ sb.append("\n");
+ }
+ } else if (StringUtils.equals(nodeName, "jats:sec")) {
+ NodeList secElements = childElement.getChildNodes();
+ for (int j = 0; j < secElements.getLength(); j++) {
+ Node secChildElement = secElements.item(j);
+ sb.append(secChildElement.getTextContent());
+ sb.append("\n");
+ }
+ sb.append("\n");
+ }
+ }
+
+ return sb.toString().trim();
+ }
+
+ 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;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java
index 5c4c49deaec9..05d3798af110 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/crossref/CrossRefImportMetadataSourceServiceImpl.java
@@ -133,7 +133,7 @@ private class SearchByQueryCallable implements Callable> {
private SearchByQueryCallable(String queryString, Integer maxResult, Integer start) {
query = new Query();
- query.addParameter("query", queryString);
+ query.addParameter("query", StringUtils.trim(queryString));
query.addParameter("count", maxResult);
query.addParameter("start", start);
}
@@ -165,7 +165,9 @@ public List call() throws Exception {
Iterator nodes = jsonNode.at("/message/items").iterator();
while (nodes.hasNext()) {
JsonNode node = nodes.next();
- results.add(transformSourceRecords(node.toString()));
+ if (!node.isMissingNode()) {
+ results.add(transformSourceRecords(node.toString()));
+ }
}
return results;
}
@@ -187,14 +189,15 @@ private SearchByIdCallable(Query query) {
private SearchByIdCallable(String id) {
this.query = new Query();
- query.addParameter("id", id);
+ query.addParameter("id", StringUtils.trim(id));
}
@Override
public List call() throws Exception {
List results = new ArrayList<>();
+ URIBuilder uriBuilder = new URIBuilder(url);
String ID = URLDecoder.decode(query.getParameterAsClass("id", String.class), "UTF-8");
- URIBuilder uriBuilder = new URIBuilder(url + "/" + ID);
+ uriBuilder.setPath(uriBuilder.getPath() + "/" + ID);
Map> params = new HashMap>();
String responseString = liveImportClient.executeHttpGetRequest(1000, uriBuilder.toString(), params);
if (StringUtils.isEmpty(responseString)) {
@@ -202,7 +205,9 @@ public List call() throws Exception {
}
JsonNode jsonNode = convertStringJsonToJsonNode(responseString);
JsonNode messageNode = jsonNode.at("/message");
- results.add(transformSourceRecords(messageNode.toString()));
+ if (!messageNode.isMissingNode()) {
+ results.add(transformSourceRecords(messageNode.toString()));
+ }
return results;
}
}
@@ -259,7 +264,9 @@ public List call() throws Exception {
Iterator nodes = jsonNode.at("/message/items").iterator();
while (nodes.hasNext()) {
JsonNode node = nodes.next();
- results.add(transformSourceRecords(node.toString()));
+ if (!node.isMissingNode()) {
+ results.add(transformSourceRecords(node.toString()));
+ }
}
return results;
}
@@ -280,7 +287,7 @@ private class CountByQueryCallable implements Callable {
private CountByQueryCallable(String queryString) {
query = new Query();
- query.addParameter("query", queryString);
+ query.addParameter("query", StringUtils.trim(queryString));
}
private CountByQueryCallable(Query query) {
@@ -314,7 +321,7 @@ private class DoiCheckCallable implements Callable {
private DoiCheckCallable(final String id) {
final Query query = new Query();
- query.addParameter("id", id);
+ query.addParameter("id", StringUtils.trim(id));
this.query = query;
}
@@ -325,7 +332,8 @@ private DoiCheckCallable(final Query query) {
@Override
public Integer call() throws Exception {
Map> params = new HashMap>();
- URIBuilder uriBuilder = new URIBuilder(url + "/" + query.getParameterAsClass("id", String.class));
+ URIBuilder uriBuilder = new URIBuilder(url);
+ uriBuilder.setPath(uriBuilder.getPath() + "/" + query.getParameterAsClass("id", String.class));
String responseString = liveImportClient.executeHttpGetRequest(1000, uriBuilder.toString(), params);
JsonNode jsonNode = convertStringJsonToJsonNode(responseString);
return StringUtils.equals(jsonNode.at("/status").toString(), "ok") ? 1 : 0;
@@ -345,4 +353,4 @@ public void setUrl(String url) {
this.url = url;
}
-}
\ No newline at end of file
+}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java
index a11f2bc2471d..6c65d96b375d 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/datacite/DataCiteImportMetadataSourceServiceImpl.java
@@ -73,8 +73,32 @@ public ImportRecord getRecord(String recordId) throws MetadataSourceException {
@Override
public int getRecordsCount(String query) throws MetadataSourceException {
- Collection records = getRecords(query, 0, -1);
- return records == null ? 0 : records.size();
+ String id = getID(query);
+ Map> params = new HashMap<>();
+ Map uriParameters = new HashMap<>();
+ params.put("uriParameters", uriParameters);
+ if (StringUtils.isBlank(id)) {
+ id = query;
+ }
+ uriParameters.put("query", id);
+ uriParameters.put("page[size]", "1");
+ int timeoutMs = configurationService.getIntProperty("datacite.timeout", 180000);
+ String url = configurationService.getProperty("datacite.url", "https://api.datacite.org/dois/");
+ String responseString = liveImportClient.executeHttpGetRequest(timeoutMs, url, params);
+ JsonNode jsonNode = convertStringJsonToJsonNode(responseString);
+ if (jsonNode == null) {
+ log.warn("DataCite returned invalid JSON");
+ throw new MetadataSourceException("Could not read datacite source");
+ }
+ JsonNode dataNode = jsonNode.at("/meta/total");
+ if (dataNode != null) {
+ try {
+ return Integer.valueOf(dataNode.toString());
+ } catch (Exception e) {
+ log.debug("Could not read integer value" + dataNode.toString());
+ }
+ }
+ return 0;
}
@Override
@@ -95,6 +119,17 @@ public Collection getRecords(String query, int start, int count) t
id = query;
}
uriParameters.put("query", id);
+ // start = current dspace page / datacite page number starting with 1
+ // dspace rounds up/down to the next configured pagination settings.
+ if (start > 0 && count > 0) {
+ uriParameters.put("page[number]", Integer.toString((start / count) + 1));
+ }
+
+ // count = dspace page size / default datacite page size is currently 25 https://support.datacite.org/docs/pagination
+ if (count > 0) {
+ uriParameters.put("page[size]", Integer.toString(count));
+ }
+
int timeoutMs = configurationService.getIntProperty("datacite.timeout", 180000);
String url = configurationService.getProperty("datacite.url", "https://api.datacite.org/dois/");
String responseString = liveImportClient.executeHttpGetRequest(timeoutMs, url, params);
@@ -108,12 +143,16 @@ public Collection getRecords(String query, int start, int count) t
Iterator iterator = dataNode.iterator();
while (iterator.hasNext()) {
JsonNode singleDoiNode = iterator.next();
- String json = singleDoiNode.at("/attributes").toString();
- records.add(transformSourceRecords(json));
+ JsonNode singleDoiNodeAttribute = singleDoiNode.at("/attributes");
+ if (!singleDoiNodeAttribute.isMissingNode()) {
+ records.add(transformSourceRecords(singleDoiNodeAttribute.toString()));
+ }
}
} else {
- String json = dataNode.at("/attributes").toString();
- records.add(transformSourceRecords(json));
+ JsonNode singleDoiNodeAttribute = dataNode.at("/attributes");
+ if (!singleDoiNodeAttribute.isMissingNode()) {
+ records.add(transformSourceRecords(singleDoiNodeAttribute.toString()));
+ }
}
return records;
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java
index b2d2ea22b0c6..ba8e11c030e9 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/metadatamapping/contributor/AuthorMetadataContributor.java
@@ -93,7 +93,7 @@ public void setMetadataFieldMapping(
}
/**
- * Retrieve the the ScopusID, orcid, author name and affiliationID
+ * Retrieve the ScopusID, orcid, author name and affiliationID
* metadata associated with the given element object.
* If the value retrieved from the element is empty
* it is set PLACEHOLDER_PARENT_METADATA_VALUE
@@ -208,4 +208,4 @@ public void setCreatorMetadataContributor(
SimpleXpathMetadatumContributor creatorMetadataContributor) {
this.creatorMetadataContributor = creatorMetadataContributor;
}
-}
\ No newline at end of file
+}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java b/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java
index c384b8f8cc1c..e5d0279aba21 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/scopus/service/ScopusImportMetadataSourceServiceImpl.java
@@ -14,6 +14,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -24,6 +25,8 @@
import javax.el.MethodNotFoundException;
import org.apache.commons.lang3.StringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
import org.dspace.content.Item;
import org.dspace.importer.external.datamodel.ImportRecord;
import org.dspace.importer.external.datamodel.Query;
@@ -62,6 +65,8 @@ public class ScopusImportMetadataSourceServiceImpl extends AbstractImportMetadat
@Autowired
private LiveImportClient liveImportClient;
+ private final static Logger log = LogManager.getLogger();
+
public LiveImportClient getLiveImportClient() {
return liveImportClient;
}
@@ -395,10 +400,16 @@ private List splitToRecords(String recordsSrc) {
saxBuilder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
Document document = saxBuilder.build(new StringReader(recordsSrc));
Element root = document.getRootElement();
- List records = root.getChildren("entry",Namespace.getNamespace("http://www.w3.org/2005/Atom"));
+ String totalResults = root.getChildText("totalResults", Namespace.getNamespace("http://a9.com/-/spec/opensearch/1.1/"));
+ if (totalResults != null && "0".equals(totalResults)) {
+ log.debug("got Scopus API with empty response");
+ return Collections.emptyList();
+ }
+ List records = root.getChildren("entry", Namespace.getNamespace("http://www.w3.org/2005/Atom"));
return records;
} catch (JDOMException | IOException e) {
- return new ArrayList();
+ log.warn("got unexpected XML response from Scopus API: " + e.getMessage());
+ return Collections.emptyList();
}
}
@@ -434,4 +445,4 @@ public void setInstKey(String instKey) {
this.instKey = instKey;
}
-}
\ No newline at end of file
+}
diff --git a/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java b/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java
index 3aa760eff39e..b690c627c85e 100644
--- a/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java
+++ b/dspace-api/src/main/java/org/dspace/importer/external/service/DoiCheck.java
@@ -20,7 +20,16 @@
*/
public class DoiCheck {
- private static final List DOI_PREFIXES = Arrays.asList("http://dx.doi.org/", "https://dx.doi.org/");
+ private static final List DOI_PREFIXES = Arrays.asList(
+ "http://dx.doi.org/",
+ "https://dx.doi.org/",
+ "http://www-dx.doi.org/",
+ "https://www-dx.doi.org/",
+ "http://doi.org/",
+ "https://doi.org/",
+ "www.dx.doi.org/",
+ "dx.doi.org/",
+ "doi:");
private static final Pattern PATTERN = Pattern.compile("10.\\d{4,9}/[-._;()/:A-Z0-9]+" +
"|10.1002/[^\\s]+" +
diff --git a/dspace-api/src/main/java/org/dspace/scripts/Process.java b/dspace-api/src/main/java/org/dspace/scripts/Process.java
index 049b7845da50..e6d751a4a9c3 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/Process.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/Process.java
@@ -51,8 +51,8 @@ public class Process implements ReloadableEntity {
@Column(name = "process_id", unique = true, nullable = false)
private Integer processId;
- @ManyToOne
- @JoinColumn(name = "user_id", nullable = false)
+ @ManyToOne(fetch = FetchType.LAZY)
+ @JoinColumn(name = "user_id")
private EPerson ePerson;
@Column(name = "start_time")
diff --git a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
index 204da303c770..93c234c2a456 100644
--- a/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/statistics/SolrLoggerServiceImpl.java
@@ -85,6 +85,7 @@
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList;
+import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
@@ -151,6 +152,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
private SolrStatisticsCore solrStatisticsCore;
@Autowired
private GeoIpService geoIpService;
+ @Autowired
+ private AuthorizeService authorizeService;
/** URL to the current-year statistics core. Prior-year shards will have a year suffixed. */
private String statisticsCoreURL;
@@ -231,6 +234,15 @@ public void postView(DSpaceObject dspaceObject, HttpServletRequest request,
public void postView(DSpaceObject dspaceObject, HttpServletRequest request,
EPerson currentUser, String referrer, Date time) {
+ Context context = new Context();
+ // Do not record statistics for Admin users
+ try {
+ if (authorizeService.isAdmin(context, currentUser)) {
+ return;
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
if (solr == null) {
return;
diff --git a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java
index 02203db4e8ba..28d2cc9ce694 100644
--- a/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java
+++ b/dspace-api/src/main/java/org/dspace/storage/bitstore/S3BitStoreService.java
@@ -10,6 +10,7 @@
import static java.lang.String.valueOf;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -119,6 +120,11 @@ public class S3BitStoreService extends BaseBitStoreService {
private Integer connectionTimeout;
private String endpoint;
+ /**
+ * The maximum size of individual chunk to download from S3 when a file is accessed. Default 5Mb
+ */
+ private long bufferSize = 5 * 1024 * 1024;
+
/**
* container for all the assets
*/
@@ -406,20 +412,7 @@ public InputStream get(Bitstream bitstream) throws IOException {
if (isRegisteredBitstream(key)) {
key = key.substring(REGISTERED_FLAG.length());
}
- try {
- File tempFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp");
- tempFile.deleteOnExit();
-
- GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
-
- Download download = tm.download(getObjectRequest, tempFile);
- download.waitForCompletion();
-
- return new DeleteOnCloseFileInputStream(tempFile);
- } catch (AmazonClientException | InterruptedException e) {
- log.error("get(" + key + ")", e);
- throw new IOException(e);
- }
+ return new S3LazyInputStream(key, bufferSize, bitstream.getSizeBytes());
}
/**
@@ -804,4 +797,84 @@ public String path(Bitstream bitstream) throws IOException {
return tempFile.getAbsolutePath();
}
+ public void setBufferSize(long bufferSize) {
+ this.bufferSize = bufferSize;
+ }
+
+ /**
+ * This inner class represent an InputStream that uses temporary files to
+ * represent chunk of the object downloaded from S3. When the input stream is
+ * read the class look first to the current chunk and download a new one once if
+ * the current one as been fully read. The class is responsible to close a chunk
+ * as soon as a new one is retrieved, the last chunk is closed when the input
+ * stream itself is closed or the last byte is read (the first of the two)
+ */
+ public class S3LazyInputStream extends InputStream {
+ private InputStream currentChunkStream;
+ private String objectKey;
+ private long endOfChunk = -1;
+ private long chunkMaxSize;
+ private long currPos = 0;
+ private long fileSize;
+
+ public S3LazyInputStream(String objectKey, long chunkMaxSize, long fileSize) throws IOException {
+ this.objectKey = objectKey;
+ this.chunkMaxSize = chunkMaxSize;
+ this.endOfChunk = 0;
+ this.fileSize = fileSize;
+ downloadChunk();
+ }
+
+ @Override
+ public int read() throws IOException {
+ // is the current chunk completely read and other are available?
+ if (currPos == endOfChunk && currPos < fileSize) {
+ currentChunkStream.close();
+ downloadChunk();
+ }
+
+ int byteRead = currPos < endOfChunk ? currentChunkStream.read() : -1;
+ // do we get any data or are we at the end of the file?
+ if (byteRead != -1) {
+ currPos++;
+ } else {
+ currentChunkStream.close();
+ }
+ return byteRead;
+ }
+
+ /**
+ * This method download the next chunk from S3
+ *
+ * @throws IOException
+ * @throws FileNotFoundException
+ */
+ private void downloadChunk() throws IOException, FileNotFoundException {
+ // Create a DownloadFileRequest with the desired byte range
+ long startByte = currPos; // Start byte (inclusive)
+ long endByte = Long.min(startByte + chunkMaxSize - 1, fileSize - 1); // End byte (inclusive)
+ GetObjectRequest getRequest = new GetObjectRequest(bucketName, objectKey)
+ .withRange(startByte, endByte);
+
+ File currentChunkFile = File.createTempFile("s3-disk-copy-" + UUID.randomUUID(), "temp");
+ currentChunkFile.deleteOnExit();
+ try {
+ Download download = tm.download(getRequest, currentChunkFile);
+ download.waitForCompletion();
+ currentChunkStream = new DeleteOnCloseFileInputStream(currentChunkFile);
+ endOfChunk = endOfChunk + download.getProgress().getBytesTransferred();
+ } catch (AmazonClientException | InterruptedException e) {
+ currentChunkFile.delete();
+ throw new IOException(e);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (currentChunkStream != null) {
+ currentChunkStream.close();
+ }
+ }
+
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java b/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java
index a593fe8ae066..0cf4ae92c2ca 100644
--- a/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java
+++ b/dspace-api/src/main/java/org/dspace/submit/consumer/SubmissionConfigConsumer.java
@@ -8,15 +8,10 @@
package org.dspace.submit.consumer;
import org.apache.logging.log4j.Logger;
-import org.dspace.content.Collection;
-import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants;
import org.dspace.core.Context;
-import org.dspace.discovery.IndexingService;
-import org.dspace.discovery.indexobject.IndexableCollection;
import org.dspace.event.Consumer;
import org.dspace.event.Event;
-import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.submit.factory.SubmissionServiceFactory;
/**
@@ -28,11 +23,9 @@ public class SubmissionConfigConsumer implements Consumer {
/**
* log4j logger
*/
- private static Logger log = org.apache.logging.log4j.LogManager.getLogger(SubmissionConfigConsumer.class);
+ private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SubmissionConfigConsumer.class);
- IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager()
- .getServiceByName(IndexingService.class.getName(),
- IndexingService.class);
+ private boolean reloadNeeded = false;
@Override
public void initialize() throws Exception {
@@ -42,37 +35,27 @@ public void initialize() throws Exception {
@Override
public void consume(Context ctx, Event event) throws Exception {
int st = event.getSubjectType();
- int et = event.getEventType();
+ if (st == Constants.COLLECTION) {
+ // NOTE: IndexEventConsumer ("discovery") should be declared before this consumer
+ // We don't reindex the collection because it will normally be reindexed by IndexEventConsumer
+ // before the submission configurations are reloaded
- if ( st == Constants.COLLECTION ) {
- switch (et) {
- case Event.MODIFY_METADATA:
- // Submission configuration it's based on solr
- // for collection's entity type but, at this point
- // that info isn't indexed yet, we need to force it
- DSpaceObject subject = event.getSubject(ctx);
- Collection collectionFromDSOSubject = (Collection) subject;
- indexer.indexContent(ctx, new IndexableCollection (collectionFromDSOSubject), true, false, false);
- indexer.commit();
-
- log.debug("SubmissionConfigConsumer occured: " + event.toString());
- // reload submission configurations
- SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload();
- break;
-
- default:
- log.debug("SubmissionConfigConsumer occured: " + event.toString());
- // reload submission configurations
- SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload();
- break;
- }
+ log.debug("SubmissionConfigConsumer occurred: " + event);
+ // submission configurations should be reloaded
+ reloadNeeded = true;
}
}
@Override
public void end(Context ctx) throws Exception {
- // No-op
+ if (reloadNeeded) {
+ // reload submission configurations
+ SubmissionServiceFactory.getInstance().getSubmissionConfigService().reload();
+
+ // Reset the boolean used
+ reloadNeeded = false;
+ }
}
@Override
diff --git a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java
index 66f778947ab5..780854b72c10 100644
--- a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java
+++ b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigService.java
@@ -34,8 +34,6 @@ public interface SubmissionConfigService {
public int countSubmissionConfigs();
- public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle);
-
public SubmissionConfig getSubmissionConfigByCollection(Collection collection);
public SubmissionConfig getSubmissionConfigByName(String submitName);
diff --git a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java
index b76725107d44..8efe5b6c3b6e 100644
--- a/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/submit/service/SubmissionConfigServiceImpl.java
@@ -56,11 +56,6 @@ public int countSubmissionConfigs() {
return submissionConfigReader.countSubmissionConfigs();
}
- @Override
- public SubmissionConfig getSubmissionConfigByCollection(String collectionHandle) {
- return submissionConfigReader.getSubmissionConfigByCollection(collectionHandle);
- }
-
@Override
public SubmissionConfig getSubmissionConfigByCollection(Collection collection) {
return submissionConfigReader.getSubmissionConfigByCollection(collection);
diff --git a/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java b/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java
index 65f1ae9dcf9b..ea66827dba0c 100644
--- a/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java
+++ b/dspace-api/src/main/java/org/dspace/subscriptions/ContentGenerator.java
@@ -96,6 +96,7 @@ private String generateBodyMail(String type, List subscription
// .orElseGet(() -> entityType2Disseminator.get("Item"))
// .disseminate(context, item, out);
}
+ out.close();
return out.toString();
} catch (Exception e) {
log.error(e.getMessage(), e);
diff --git a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java
index 0cd8cb5fc64c..fa89b3441408 100644
--- a/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java
+++ b/dspace-api/src/main/java/org/dspace/versioning/DefaultItemVersionProvider.java
@@ -52,7 +52,9 @@ public class DefaultItemVersionProvider extends AbstractVersionProvider implemen
@Override
public Item createNewItemAndAddItInWorkspace(Context context, Item nativeItem) {
try {
- WorkspaceItem workspaceItem = workspaceItemService.create(context, nativeItem.getOwningCollection(), true);
+ WorkspaceItem workspaceItem = workspaceItemService.create(context, nativeItem.getOwningCollection(),
+ false,
+ true);
Item itemNew = workspaceItem.getItem();
itemService.update(context, itemNew);
return itemNew;
diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java
index 802c4b3c0da2..864a7d17c67f 100644
--- a/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/XmlWorkflowServiceImpl.java
@@ -1236,7 +1236,7 @@ protected WorkspaceItem returnToWorkspace(Context c, XmlWorkflowItem wfi)
public String getEPersonName(EPerson ePerson) {
String submitter = ePerson.getFullName();
- submitter = submitter + "(" + ePerson.getEmail() + ")";
+ submitter = submitter + " (" + ePerson.getEmail() + ")";
return submitter;
}
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql
new file mode 100644
index 000000000000..61f361625dd9
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql
@@ -0,0 +1,12 @@
+--
+-- 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/
+--
+
+DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null;
+
+ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk
+ CHECK (eperson_id is not null or epersongroup_id is not null) ;
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07.01__set_eperson_process_nullable.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07.01__set_eperson_process_nullable.sql
new file mode 100644
index 000000000000..39dc1115be49
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.03.07.01__set_eperson_process_nullable.sql
@@ -0,0 +1,9 @@
+--
+-- 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/
+--
+
+ALTER TABLE process ALTER COLUMN user_id DROP NOT NULL;
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql
new file mode 100644
index 000000000000..26de16f466ee
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2024.05.07__process_eperson_constraint.sql
@@ -0,0 +1,13 @@
+--
+-- 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/
+--
+
+-- If Process references an EPerson that no longer exists, set the "user_id" to null.
+UPDATE process SET user_id = null WHERE NOT EXISTS (SELECT * FROM EPerson where uuid = process.user_id);
+
+-- Add new constraint where process.user_id is nullified if referenced EPerson is deleted.
+ALTER TABLE process ADD CONSTRAINT process_eperson FOREIGN KEY (user_id) REFERENCES EPerson(uuid) ON DELETE SET NULL;
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql
new file mode 100644
index 000000000000..61f361625dd9
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2023.09.28__enforce_group_or_eperson_for_resourcepolicy.sql
@@ -0,0 +1,12 @@
+--
+-- 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/
+--
+
+DELETE FROM ResourcePolicy WHERE eperson_id is null and epersongroup_id is null;
+
+ALTER TABLE ResourcePolicy ADD CONSTRAINT resourcepolicy_eperson_and_epersongroup_not_nullobject_chk
+ CHECK (eperson_id is not null or epersongroup_id is not null) ;
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07.01__set_eperson_process_nullable.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07.01__set_eperson_process_nullable.sql
new file mode 100644
index 000000000000..39dc1115be49
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.03.07.01__set_eperson_process_nullable.sql
@@ -0,0 +1,9 @@
+--
+-- 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/
+--
+
+ALTER TABLE process ALTER COLUMN user_id DROP NOT NULL;
diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql
new file mode 100644
index 000000000000..26de16f466ee
--- /dev/null
+++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2024.05.07__process_eperson_constraint.sql
@@ -0,0 +1,13 @@
+--
+-- 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/
+--
+
+-- If Process references an EPerson that no longer exists, set the "user_id" to null.
+UPDATE process SET user_id = null WHERE NOT EXISTS (SELECT * FROM EPerson where uuid = process.user_id);
+
+-- Add new constraint where process.user_id is nullified if referenced EPerson is deleted.
+ALTER TABLE process ADD CONSTRAINT process_eperson FOREIGN KEY (user_id) REFERENCES EPerson(uuid) ON DELETE SET NULL;
diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
index 8a951d26b9e2..2a2747da20b1 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
@@ -27,6 +27,8 @@
+
+
@@ -491,6 +493,14 @@
+
+
+
+
+
+
+
+
diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml
index d2051496cfd7..d3989e9154b0 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/item-filters.xml
@@ -294,8 +294,7 @@
-
+
+
+
+ net.minidev
+ json-smart
+ 2.3
@@ -715,7 +715,7 @@
org.hamcrest
- hamcrest-all
+ hamcresttest
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java
index 38588ed1f4ba..8718ff302e59 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/BitstreamRestController.java
@@ -20,6 +20,7 @@
import javax.ws.rs.core.Response;
import org.apache.catalina.connector.ClientAbortException;
+import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
@@ -141,6 +142,7 @@ public ResponseEntity retrieve(@PathVariable UUID uuid, HttpServletResponse resp
.withBufferSize(BUFFER_SIZE)
.withFileName(name)
.withChecksum(bit.getChecksum())
+ .withLength(bit.getSizeBytes())
.withMimetype(mimetype)
.with(request)
.with(response);
@@ -169,6 +171,12 @@ public ResponseEntity retrieve(@PathVariable UUID uuid, HttpServletResponse resp
//Send the data
if (httpHeadersInitializer.isValid()) {
HttpHeaders httpHeaders = httpHeadersInitializer.initialiseHeaders();
+
+ if (RequestMethod.HEAD.name().equals(request.getMethod())) {
+ log.debug("HEAD request - no response body");
+ return ResponseEntity.ok().headers(httpHeaders).build();
+ }
+
return ResponseEntity.ok().headers(httpHeaders).body(bitstreamResource);
}
@@ -201,12 +209,39 @@ private boolean isNotAnErrorResponse(HttpServletResponse response) {
|| responseCode.equals(Response.Status.Family.REDIRECTION);
}
+ /**
+ * Check if a Bitstream of the specified format should always be downloaded (i.e. "content-disposition: attachment")
+ * or can be opened inline (i.e. "content-disposition: inline").
+ *
+ * NOTE that downloading via "attachment" is more secure, as the user's browser will not attempt to process or
+ * display the file. But, downloading via "inline" may be seen as more user-friendly for common formats.
+ * @param format BitstreamFormat
+ * @return true if always download ("attachment"). false if can be opened inline ("inline")
+ */
private boolean checkFormatForContentDisposition(BitstreamFormat format) {
- // never automatically download undefined formats
- if (format == null) {
- return false;
+ // Undefined or Unknown formats should ALWAYS be downloaded for additional security.
+ if (format == null || format.getSupportLevel() == BitstreamFormat.UNKNOWN) {
+ return true;
}
- List formats = List.of((configurationService.getArrayProperty("webui.content_disposition_format")));
+
+ // Load additional formats configured to require download
+ List configuredFormats = List.of(configurationService.
+ getArrayProperty("webui.content_disposition_format"));
+
+ // If configuration includes "*", then all formats will always be downloaded.
+ if (configuredFormats.contains("*")) {
+ return true;
+ }
+
+ // Define a download list of formats which DSpace forces to ALWAYS be downloaded.
+ // These formats can embed JavaScript which may be run in the user's browser if the file is opened inline.
+ // Therefore, DSpace blocks opening these formats inline as it could be used for an XSS attack.
+ List downloadOnlyFormats = List.of("text/html", "text/javascript", "text/xml", "rdf");
+
+ // Combine our two lists
+ List formats = ListUtils.union(downloadOnlyFormats, configuredFormats);
+
+ // See if the passed in format's MIME type or file extension is listed.
boolean download = formats.contains(format.getMIMEType());
if (!download) {
for (String ext : format.getExtensions()) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/CsrfRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CsrfRestController.java
new file mode 100644
index 000000000000..1695365477be
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/CsrfRestController.java
@@ -0,0 +1,63 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.data.rest.webmvc.ControllerUtils;
+import org.springframework.hateoas.RepresentationModel;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.web.csrf.CsrfToken;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Define GET /api/security/csrf endpoint which may be used to obtain a CSRF token from Spring Security.
+ * This is useful to force a CSRF token to be generated prior to a POST/PUT/PATCH request that requires it.
+ *
+ * NOTE: This endpoint should be used sparingly to ensure clients are NOT performing two requests for every modifying
+ * request (e.g. a GET /csrf followed by a POST/PUT/PATCH to another endpoint). Ideally, calling this endpoint is only
+ * necessary BEFORE the first POST/PUT/PATCH (if a CSRF token has not yet been obtained), or in scenarios where the
+ * client must *force* the CSRF token to be reloaded.
+ */
+@RequestMapping(value = "/api/security")
+@RestController
+public class CsrfRestController {
+
+ @Lazy
+ @Autowired
+ CsrfTokenRepository csrfTokenRepository;
+
+ /**
+ * Return the current CSRF token as defined by Spring Security.
+ * Inspired by
+ * https://docs.spring.io/spring-security/reference/5.8/migration/servlet/exploits.html#_i_am_using_a_single_page_application_with_httpsessioncsrftokenrepository
+ * @param request HTTP Request
+ * @param response HTTP response
+ * @param csrfToken injected CsrfToken by Spring Security
+ * @return An empty response with CSRF in header & cookie
+ */
+ @GetMapping("/csrf")
+ @PreAuthorize("permitAll()")
+ public ResponseEntity> getCsrf(HttpServletRequest request,
+ HttpServletResponse response,
+ CsrfToken csrfToken) {
+ // Save the CSRF token to our response using the currently enabled CsrfTokenRepository
+ csrfTokenRepository.saveToken(csrfToken, request, response);
+
+ // Return a 204 No Content status
+ return ControllerUtils.toEmptyResponse(HttpStatus.NO_CONTENT);
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java
index b7f94e379685..c0e8374f4240 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/OpenSearchController.java
@@ -285,7 +285,6 @@ private Map getLabels(HttpServletRequest request) {
labelMap.put(SyndicationFeed.MSG_UNTITLED, "notitle");
labelMap.put(SyndicationFeed.MSG_LOGO_TITLE, "logo.title");
labelMap.put(SyndicationFeed.MSG_FEED_DESCRIPTION, "general-feed.description");
- labelMap.put(SyndicationFeed.MSG_UITYPE, SyndicationFeed.UITYPE_JSPUI);
for (String selector : SyndicationFeed.getDescriptionSelectors()) {
labelMap.put("metadata." + selector, selector);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java
index 02ca816290d0..0f5378125d8f 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/authorization/impl/DeleteFeature.java
@@ -65,11 +65,13 @@ public class DeleteFeature implements AuthorizationFeature {
@Override
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
if (object instanceof BaseObjectRest) {
+ DSpaceObject dSpaceObject = (DSpaceObject) utils.getDSpaceAPIObjectFromRest(context, object);
+
if (object.getType().equals(WorkspaceItemRest.NAME)) {
- object = ((WorkspaceItemRest)object).getItem();
+ WorkspaceItem workspaceItem = (WorkspaceItem) utils.getDSpaceAPIObjectFromRest(context, object);
+ dSpaceObject = workspaceItem.getItem();
}
- DSpaceObject dSpaceObject = (DSpaceObject) utils.getDSpaceAPIObjectFromRest(context, object);
DSpaceObject parentObject = getParentObject(context, dSpaceObject);
switch (object.getType()) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java
index c936f9b622f9..1111274b09fd 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/AInprogressItemConverter.java
@@ -27,7 +27,6 @@
import org.dspace.content.InProgressSubmission;
import org.dspace.content.Item;
import org.dspace.core.Context;
-import org.dspace.eperson.EPerson;
import org.dspace.services.RequestService;
import org.dspace.services.model.Request;
import org.dspace.submit.factory.SubmissionServiceFactory;
@@ -83,21 +82,14 @@ public AInprogressItemConverter() throws SubmissionConfigReaderException {
protected void fillFromModel(T obj, R witem, Projection projection) {
Collection collection = obj.getCollection();
Item item = obj.getItem();
- EPerson submitter = null;
- submitter = obj.getSubmitter();
witem.setId(obj.getID());
- witem.setCollection(collection != null ? converter.toRest(collection, projection) : null);
- if (submitter != null) {
- witem.setSubmitter(converter.toRest(submitter, projection));
- }
// 1. retrieve the submission definition
// 2. iterate over the submission section to allow to plugin additional
// info
if (collection != null) {
-
addValidationErrorsToItem(obj, witem);
SubmissionDefinitionRest def = converter.toRest(getSubmissionConfig(item, collection), projection);
@@ -140,8 +132,6 @@ protected void fillFromModel(T obj, R witem, Projection projection) {
}
}
- // need to be after to have stored the submission-name in the request attribute
- witem.setItem(converter.toRest(item, projection));
}
private SubmissionConfig getSubmissionConfig(Item item, Collection collection) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
index e9b6aa03b85a..8cae60eca39e 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CollectionConverter.java
@@ -9,8 +9,11 @@
import org.dspace.app.rest.model.CollectionRest;
import org.dspace.app.rest.projection.Projection;
+import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.content.Collection;
+import org.dspace.content.service.CollectionService;
import org.dspace.discovery.IndexableObject;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
@@ -23,10 +26,14 @@
public class CollectionConverter extends DSpaceObjectConverter
implements IndexableObjectConverter {
+ @Autowired
+ CollectionService collectionService;
+
@Override
public CollectionRest convert(Collection collection, Projection projection) {
CollectionRest resource = super.convert(collection, projection);
- resource.setArchivedItemsCount(collection.countArchivedItems());
+ resource.setArchivedItemsCount(
+ collectionService.countArchivedItems(ContextUtil.obtainCurrentRequestContext(), collection));
return resource;
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
index a90ad3cfe644..62062e08139c 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/CommunityConverter.java
@@ -9,8 +9,11 @@
import org.dspace.app.rest.model.CommunityRest;
import org.dspace.app.rest.projection.Projection;
+import org.dspace.app.rest.utils.ContextUtil;
import org.dspace.content.Community;
+import org.dspace.content.service.CommunityService;
import org.dspace.discovery.IndexableObject;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
@@ -24,9 +27,14 @@ public class CommunityConverter
extends DSpaceObjectConverter
implements IndexableObjectConverter {
+ @Autowired
+ CommunityService communityService;
+
public CommunityRest convert(Community community, Projection projection) {
CommunityRest resource = super.convert(community, projection);
- resource.setArchivedItemsCount(community.countArchivedItems());
+
+ resource.setArchivedItemsCount(
+ communityService.countArchivedItems(ContextUtil.obtainCurrentRequestContext(), community));
return resource;
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/EditItemConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/EditItemConverter.java
index 8a2135e032bb..4299f11df8d5 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/EditItemConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/EditItemConverter.java
@@ -7,7 +7,6 @@
*/
package org.dspace.app.rest.converter;
-import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import org.apache.logging.log4j.Logger;
@@ -137,11 +136,6 @@ protected void fillFromModel(EditItem obj, EditItemRest rest, Projection project
}
}
- rest.setCollection(collection != null ? converter.toRest(collection, projection) : null);
- rest.setItem(converter.toRest(item, projection));
- if (Objects.nonNull(submitter)) {
- rest.setSubmitter(converter.toRest(submitter, projection));
- }
}
private void addValidationErrorsToItem(EditItem obj, EditItemRest rest) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java
index 1c8cd6a21452..54231132d769 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ProcessConverter.java
@@ -7,7 +7,6 @@
*/
package org.dspace.app.rest.converter;
-import java.util.Objects;
import java.util.stream.Collectors;
import org.dspace.app.rest.model.ParameterValueRest;
@@ -40,7 +39,7 @@ public ProcessRest convert(Process process, Projection projection) {
processRest.setId(process.getID());
processRest.setScriptName(process.getName());
processRest.setProcessId(process.getID());
- if (Objects.nonNull(process.getEPerson())) {
+ if (process.getEPerson() != null) {
processRest.setUserId(process.getEPerson().getID());
}
processRest.setProcessStatus(process.getProcessStatus());
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java
index f2e049ed89e6..3bf7a43e5a59 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/AInprogressSubmissionRest.java
@@ -22,16 +22,11 @@
*/
public abstract class AInprogressSubmissionRest extends BaseObjectRest {
+
private Date lastModified = new Date();
private Map sections;
@JsonIgnore
- private CollectionRest collection;
- @JsonIgnore
- private ItemRest item;
- @JsonIgnore
private SubmissionDefinitionRest submissionDefinition;
- @JsonIgnore
- private EPersonRest submitter;
public Date getLastModified() {
return lastModified;
@@ -41,14 +36,6 @@ public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
- public ItemRest getItem() {
- return item;
- }
-
- public void setItem(ItemRest item) {
- this.item = item;
- }
-
public SubmissionDefinitionRest getSubmissionDefinition() {
return submissionDefinition;
}
@@ -57,14 +44,6 @@ public void setSubmissionDefinition(SubmissionDefinitionRest submissionDefinitio
this.submissionDefinition = submissionDefinition;
}
- public EPersonRest getSubmitter() {
- return submitter;
- }
-
- public void setSubmitter(EPersonRest submitter) {
- this.submitter = submitter;
- }
-
public Map getSections() {
if (sections == null) {
sections = new HashMap();
@@ -76,12 +55,6 @@ public void setSections(Map sections) {
this.sections = sections;
}
- public CollectionRest getCollection() {
- return collection;
- }
- public void setCollection(CollectionRest collection) {
- this.collection = collection;
- }
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/EditItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/EditItemRest.java
index ef5dd4525464..ee0e0ee92380 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/EditItemRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/EditItemRest.java
@@ -14,19 +14,33 @@
*
* @author Danilo Di Nuzzo (danilo.dinuzzo at 4science.it)
*/
-@LinksRest(links = {
+@LinksRest(links =
+ {
@LinkRest(
- name = EditItemRest.MODE,
- method = "getModes"
+ name = EditItemRest.MODE,
+ method = "getModes"
+ ),
+ @LinkRest(
+ name = EditItemRest.ITEM,
+ method = "getEditItemItem"
+ ),
+ @LinkRest(
+ name = EditItemRest.COLLECTION,
+ method = "getEditItemCollection"
)
-})
+ }
+)
public class EditItemRest extends AInprogressSubmissionRest {
private static final long serialVersionUID = 964876735342568998L;
public static final String NAME = "edititem";
+ public static final String NAME_PLURAL = "edititems";
public static final String MODE = "modes";
public static final String CATEGORY = RestAddressableModel.CORE;
+ public static final String ITEM = "item";
+ public static final String COLLECTION = "collection";
+
@Override
public String getCategory() {
return CATEGORY;
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java
index 8f580f441477..4a840a0bb77b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkflowItemRest.java
@@ -15,10 +15,22 @@
* @author Andrea Bollini (andrea.bollini at 4science.it)
*/
@LinksRest(links = {
- @LinkRest(
- name = WorkflowItemRest.STEP,
- method = "getStep"
- )
+ @LinkRest(
+ name = WorkflowItemRest.STEP,
+ method = "getStep"
+ ),
+ @LinkRest(
+ name = WorkflowItemRest.SUBMITTER,
+ method = "getWorkflowItemSubmitter"
+ ),
+ @LinkRest(
+ name = WorkflowItemRest.ITEM,
+ method = "getWorkflowItemItem"
+ ),
+ @LinkRest(
+ name = WorkflowItemRest.COLLECTION,
+ method = "getWorkflowItemCollection"
+ )
})
public class WorkflowItemRest extends AInprogressSubmissionRest {
public static final String NAME = "workflowitem";
@@ -26,6 +38,11 @@ public class WorkflowItemRest extends AInprogressSubmissionRest {
public static final String STEP = "step";
+ public static final String SUBMITTER = "submitter";
+ public static final String ITEM = "item";
+ public static final String COLLECTION = "collection";
+
+
@Override
public String getCategory() {
return CATEGORY;
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java
index f31dbfa9dcf8..d4702fc30356 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/WorkspaceItemRest.java
@@ -18,6 +18,18 @@
@LinkRest(
name = WorkspaceItemRest.SUPERVISION_ORDERS,
method = "getSupervisionOrders"
+ ),
+ @LinkRest(
+ name = WorkspaceItemRest.SUBMITTER,
+ method = "getWorkspaceItemSubmitter"
+ ),
+ @LinkRest(
+ name = WorkspaceItemRest.ITEM,
+ method = "getWorkspaceItemItem"
+ ),
+ @LinkRest(
+ name = WorkspaceItemRest.COLLECTION,
+ method = "getWorkspaceItemCollection"
)
})
public class WorkspaceItemRest extends AInprogressSubmissionRest {
@@ -25,6 +37,9 @@ public class WorkspaceItemRest extends AInprogressSubmissionRest {
public static final String CATEGORY = RestAddressableModel.SUBMISSION;
public static final String SUPERVISION_ORDERS = "supervisionOrders";
+ public static final String SUBMITTER = "submitter";
+ public static final String ITEM = "item";
+ public static final String COLLECTION = "collection";
@Override
public String getCategory() {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractEditItemLinkRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractEditItemLinkRestRepository.java
new file mode 100644
index 000000000000..6a8e23033bce
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AbstractEditItemLinkRestRepository.java
@@ -0,0 +1,99 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Function;
+
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.content.Item;
+import org.dspace.content.edit.EditItem;
+import org.dspace.content.edit.service.EditItemService;
+import org.dspace.content.service.ItemService;
+import org.dspace.core.Context;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.AccessDeniedException;
+
+/**
+ * Class that contains the basic implementation to retrieve linked {@link EditItem} resources.
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+public class AbstractEditItemLinkRestRepository extends AbstractDSpaceRestRepository {
+
+ private static final Logger log = LoggerFactory.getLogger(AbstractEditItemLinkRestRepository.class);
+
+ @Autowired
+ private EditItemService editItemService;
+ @Autowired
+ private ItemService itemService;
+
+ protected static Optional getEditItemRestRequest(String data) {
+ if (data == null || data.isEmpty()) {
+ return Optional.empty();
+ }
+
+ String[] split = data.split(":");
+
+ UUID uuid;
+ try {
+ uuid = UUID.fromString(split[0]);
+ } catch (Exception e) {
+ log.error("Cannot convert the following uuid: {}", split[0], e);
+ return Optional.empty();
+ }
+ String mode = split[1];
+ return Optional.of(new EditItemRestRequest(uuid, mode));
+ }
+
+ protected EditItem findEditItem(EditItemRestRequest requestDetails) {
+ try {
+ Context context = obtainContext();
+ Item item = itemService.find(context, requestDetails.uuid);
+ EditItem editItem = editItemService.find(context, item, requestDetails.mode);
+
+ if (editItem == null) {
+ throw new ResourceNotFoundException("No such edit item found: " + requestDetails.uuid);
+ }
+ return editItem;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ } catch (AuthorizeException e) {
+ throw new AccessDeniedException(
+ "The current user does not have rights to edit mode <" + requestDetails.mode + ">"
+ );
+ }
+ }
+
+ protected R getMappedResource(
+ Optional request,
+ Function mapper,
+ Projection projection
+ ) {
+ return request.map(this::findEditItem)
+ .map(mapper)
+ .map(obj -> converter.toRest(obj, projection))
+ .orElse(null);
+ }
+
+ protected static class EditItemRestRequest {
+ public final UUID uuid;
+ public final String mode;
+
+ public EditItemRestRequest(UUID uuid, String mode) {
+ this.uuid = uuid;
+ this.mode = mode;
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemCollectionLinkRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemCollectionLinkRestRepository.java
new file mode 100644
index 000000000000..05f8aab0bf01
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemCollectionLinkRestRepository.java
@@ -0,0 +1,50 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.CollectionRest;
+import org.dspace.app.rest.model.EditItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.content.edit.EditItem;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link resource for {@link EditItemRest#COLLECTION}
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+@Component(EditItemRest.CATEGORY + "." + EditItemRest.NAME + "." + EditItemRest.COLLECTION)
+public class EditItemCollectionLinkRestRepository extends AbstractEditItemLinkRestRepository
+ implements LinkRestRepository {
+
+ /**
+ * Retrieve the collection for an edit item.
+ *
+ * @param request - The current request
+ * @param data - The data template that contains both item uuid and mode {uuid:mode}, joined by a column
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the item for the edit item
+ */
+ public CollectionRest getEditItemCollection(
+ @Nullable HttpServletRequest request, String data,
+ @Nullable Pageable optionalPageable, Projection projection
+ ) {
+ return getMappedResource(
+ getEditItemRestRequest(data),
+ EditItem::getCollection,
+ projection
+ );
+
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemItemLinkRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemItemLinkRestRepository.java
new file mode 100644
index 000000000000..bb83fffd3673
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/EditItemItemLinkRestRepository.java
@@ -0,0 +1,49 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.EditItemRest;
+import org.dspace.app.rest.model.ItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.content.edit.EditItem;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link resource for {@link EditItemRest#ITEM}
+ *
+ * @author Vincenzo Mecca (vins01-4science - vincenzo.mecca at 4science.com)
+ **/
+@Component(EditItemRest.CATEGORY + "." + EditItemRest.NAME + "." + EditItemRest.ITEM)
+public class EditItemItemLinkRestRepository extends AbstractEditItemLinkRestRepository implements LinkRestRepository {
+
+ /**
+ * Retrieve the item for an edit item.
+ *
+ * @param request - The current request
+ * @param data - The data template that contains both item uuid and mode {uuid:mode}, joined by a column
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the item for the edit item
+ */
+ public ItemRest getEditItemItem(
+ @Nullable HttpServletRequest request, String data,
+ @Nullable Pageable optionalPageable, Projection projection
+ ) {
+ return getMappedResource(
+ getEditItemRestRequest(data),
+ EditItem::getItem,
+ projection
+ );
+ }
+
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java
index 8fd28bbe94b8..42672062175a 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/FeedbackRestRepository.java
@@ -79,8 +79,14 @@ protected FeedbackRest createAndReturn(Context context) throws AuthorizeExceptio
throw new DSpaceBadRequestException("e-mail and message fields are mandatory!");
}
+ String pageUrl = feedbackRest.getPage();
+ String urlPrefix = configurationService.getProperty("dspace.ui.url");
+ if (StringUtils.isNotBlank(pageUrl) && ! StringUtils.startsWith(pageUrl, urlPrefix)) {
+ throw new DSpaceBadRequestException("unexpected page url was submitted");
+ }
+
try {
- feedbackService.sendEmail(context, req, recipientEmail, senderEmail, message, feedbackRest.getPage());
+ feedbackService.sendEmail(context, req, recipientEmail, senderEmail, message, pageUrl);
} catch (IOException | MessagingException e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -100,4 +106,4 @@ public void setFeedbackService(FeedbackService feedbackService) {
this.feedbackService = feedbackService;
}
-}
\ No newline at end of file
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java
index 9be8a117c992..2a9dbad77070 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RelationshipRestRepository.java
@@ -29,9 +29,11 @@
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.DSpaceObject;
+import org.dspace.content.EntityType;
import org.dspace.content.Item;
import org.dspace.content.Relationship;
import org.dspace.content.RelationshipType;
+import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
@@ -59,6 +61,9 @@ public class RelationshipRestRepository extends DSpaceRestRepository findByLabel(@Parameter(value = "label", required = true) String label,
@Parameter(value = "dso", required = false) UUID dsoId,
+ @Parameter(value = "relatedEntityType") String relatedEntityType,
Pageable pageable) throws SQLException {
Context context = obtainContext();
@@ -377,14 +384,28 @@ public Page findByLabel(@Parameter(value = "label", required =
if (item == null) {
throw new ResourceNotFoundException("The request DSO with id: " + dsoId + " was not found");
}
+
+ EntityType dsoEntityType = itemService.getEntityType(context, item);
+
+ if (dsoEntityType == null) {
+ throw new UnprocessableEntityException(String.format(
+ "The request DSO with id: %s doesn't have an entity type", dsoId));
+ }
+
for (RelationshipType relationshipType : relationshipTypeList) {
- boolean isLeft = false;
- if (relationshipType.getLeftwardType().equalsIgnoreCase(label)) {
- isLeft = true;
+ if (relatedEntityType == null ||
+ relationshipType.getRightType().getLabel().equals(dsoEntityType.getLabel()) &&
+ relationshipType.getLeftType().getLabel().equals(relatedEntityType) ||
+ relationshipType.getRightType().getLabel().equals(relatedEntityType) &&
+ relationshipType.getLeftType().getLabel().equals(dsoEntityType.getLabel())) {
+ boolean isLeft = relationshipType.getLeftwardType().equalsIgnoreCase(label);
+ total +=
+ relationshipService.countByItemAndRelationshipType(context, item, relationshipType, isLeft);
+ relationships.addAll(
+ relationshipService.findByItemAndRelationshipType(context, item, relationshipType,
+ isLeft, pageable.getPageSize(),
+ Math.toIntExact(pageable.getOffset())));
}
- total += relationshipService.countByItemAndRelationshipType(context, item, relationshipType, isLeft);
- relationships.addAll(relationshipService.findByItemAndRelationshipType(context, item, relationshipType,
- isLeft, pageable.getPageSize(), Math.toIntExact(pageable.getOffset())));
}
} else {
for (RelationshipType relationshipType : relationshipTypeList) {
@@ -402,7 +423,7 @@ public Page findByLabel(@Parameter(value = "label", required =
* of potentially related items we need to know which of these other items
* are already in a specific relationship with the focus item and,
* by exclusion which ones are not yet related.
- *
+ *
* @param typeId The relationship type id to apply as a filter to the returned relationships
* @param label The name of the relation as defined from the side of the 'focusItem'
* @param focusUUID The uuid of the item to be checked on the side defined by 'relationshipLabel'
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
index 6eb631cfa56e..5945d516600a 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/RequestItemRepository.java
@@ -247,11 +247,15 @@ public RequestItemRest put(Context context, HttpServletRequest request,
message = responseMessageNode.asText();
}
+ JsonNode responseSubjectNode = requestBody.findValue("subject");
+ String subject = null;
+ if (responseSubjectNode != null && !responseSubjectNode.isNull()) {
+ subject = responseSubjectNode.asText();
+ }
ri.setDecision_date(new Date());
requestItemService.update(context, ri);
// Send the response email
- String subject = requestBody.findValue("subject").asText();
try {
requestItemEmailNotifier.sendResponse(context, ri, subject, message);
} catch (IOException ex) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java
index 72ca3f254256..e2c258d615df 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ResourcePolicyRestRepository.java
@@ -259,14 +259,6 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx
if (dspaceObject == null) {
throw new UnprocessableEntityException("DSpaceObject with this uuid: " + resourceUuid + " not found");
}
- resourcePolicy = resourcePolicyService.create(context);
- resourcePolicy.setRpType(resourcePolicyRest.getPolicyType());
- resourcePolicy.setdSpaceObject(dspaceObject);
- resourcePolicy.setRpName(resourcePolicyRest.getName());
- resourcePolicy.setRpDescription(resourcePolicyRest.getDescription());
- resourcePolicy.setAction(Constants.getActionID(resourcePolicyRest.getAction()));
- resourcePolicy.setStartDate(resourcePolicyRest.getStartDate());
- resourcePolicy.setEndDate(resourcePolicyRest.getEndDate());
if (epersonUuidStr != null) {
try {
@@ -275,12 +267,11 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx
if (ePerson == null) {
throw new UnprocessableEntityException("EPerson with uuid: " + epersonUuid + " not found");
}
- resourcePolicy.setEPerson(ePerson);
- resourcePolicyService.update(context, resourcePolicy);
+ resourcePolicy = resourcePolicyService.create(context, ePerson, null);
+
} catch (SQLException excSQL) {
throw new RuntimeException(excSQL.getMessage(), excSQL);
}
- return converter.toRest(resourcePolicy, utils.obtainProjection());
} else {
try {
UUID groupUuid = UUID.fromString(groupUuidStr);
@@ -288,13 +279,27 @@ protected ResourcePolicyRest createAndReturn(Context context) throws AuthorizeEx
if (group == null) {
throw new UnprocessableEntityException("Group with uuid: " + groupUuid + " not found");
}
- resourcePolicy.setGroup(group);
- resourcePolicyService.update(context, resourcePolicy);
+ resourcePolicy = resourcePolicyService.create(context, null, group);
} catch (SQLException excSQL) {
throw new RuntimeException(excSQL.getMessage(), excSQL);
}
+ }
+
+ if (resourcePolicy != null) {
+
+ resourcePolicy.setRpType(resourcePolicyRest.getPolicyType());
+ resourcePolicy.setdSpaceObject(dspaceObject);
+ resourcePolicy.setRpName(resourcePolicyRest.getName());
+ resourcePolicy.setRpDescription(resourcePolicyRest.getDescription());
+ resourcePolicy.setAction(Constants.getActionID(resourcePolicyRest.getAction()));
+ resourcePolicy.setStartDate(resourcePolicyRest.getStartDate());
+ resourcePolicy.setEndDate(resourcePolicyRest.getEndDate());
+ resourcePolicyService.update(context, resourcePolicy);
return converter.toRest(resourcePolicy, utils.obtainProjection());
+ } else {
+ throw new UnprocessableEntityException("A resource policy must contain a valid eperson or group");
}
+
}
@Override
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java
index e95cefb9f04d..92d5c9daf47d 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/VocabularyRestRepository.java
@@ -101,6 +101,9 @@ public VocabularyRest findByMetadataAndCollection(
}
String authorityName = cas.getChoiceAuthorityName(tokens[0], tokens[1], tokens[2], Constants.ITEM, collection);
+ if (authorityName == null) {
+ return null;
+ }
ChoiceAuthority source = cas.getChoiceAuthorityByAuthorityName(authorityName);
return authorityUtils.convertAuthority(source, authorityName, utils.obtainProjection());
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java
new file mode 100644
index 000000000000..fa92a69e77d6
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemCollectionLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.CollectionRest;
+import org.dspace.app.rest.model.WorkflowItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.core.Context;
+import org.dspace.workflow.WorkflowItem;
+import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "collection" subresource of a workflow item.
+ */
+@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.COLLECTION)
+public class WorkflowItemCollectionLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ XmlWorkflowItemService wis;
+
+ /**
+ * Retrieve the item for a workflow collection.
+ *
+ * @param request - The current request
+ * @param id - The workflow item ID for which to retrieve the collection
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the item for the workflow collection
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')")
+ public CollectionRest getWorkflowItemCollection(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkflowItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workflow item: " + id);
+ }
+
+ return converter.toRest(witem.getCollection(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java
new file mode 100644
index 000000000000..40624799bff4
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemItemLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.ItemRest;
+import org.dspace.app.rest.model.WorkflowItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.core.Context;
+import org.dspace.workflow.WorkflowItem;
+import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "item" subresource of a workflow item.
+ */
+@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.ITEM)
+public class WorkflowItemItemLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ XmlWorkflowItemService wis;
+
+ /**
+ * Retrieve the item for a workflow item.
+ *
+ * @param request - The current request
+ * @param id - The workflow item ID for which to retrieve the item
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the item for the workflow item
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')")
+ public ItemRest getWorkflowItemItem(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkflowItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workflow item: " + id);
+ }
+
+ return converter.toRest(witem.getItem(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java
new file mode 100644
index 000000000000..b4b0ec0adfff
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkflowItemSubmitterLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.EPersonRest;
+import org.dspace.app.rest.model.WorkflowItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.core.Context;
+import org.dspace.workflow.WorkflowItem;
+import org.dspace.xmlworkflow.storedcomponents.service.XmlWorkflowItemService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "submitter" subresource of a workflow item.
+ */
+@Component(WorkflowItemRest.CATEGORY + "." + WorkflowItemRest.NAME + "." + WorkflowItemRest.SUBMITTER)
+public class WorkflowItemSubmitterLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ XmlWorkflowItemService wis;
+
+ /**
+ * Retrieve the submitter for a workflow item.
+ *
+ * @param request - The current request
+ * @param id - The workflow item ID for which to retrieve the submitter
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the submitter for the workflow item
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKFLOWITEM', 'READ')")
+ public EPersonRest getWorkflowItemSubmitter(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkflowItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workflow item: " + id);
+ }
+
+ return converter.toRest(witem.getSubmitter(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java
new file mode 100644
index 000000000000..c8f9373b07c7
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemCollectionLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.CollectionRest;
+import org.dspace.app.rest.model.WorkspaceItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.content.WorkspaceItem;
+import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.core.Context;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "collection" subresource of a workspace item.
+ */
+@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.COLLECTION)
+public class WorkspaceItemCollectionLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ WorkspaceItemService wis;
+
+ /**
+ * Retrieve the collection for a workspace item.
+ *
+ * @param request - The current request
+ * @param id - The workspace item ID for which to retrieve the collection
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the collection for the workspace item
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')")
+ public CollectionRest getWorkspaceItemCollection(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkspaceItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workspace item: " + id);
+ }
+
+ return converter.toRest(witem.getCollection(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java
new file mode 100644
index 000000000000..48052fe5371f
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemItemLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.ItemRest;
+import org.dspace.app.rest.model.WorkspaceItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.content.WorkspaceItem;
+import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.core.Context;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "item" subresource of a workspace item.
+ */
+@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.ITEM)
+public class WorkspaceItemItemLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ WorkspaceItemService wis;
+
+ /**
+ * Retrieve the item for a workspace item.
+ *
+ * @param request - The current request
+ * @param id - The workspace item ID for which to retrieve the item
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the item for the workspace item
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')")
+ public ItemRest getWorkspaceItemItem(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkspaceItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workspace item: " + id);
+ }
+
+ return converter.toRest(witem.getItem(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java
new file mode 100644
index 000000000000..a98de6a0b3ac
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/WorkspaceItemSubmitterLinkRepository.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.sql.SQLException;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+
+import org.dspace.app.rest.model.EPersonRest;
+import org.dspace.app.rest.model.WorkspaceItemRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.content.WorkspaceItem;
+import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.core.Context;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * Link repository for "submitter" subresource of a workspace item.
+ */
+@Component(WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME + "." + WorkspaceItemRest.SUBMITTER)
+public class WorkspaceItemSubmitterLinkRepository extends AbstractDSpaceRestRepository
+ implements LinkRestRepository {
+
+ @Autowired
+ WorkspaceItemService wis;
+
+ /**
+ * Retrieve the submitter for a workspace item.
+ *
+ * @param request - The current request
+ * @param id - The workspace item ID for which to retrieve the submitter
+ * @param optionalPageable - optional pageable object
+ * @param projection - the current projection
+ * @return the submitter for the workspace item
+ */
+ @PreAuthorize("hasPermission(#id, 'WORKSPACEITEM', 'READ')")
+ public EPersonRest getWorkspaceItemSubmitter(@Nullable HttpServletRequest request, Integer id,
+ @Nullable Pageable optionalPageable, Projection projection) {
+ try {
+ Context context = obtainContext();
+ WorkspaceItem witem = wis.find(context, id);
+ if (witem == null) {
+ throw new ResourceNotFoundException("No such workspace item: " + id);
+ }
+
+ return converter.toRest(witem.getSubmitter(), projection);
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/DSpaceCsrfTokenRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/DSpaceCsrfTokenRepository.java
index 2079727ac889..7cadcce077e8 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/DSpaceCsrfTokenRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/security/DSpaceCsrfTokenRepository.java
@@ -53,11 +53,16 @@
public class DSpaceCsrfTokenRepository implements CsrfTokenRepository {
// This cookie name is changed from the default "XSRF-TOKEN" to ensure it is uniquely named and doesn't conflict
// with any other XSRF-TOKEN cookies (e.g. in Angular UI, the XSRF-TOKEN cookie is a *client-side* only cookie)
- static final String DEFAULT_CSRF_COOKIE_NAME = "DSPACE-XSRF-COOKIE";
+ public static final String DEFAULT_CSRF_COOKIE_NAME = "DSPACE-XSRF-COOKIE";
- static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";
+ // The HTTP header that is sent back to the client whenever a new CSRF token is created
+ // (NOTE: This is purposefully different from DEFAULT_CSRF_HEADER_NAME below!)
+ public static final String DSPACE_CSRF_HEADER_NAME = "DSPACE-XSRF-TOKEN";
- static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
+ public static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";
+
+ // The HTTP header that Spring Security expects to receive from the client in order to validate a CSRF token
+ public static final String DEFAULT_CSRF_HEADER_NAME = "X-XSRF-TOKEN";
private String parameterName = DEFAULT_CSRF_PARAMETER_NAME;
@@ -132,7 +137,7 @@ public void saveToken(CsrfToken token, HttpServletRequest request,
// We send our token via a custom header because client can be on a different domain.
// Cookies cannot be reliably sent cross-domain.
if (StringUtils.hasLength(tokenValue)) {
- response.setHeader("DSPACE-XSRF-TOKEN", tokenValue);
+ response.setHeader(DSPACE_CSRF_HEADER_NAME, tokenValue);
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java
index ec4dff9f6c51..602ae5e9690b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/CCLicenseAddPatchOperation.java
@@ -26,7 +26,7 @@
* Example:
* curl -X PATCH http://${dspace.server.url}/api/submission/workspaceitems/31599 -H "Content-Type:
* application/json" -d '[{ "op": "add", "path": "/sections/cclicense/uri",
- * "value":"http://creativecommons.org/licenses/by-nc-sa/3.0/us/"}]'
+ * "value":"https://creativecommons.org/licenses/by-nc-sa/3.0/us/"}]'
*
*/
public class CCLicenseAddPatchOperation extends AddPatchOperation {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/ItemMetadataValueAddPatchOperation.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/ItemMetadataValueAddPatchOperation.java
index 8c819dddfd3d..55a088f59399 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/ItemMetadataValueAddPatchOperation.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/submit/factory/impl/ItemMetadataValueAddPatchOperation.java
@@ -221,7 +221,7 @@ private Integer getRelId(String authority) {
private void updateRelationshipPlace(Context context, Item dso, int place, Relationship rs) {
try {
- if (rs.getLeftItem() == dso) {
+ if (rs.getLeftItem().getID().equals(dso.getID())) {
rs.setLeftPlace(place);
} else {
rs.setRightPlace(place);
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java
index 56b8ae32dce1..9291a436c787 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/DSpaceConfigurationInitializer.java
@@ -8,7 +8,7 @@
package org.dspace.app.rest.utils;
import org.apache.commons.configuration2.Configuration;
-import org.apache.commons.configuration2.spring.ConfigurationPropertySource;
+import org.dspace.servicemanager.config.DSpaceConfigurationPropertySource;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.slf4j.Logger;
@@ -38,8 +38,8 @@ public void initialize(final ConfigurableApplicationContext applicationContext)
Configuration configuration = configurationService.getConfiguration();
// Create an Apache Commons Configuration Property Source from our configuration
- ConfigurationPropertySource apacheCommonsConfigPropertySource =
- new ConfigurationPropertySource(configuration.getClass().getName(), configuration);
+ DSpaceConfigurationPropertySource apacheCommonsConfigPropertySource =
+ new DSpaceConfigurationPropertySource(configuration.getClass().getName(), configuration);
// Prepend it to the Environment's list of PropertySources
// NOTE: This is added *first* in the list so that settings in DSpace's ConfigurationService *override*
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java
index a69da4c5e86b..d68c710a3c7a 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/HttpHeadersInitializer.java
@@ -14,6 +14,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -33,7 +34,6 @@ public class HttpHeadersInitializer {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
- private static final String METHOD_HEAD = "HEAD";
private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES";
private static final String CONTENT_TYPE_MULTITYPE_WITH_BOUNDARY = "multipart/byteranges; boundary=" +
MULTIPART_BOUNDARY;
@@ -144,6 +144,9 @@ public HttpHeaders initialiseHeaders() throws IOException {
if (checksum != null) {
httpHeaders.put(ETAG, Collections.singletonList(checksum));
}
+ if (Objects.nonNull((Long.valueOf(this.length)))) {
+ httpHeaders.put(HttpHeaders.CONTENT_LENGTH, Collections.singletonList(String.valueOf(this.length)));
+ }
httpHeaders.put(LAST_MODIFIED, Collections.singletonList(FastHttpDateFormat.formatDate(lastModified)));
httpHeaders.put(EXPIRES, Collections.singletonList(FastHttpDateFormat.formatDate(
System.currentTimeMillis() + DEFAULT_EXPIRE_TIME)));
@@ -165,16 +168,14 @@ public HttpHeaders initialiseHeaders() throws IOException {
httpHeaders.put(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,
Collections.singletonList(HttpHeaders.ACCEPT_RANGES));
- httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT,
- disposition,
- encodeText(fileName))));
- log.debug("Content-Disposition : {}", disposition);
- // Content phase
- if (METHOD_HEAD.equals(request.getMethod())) {
- log.debug("HEAD request - skipping content");
- return null;
+ // distposition may be null here if contentType is null
+ if (!isNullOrEmpty(disposition)) {
+ httpHeaders.put(CONTENT_DISPOSITION, Collections.singletonList(String.format(CONTENT_DISPOSITION_FORMAT,
+ disposition,
+ encodeText(fileName))));
}
+ log.debug("Content-Disposition : {}", disposition);
return httpHeaders;
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java
index d604ff2066c2..b83c6f638c46 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/utils/ScopeResolver.java
@@ -8,12 +8,18 @@
package org.dspace.app.rest.utils;
import java.sql.SQLException;
+import java.util.Optional;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.DSpaceObject;
+import org.dspace.content.Item;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
+import org.dspace.content.service.DSpaceObjectService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.discovery.IndexableObject;
@@ -40,28 +46,80 @@ public class ScopeResolver {
@Autowired
ItemService itemService;
+ /**
+ * Returns an IndexableObject corresponding to the community or collection
+ * of the given scope, or null if the scope is not a valid UUID, or is a
+ * valid UUID that does not correspond to a community of collection.
+ *
+ * @param context the DSpace context
+ * @param scope a String containing the UUID of the community or collection
+ * to return.
+ * @return an IndexableObject corresponding to the community or collection
+ * of the given scope, or null if the scope is not a valid UUID, or is a
+ * valid UUID that does not correspond to a community of collection.
+ */
public IndexableObject resolveScope(Context context, String scope) {
IndexableObject scopeObj = null;
- if (StringUtils.isNotBlank(scope)) {
- try {
- UUID uuid = UUID.fromString(scope);
- scopeObj = new IndexableCommunity(communityService.find(context, uuid));
- if (scopeObj.getIndexedObject() == null) {
- scopeObj = new IndexableCollection(collectionService.find(context, uuid));
- }
- if (scopeObj.getIndexedObject() == null) {
- scopeObj = new IndexableItem(itemService.find(context, uuid));
- }
- } catch (IllegalArgumentException ex) {
- log.warn("The given scope string " + StringUtils.trimToEmpty(scope) + " is not a UUID", ex);
- } catch (SQLException ex) {
+ Optional uuidOptional =
+ Optional.ofNullable(scope)
+ .filter(StringUtils::isNotBlank)
+ .map(this::asUUID);
+ return uuidOptional
+ .flatMap(uuid -> resolveWithIndexedObject(context, Optional.of(uuid), communityService))
+ .or(() -> resolveWithIndexedObject(context, uuidOptional, collectionService))
+ .orElseGet(() -> {
log.warn(
- "Unable to retrieve DSpace Object with ID " + StringUtils.trimToEmpty(scope) + " from the database",
- ex);
- }
+ "The given scope string " +
+ StringUtils.trimToEmpty(scope) +
+ " is not a collection or community UUID."
+ );
+ return uuidOptional.map(uuid -> resolve(context, uuid, itemService)).orElse(null);
+ });
+ }
+
+ private UUID asUUID(String scope) {
+ try {
+ return UUID.fromString(scope);
+ } catch (IllegalArgumentException ex) {
+ log.warn("The given scope string " + StringUtils.trimToEmpty(scope) + " is not a UUID", ex);
}
+ return null;
+ }
+
+ private Optional resolveWithIndexedObject(
+ Context context, Optional uuidOptional, DSpaceObjectService service
+ ) {
+ return uuidOptional.map(uuid -> resolve(context, uuid, service))
+ .filter(obj -> obj.getIndexedObject() != null);
+ }
- return scopeObj;
+ public IndexableObject resolve(
+ Context context, UUID uuid, DSpaceObjectService service
+ ) {
+ if (uuid == null) {
+ return null;
+ }
+ T dspaceObject = null;
+ try {
+ dspaceObject = service.find(context, uuid);
+ } catch (IllegalArgumentException ex) {
+ log.warn("The given scope string " + StringUtils.trimToEmpty(uuid.toString()) + " is not a UUID", ex);
+ } catch (SQLException ex) {
+ log.warn(
+ "Unable to retrieve DSpace Object with ID " + StringUtils.trimToEmpty(uuid.toString()) +
+ " from the database",
+ ex);
+ }
+ if (dspaceObject == null) {
+ return null;
+ }
+ if (dspaceObject instanceof Community) {
+ return new IndexableCommunity((Community) dspaceObject);
+ }
+ if (dspaceObject instanceof Collection) {
+ return new IndexableCollection((Collection) dspaceObject);
+ }
+ return new IndexableItem((Item) dspaceObject);
}
}
diff --git a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml
index 49a1fc6e0605..b6c6cc364dc5 100644
--- a/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml
+++ b/dspace-server-webapp/src/test/data/dspaceFolder/config/spring/api/test-discovery.xml
@@ -4554,6 +4554,24 @@
+
+
+
+
+ crispj.coordinator
+ crispj.partnerou
+ crispj.organization
+
+
+
+
+
+
+
+
+
+
@@ -4694,16 +4712,16 @@
-
+
-
+
-
+
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java
index 1ddea619d2fc..645d52df59f1 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/opensearch/OpenSearchControllerIT.java
@@ -96,7 +96,12 @@ public void findResultSimpleTest() throws Exception {
Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
- Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build();
+ // Add a fake logo to the Collection
+ Collection col1 = CollectionBuilder.createCollection(context, child1)
+ .withName("Collection 1")
+ .withLogo("logo_collection")
+ .build();
+ String colLogoUuid = col1.getLogo().getID().toString();
Item publicItem1 = ItemBuilder.createItem(context, col1)
.withTitle("Boars at Yellowstone")
@@ -118,10 +123,24 @@ public void findResultSimpleTest() throws Exception {
.andExpect(xpath("feed/Query/@searchTerms").string("Yellowstone"))
.andExpect(xpath("feed/totalResults").string("2"))
;
+
+ // When we search at the Collection level (scope = Collection UUID)
+ getClient().perform(get("/opensearch/search")
+ .param("scope", col1.getID().toString())
+ .param("query", "Yellowstone"))
+ //The status has to be 200 OK
+ .andExpect(status().isOk())
+ // We expect the content type to be "application/atom+xml;charset=UTF-8"
+ .andExpect(content().contentType("application/atom+xml;charset=UTF-8"))
+ .andExpect(xpath("feed/Query/@searchTerms").string("Yellowstone"))
+ .andExpect(xpath("feed/totalResults").string("2"))
+ // We expect feed will have the Collection logo
+ .andExpect(xpath("feed/logo")
+ .string("http://localhost:4000/bitstreams/" + colLogoUuid + "/download"))
+ ;
}
// This test does not find the record, so there are obviously issues with special chars
- @Ignore
@Test
public void findResultWithSpecialCharsTest() throws Exception {
//Turn off the authorization system, otherwise we can't make the objects
@@ -144,12 +163,12 @@ public void findResultWithSpecialCharsTest() throws Exception {
.build();
//When we call the root endpoint
getClient().perform(get("/opensearch/search")
- .param("query", "Bär"))
+ .param("query", "Bären"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/atom+xml;charset=UTF-8"
.andExpect(content().contentType("application/atom+xml;charset=UTF-8"))
- .andExpect(xpath("feed/Query/@searchTerms").string("B%C3%A4r"))
+ .andExpect(xpath("feed/Query/@searchTerms").string("B%C3%A4ren"))
.andExpect(xpath("feed/totalResults").string("1"))
;
}
@@ -269,4 +288,32 @@ public void emptyDescriptionTest() throws Exception {
.andExpect(status().isOk())
.andExpect(xpath("rss/channel/description").string("No Description"));
}
+
+ @Test
+ public void scopeNotCommunityOrCollectionUUIDTest() throws Exception {
+ // Tests that a OpenSearch response with 1 result (equivalent to an
+ // unscoped request) is returned if the "scope" UUID is a
+ // validly-formatted UUID, but not a community or collection UUID.
+ context.turnOffAuthorisationSystem();
+ parentCommunity = CommunityBuilder.createCommunity(context)
+ .withName("Parent Community")
+ .build();
+ Collection collection1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1")
+ .build();
+
+ Item publicItem1 = ItemBuilder.createItem(context, collection1)
+ .withTitle("Boars at Yellowstone")
+ .withIssueDate("2017-10-17")
+ .withAuthor("Ballini, Andreas").withAuthor("Moriarti, Susan")
+ .build();
+
+ // UUID is valid, but not a community or collection UUID
+ String testUUID = "b68f0d1c-7316-41dc-835d-46b79b35642e";
+
+ getClient().perform(get("/opensearch/search")
+ .param("scope", testUUID)
+ .param("query", "*"))
+ .andExpect(status().isOk())
+ .andExpect(xpath("feed/totalResults").string("1"));
+ }
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java
index a326d195c2a0..c31bb61f060e 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamControllerIT.java
@@ -302,25 +302,25 @@ public void putOnBitstreamInOneBundle() throws Exception {
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -471,31 +471,31 @@ public void putOnBitstreamInMultipleBundles() throws Exception {
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle2).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle2).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -592,25 +592,25 @@ public void putOnBitstreamInNoBundle() throws Exception {
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -708,22 +708,22 @@ public void putOnBitstreamInOneBundleWithNoRemoveRights() throws Exception {
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -810,22 +810,22 @@ public void putOnBitstreamInOneBundleWithNoWriteOnCurrentBundleRights() throws E
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -913,22 +913,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnTargetBundle() throws Ex
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -1015,22 +1015,22 @@ public void putOnBitstreamInOneBundleWithNoAddRightsOnTargetBundle() throws Exce
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -1117,22 +1117,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnBitstream() throws Excep
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -1220,22 +1220,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnCurrentItem() throws Exc
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetItem).build();
@@ -1322,22 +1322,22 @@ public void putOnBitstreamInOneBundleWithNoWriteRightsOnTargetItem() throws Exce
.withPassword("test")
.withNameInMetadata("Bundle", "Put").build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.REMOVE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bundle1).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.ADD)
.withDspaceObject(targetBundle).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(bitstream).build();
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(putBundlePerson)
+ ResourcePolicyBuilder.createResourcePolicy(context, putBundlePerson, null)
.withAction(Constants.WRITE)
.withDspaceObject(publicItem1).build();
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java
index fd128269308d..d28202af659b 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java
@@ -56,7 +56,7 @@ public class BitstreamFormatRestRepositoryIT extends AbstractControllerIntegrati
@Autowired
private BitstreamFormatConverter bitstreamFormatConverter;
- private final int DEFAULT_AMOUNT_FORMATS = 85;
+ private final int DEFAULT_AMOUNT_FORMATS = 86;
@Test
public void findAllPaginationTest() throws Exception {
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java
index 92cff6db2192..b3964d3e8153 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestControllerIT.java
@@ -208,6 +208,18 @@ public void retrieveFullBitstream() throws Exception {
}
context.restoreAuthSystemState();
+ //** WHEN **
+ // we want to know what we are downloading before we download it
+ getClient().perform(head("/api/core/bitstreams/" + bitstream.getID() + "/content"))
+ //** THEN **
+ .andExpect(status().isOk())
+
+ //The Content Length must match the full length
+ .andExpect(header().longValue("Content-Length", bitstreamContent.getBytes().length))
+ .andExpect(header().string("Content-Type", "text/plain;charset=UTF-8"))
+ .andExpect(header().string("ETag", "\"" + bitstream.getChecksum() + "\""))
+ .andExpect(content().bytes(new byte[] {}));
+
//** WHEN **
//We download the bitstream
getClient().perform(get("/api/core/bitstreams/" + bitstream.getID() + "/content"))
@@ -234,7 +246,7 @@ public void retrieveFullBitstream() throws Exception {
.andExpect(status().isNotModified());
//The download and head request should also be logged as a statistics record
- checkNumberOfStatsRecords(bitstream, 2);
+ checkNumberOfStatsRecords(bitstream, 3);
}
@Test
@@ -1105,8 +1117,7 @@ public void updateBitstreamFormatEPerson() throws Exception {
context.turnOffAuthorisationSystem();
- createResourcePolicy(context)
- .withUser(eperson)
+ createResourcePolicy(context, eperson, null)
.withAction(WRITE)
.withDspaceObject(bitstream)
.build();
@@ -1359,7 +1370,7 @@ public void checkContentDispositionOfFormats() throws Exception {
Bitstream rtf;
Bitstream xml;
Bitstream txt;
- Bitstream html;
+ Bitstream csv;
try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) {
rtf = BitstreamBuilder.createBitstream(context, item, is)
.withMimeType("text/richtext").build();
@@ -1367,8 +1378,8 @@ public void checkContentDispositionOfFormats() throws Exception {
.withMimeType("text/xml").build();
txt = BitstreamBuilder.createBitstream(context, item, is)
.withMimeType("text/plain").build();
- html = BitstreamBuilder.createBitstream(context, item, is)
- .withMimeType("text/html").build();
+ csv = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("text/csv").build();
}
context.restoreAuthSystemState();
@@ -1377,9 +1388,89 @@ public void checkContentDispositionOfFormats() throws Exception {
verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true);
verifyBitstreamDownload(txt, "text/plain;charset=UTF-8", true);
// this format is not configured and should open inline
- verifyBitstreamDownload(html, "text/html;charset=UTF-8", false);
+ verifyBitstreamDownload(csv, "text/csv;charset=UTF-8", false);
+ }
+
+ @Test
+ public void checkHardcodedContentDispositionFormats() throws Exception {
+ // This test is similar to the above test, but it verifies that our *hardcoded settings* for
+ // webui.content_disposition_format are protecting us from loading specific formats *inline*.
+ context.turnOffAuthorisationSystem();
+ Community community = CommunityBuilder.createCommunity(context).build();
+ Collection collection = CollectionBuilder.createCollection(context, community).build();
+ Item item = ItemBuilder.createItem(context, collection).build();
+ String content = "Test Content";
+ Bitstream html;
+ Bitstream js;
+ Bitstream rdf;
+ Bitstream xml;
+ Bitstream unknown;
+ Bitstream svg;
+ try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) {
+ html = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("text/html").build();
+ js = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("text/javascript").build();
+ // NOTE: RDF has a MIME Type with a "charset" in our bitstream-formats.xml
+ rdf = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("application/rdf+xml; charset=utf-8").build();
+ xml = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("text/xml").build();
+ unknown = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("application/octet-stream").build();
+ svg = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("image/svg+xml").build();
+
+ }
+ context.restoreAuthSystemState();
+
+ // By default, HTML, JS & XML should all download. This protects us from possible XSS attacks, as
+ // each of these formats can embed JavaScript which may execute when the file is loaded *inline*.
+ verifyBitstreamDownload(html, "text/html;charset=UTF-8", true);
+ verifyBitstreamDownload(js, "text/javascript;charset=UTF-8", true);
+ verifyBitstreamDownload(rdf, "application/rdf+xml;charset=UTF-8", true);
+ verifyBitstreamDownload(xml, "text/xml;charset=UTF-8", true);
+ // Unknown file formats should also always download
+ verifyBitstreamDownload(unknown, "application/octet-stream;charset=UTF-8", true);
+ // SVG does NOT currently exist as a recognized format in DSpace's bitstream-formats.xml, but it's another
+ // format that allows embedded JavaScript. This test is a reminder that SVGs should NOT be opened inline.
+ verifyBitstreamDownload(svg, "application/octet-stream;charset=UTF-8", true);
}
+ @Test
+ public void checkWildcardContentDispositionFormats() throws Exception {
+ // Setting "*" should result in all formats being downloaded (nothing will be opened inline)
+ configurationService.setProperty("webui.content_disposition_format", "*");
+
+ context.turnOffAuthorisationSystem();
+ Community community = CommunityBuilder.createCommunity(context).build();
+ Collection collection = CollectionBuilder.createCollection(context, community).build();
+ Item item = ItemBuilder.createItem(context, collection).build();
+ String content = "Test Content";
+ Bitstream csv;
+ Bitstream jpg;
+ Bitstream mpg;
+ Bitstream pdf;
+ try (InputStream is = IOUtils.toInputStream(content, CharEncoding.UTF_8)) {
+ csv = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("text/csv").build();
+ jpg = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("image/jpeg").build();
+ mpg = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("video/mpeg").build();
+ pdf = BitstreamBuilder.createBitstream(context, item, is)
+ .withMimeType("application/pdf").build();
+ }
+ context.restoreAuthSystemState();
+
+ // All formats should be download only
+ verifyBitstreamDownload(csv, "text/csv;charset=UTF-8", true);
+ verifyBitstreamDownload(jpg, "image/jpeg;charset=UTF-8", true);
+ verifyBitstreamDownload(mpg, "video/mpeg;charset=UTF-8", true);
+ verifyBitstreamDownload(pdf, "application/pdf;charset=UTF-8", true);
+ }
+
+
private void verifyBitstreamDownload(Bitstream file, String contentType, boolean shouldDownload) throws Exception {
String token = getAuthToken(admin.getEmail(), password);
String header = getClient(token).perform(get("/api/core/bitstreams/" + file.getID() + "/content")
@@ -1388,11 +1479,15 @@ private void verifyBitstreamDownload(Bitstream file, String contentType, boolean
.andExpect(content().contentType(contentType))
.andReturn().getResponse().getHeader("content-disposition");
if (shouldDownload) {
- assertTrue(header.contains("attachment"));
- assertFalse(header.contains("inline"));
+ assertTrue("Content-Disposition should contain 'attachment' for " + contentType,
+ header.contains("attachment"));
+ assertFalse("Content-Disposition should NOT contain 'inline' for " + contentType,
+ header.contains("inline"));
} else {
- assertTrue(header.contains("inline"));
- assertFalse(header.contains("attachment"));
+ assertTrue("Content-Disposition should contain 'inline' for " + contentType,
+ header.contains("inline"));
+ assertFalse("Content-Disposition should NOT contain 'attachment' for " + contentType,
+ header.contains("attachment"));
}
}
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
index a0069a0a4b4f..91f94fadb479 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamRestRepositoryIT.java
@@ -711,7 +711,7 @@ public void findOneBitstreamTest_EmbargoedBitstream_ePersonREADRightsOnBundle()
// Replace anon read policy on bundle of bitstream with ePerson READ policy
resourcePolicyService.removePolicies(context, bitstream.getBundles().get(0), Constants.READ);
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson)
+ ResourcePolicyBuilder.createResourcePolicy(context, eperson, null)
.withAction(Constants.READ)
.withDspaceObject(bitstream.getBundles().get(0)).build();
@@ -774,9 +774,9 @@ public void findOneBitstreamFormatTest_EmbargoedBitstream_ePersonREADRightsOnBun
// Replace anon read policy on bundle of bitstream with ePerson READ policy
resourcePolicyService.removePolicies(context, bitstream.getBundles().get(0), Constants.READ);
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson)
- .withAction(Constants.READ)
- .withDspaceObject(bitstream.getBundles().get(0)).build();
+ ResourcePolicyBuilder.createResourcePolicy(context, eperson, null)
+ .withAction(Constants.READ)
+ .withDspaceObject(bitstream.getBundles().get(0)).build();
context.restoreAuthSystemState();
@@ -899,7 +899,7 @@ public void findOneBitstreamTest_EmbargoedBitstream_ePersonREADRightsOnItem() th
// Replace anon read policy on item of bitstream with ePerson READ policy
resourcePolicyService.removePolicies(context, publicItem1, Constants.READ);
- ResourcePolicyBuilder.createResourcePolicy(context).withUser(eperson)
+ ResourcePolicyBuilder.createResourcePolicy(context, eperson, null)
.withAction(Constants.READ)
.withDspaceObject(publicItem1).build();
@@ -1547,8 +1547,7 @@ public void testHiddenMetadataForUserWithWriteRights() throws Exception {
.build();
}
- ResourcePolicyBuilder.createResourcePolicy(context)
- .withUser(eperson)
+ ResourcePolicyBuilder.createResourcePolicy(context, eperson, null)
.withAction(WRITE)
.withDspaceObject(col1)
.build();
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java
index 259580f8c081..6b148e88e132 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/BundleRestRepositoryIT.java
@@ -347,7 +347,7 @@ public void createBundleWithSufficientPermissions() throws Exception {
.withPassword("test")
.withNameInMetadata("Create", "Bundle").build();
- ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context).withUser(createBundleEperson)
+ ResourcePolicy rp1 = ResourcePolicyBuilder.createResourcePolicy(context, createBundleEperson, null)
.withAction(Constants.ADD)
.withDspaceObject(item).build();
context.restoreAuthSystemState();
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java
index f07c816b9c98..eb49661259cc 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseAddPatchOperationIT.java
@@ -63,7 +63,7 @@ public void patchSubmissionCCLicense() throws Exception {
List ops = new ArrayList<>();
AddOperation addOperation = new AddOperation("/sections/cclicense/uri",
- "http://creativecommons.org/licenses/by-nc-sa/4.0/");
+ "https://creativecommons.org/licenses/by-nc-sa/4.0/");
ops.add(addOperation);
String patchBody = getPatchContent(ops);
@@ -74,7 +74,7 @@ public void patchSubmissionCCLicense() throws Exception {
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.sections.cclicense", allOf(
- hasJsonPath("$.uri", is("http://creativecommons.org/licenses/by-nc-sa/4.0/")),
+ hasJsonPath("$.uri", is("https://creativecommons.org/licenses/by-nc-sa/4.0/")),
hasJsonPath("$.rights",
is("Attribution-NonCommercial-ShareAlike 4.0 International")),
hasJsonPath("$.file.name", is("license_rdf"))
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java
index 8e01678899a5..dd2b99d158b9 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CCLicenseRemovePatchOperationIT.java
@@ -64,7 +64,7 @@ public void patchRemoveSubmissionCCLicense() throws Exception {
// First add a license and verify it is added
List ops = new ArrayList<>();
AddOperation addOperation = new AddOperation("/sections/cclicense/uri",
- "http://creativecommons.org/licenses/by-nc-sa/4.0/");
+ "https://creativecommons.org/licenses/by-nc-sa/4.0/");
ops.add(addOperation);
String patchBody = getPatchContent(ops);
@@ -75,7 +75,7 @@ public void patchRemoveSubmissionCCLicense() throws Exception {
.contentType(MediaType.APPLICATION_JSON_PATCH_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.sections.cclicense", allOf(
- hasJsonPath("$.uri", is("http://creativecommons.org/licenses/by-nc-sa/4.0/")),
+ hasJsonPath("$.uri", is("https://creativecommons.org/licenses/by-nc-sa/4.0/")),
hasJsonPath("$.rights",
is("Attribution-NonCommercial-ShareAlike 4.0 International")),
hasJsonPath("$.file.name", is("license_rdf"))
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java
index d97d0f2ce692..7d34aa771bdc 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionLogoControllerIT.java
@@ -24,10 +24,13 @@
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.builder.CollectionBuilder;
import org.dspace.builder.CommunityBuilder;
+import org.dspace.builder.EPersonBuilder;
import org.dspace.content.Bitstream;
import org.dspace.content.Collection;
+import org.dspace.content.Community;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Constants;
+import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.hamcrest.Matchers;
@@ -116,6 +119,34 @@ public void createLogoNoRights() throws Exception {
.andExpect(status().isForbidden());
}
+ @Test
+ public void createLogoByCollectionAdmin() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ EPerson collectionAdmin = EPersonBuilder.createEPerson(context)
+ .withEmail("test4@mail.com")
+ .withPassword(password)
+ .withCanLogin(true)
+ .build();
+
+ Community community = CommunityBuilder.createCommunity(context)
+ .withName("New Community")
+ .build();
+
+ childCollection = CollectionBuilder.createCollection(context, community)
+ .withName("name of collection")
+ .withAdminGroup(collectionAdmin)
+ .build();
+
+ context.restoreAuthSystemState();
+
+ String userToken = getAuthToken(collectionAdmin.getEmail(), password);
+ getClient(userToken).perform(
+ MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
+ .file(bitstreamFile))
+ .andExpect(status().isCreated());
+ }
+
@Test
public void createDuplicateLogo() throws Exception {
getClient(adminAuthToken).perform(
@@ -196,6 +227,42 @@ public void collectionLogoPoliciesTest() throws Exception {
));
}
+ @Test
+ public void deleteLogoByCollectionAdmin() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ EPerson collectionAdmin = EPersonBuilder.createEPerson(context)
+ .withEmail("test4@mail.com")
+ .withPassword(password)
+ .withCanLogin(true)
+ .build();
+
+ Community community = CommunityBuilder.createCommunity(context)
+ .withName("New Community")
+ .build();
+
+ childCollection = CollectionBuilder.createCollection(context, community)
+ .withName("name of collection")
+ .withAdminGroup(collectionAdmin)
+ .build();
+
+ context.restoreAuthSystemState();
+
+ String userToken = getAuthToken(collectionAdmin.getEmail(), password);
+ MvcResult mvcPostResult = getClient(userToken).perform(
+ MockMvcRequestBuilders.multipart(getLogoUrlTemplate(childCollection.getID().toString()))
+ .file(bitstreamFile))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String postContent = mvcPostResult.getResponse().getContentAsString();
+ Map mapPostResult = mapper.readValue(postContent, Map.class);
+
+ getClient(userToken)
+ .perform(delete(getBitstreamUrlTemplate(String.valueOf(mapPostResult.get("uuid")))))
+ .andExpect(status().isNoContent());
+ }
+
private String getLogoUrlTemplate(String uuid) {
return "/api/core/collections/" + uuid + "/logo";
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
index 1595fb1069ce..8c2d970735a3 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CollectionRestRepositoryIT.java
@@ -2020,8 +2020,7 @@ public void testHiddenMetadataForUserWithWriteRights() throws Exception {
- ResourcePolicyBuilder.createResourcePolicy(context)
- .withUser(eperson)
+ ResourcePolicyBuilder.createResourcePolicy(context, eperson, null)
.withAction(WRITE)
.withDspaceObject(col1)
.build();
@@ -3242,11 +3241,10 @@ public void testSubGroupOfCommunityAdminGroupAuthorizedSearch() throws Exception
communityC = CommunityBuilder.createCommunity(context)
.withName("the last community is topLevelCommunityC")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_" +
+ topLevelCommunityA.getID() + "_ADMIN"))
.withDspaceObject(communityB)
- .withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COMMUNITY_" + topLevelCommunityA.getID() + "_ADMIN"))
- .build();
+ .withAction(Constants.ADMIN).build();
collectionB = CollectionBuilder.createCollection(context, subCommunityA)
.withName("collectionB is a very original name")
.build();
@@ -3298,11 +3296,10 @@ public void testSubGroupOfSubCommunityAdminGroupAuthorizedSearch() throws Except
.withName("the last community is topLevelCommunityC")
.addParentCommunity(context, topLevelCommunityA)
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_"
+ + subCommunityA.getID() + "_ADMIN"))
.withDspaceObject(communityB)
- .withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COMMUNITY_" + subCommunityA.getID() + "_ADMIN"))
- .build();
+ .withAction(Constants.ADMIN).build();
collectionB = CollectionBuilder.createCollection(context, subCommunityA)
.withName("collectionB is a very original name")
.build();
@@ -3360,11 +3357,10 @@ public void testSubGroupOfCollectionAdminGroupAuthorizedSearch() throws Exceptio
collectionC = CollectionBuilder.createCollection(context, communityC)
.withName("the last collection is collectionC")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_"
+ + collectionA.getID() + "_ADMIN"))
.withDspaceObject(collectionB)
- .withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_ADMIN"))
- .build();
+ .withAction(Constants.ADMIN).build();
context.restoreAuthSystemState();
String token = getAuthToken(eperson.getEmail(), password);
@@ -3413,11 +3409,10 @@ public void testSubGroupOfSubmitterGroupAuthorizedSearch() throws Exception {
collectionB = CollectionBuilder.createCollection(context, communityB)
.withName("collectionB is a very original name")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_"
+ + collectionA.getID() + "_SUBMIT"))
.withDspaceObject(collectionB)
- .withAction(Constants.ADD)
- .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_SUBMIT"))
- .build();
+ .withAction(Constants.ADD).build();
collectionC = CollectionBuilder.createCollection(context, communityC)
.withName("the last collection is collectionC")
.build();
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java
index 61ebfc7dd7b6..bd6437467390 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityLogoControllerIT.java
@@ -23,9 +23,12 @@
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.builder.CommunityBuilder;
+import org.dspace.builder.EPersonBuilder;
import org.dspace.content.Bitstream;
+import org.dspace.content.Community;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Constants;
+import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.hamcrest.Matchers;
@@ -111,6 +114,29 @@ public void createLogoNoRights() throws Exception {
.andExpect(status().isForbidden());
}
+ @Test
+ public void createLogoBYCommunityAdmin() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ EPerson communityAdmin = EPersonBuilder.createEPerson(context)
+ .withEmail("test4@mail.com")
+ .withPassword(password)
+ .withCanLogin(true)
+ .build();
+
+ Community community = CommunityBuilder.createCommunity(context)
+ .withName("New Community")
+ .withAdminGroup(communityAdmin)
+ .build();
+
+ context.restoreAuthSystemState();
+ String userToken = getAuthToken(communityAdmin.getEmail(), password);
+ getClient(userToken).perform(
+ MockMvcRequestBuilders.multipart(getLogoUrlTemplate(community.getID().toString()))
+ .file(bitstreamFile))
+ .andExpect(status().isCreated());
+ }
+
@Test
public void createDuplicateLogo() throws Exception {
getClient(adminAuthToken).perform(
@@ -191,6 +217,38 @@ public void communityLogoPoliciesTest() throws Exception {
));
}
+ @Test
+ public void deleteLogoByCommunityAdmin() throws Exception {
+ context.turnOffAuthorisationSystem();
+
+ EPerson communityAdmin = EPersonBuilder.createEPerson(context)
+ .withEmail("test4@mail.com")
+ .withPassword(password)
+ .withCanLogin(true)
+ .build();
+
+ Community community = CommunityBuilder.createCommunity(context)
+ .withName("New Community")
+ .withAdminGroup(communityAdmin)
+ .build();
+
+ context.restoreAuthSystemState();
+
+ String userToken = getAuthToken(communityAdmin.getEmail(), password);
+ MvcResult mvcPostResult = getClient(userToken).perform(
+ MockMvcRequestBuilders.multipart(getLogoUrlTemplate(community.getID().toString()))
+ .file(bitstreamFile))
+ .andExpect(status().isCreated())
+ .andReturn();
+
+ String postContent = mvcPostResult.getResponse().getContentAsString();
+ Map mapPostResult = mapper.readValue(postContent, Map.class);
+
+ getClient(userToken)
+ .perform(delete(getBitstreamUrlTemplate(String.valueOf(mapPostResult.get("uuid")))))
+ .andExpect(status().isNoContent());
+ }
+
private String getLogoUrlTemplate(String uuid) {
return "/api/core/communities/" + uuid + "/logo";
}
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java
index 30614e6125f2..22e62c24168a 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CommunityRestRepositoryIT.java
@@ -2370,10 +2370,10 @@ public void testSubGroupOfCommunityAdminGroupAuthorizedSearch() throws Exception
communityC = CommunityBuilder.createCommunity(context)
.withName("the last community is topLevelCommunityC")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_"
+ + topLevelCommunityA.getID() + "_ADMIN"))
.withDspaceObject(communityB)
.withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COMMUNITY_" + topLevelCommunityA.getID() + "_ADMIN"))
.build();
context.restoreAuthSystemState();
@@ -2423,10 +2423,10 @@ public void testSubGroupOfSubCommunityAdminGroupAuthorizedSearch() throws Except
.withName("the last community is topLevelCommunityC")
.addParentCommunity(context, topLevelCommunityA)
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COMMUNITY_"
+ + subCommunityA.getID() + "_ADMIN"))
.withDspaceObject(communityB)
.withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COMMUNITY_" + subCommunityA.getID() + "_ADMIN"))
.build();
context.restoreAuthSystemState();
@@ -2473,10 +2473,10 @@ public void testSubGroupOfCollectionAdminGroupAuthorizedSearch() throws Exceptio
Collection collectionB = CollectionBuilder.createCollection(context, communityB)
.withName("collectionB")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_"
+ + collectionA.getID() + "_ADMIN"))
.withDspaceObject(collectionB)
.withAction(Constants.ADMIN)
- .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_ADMIN"))
.build();
communityC = CommunityBuilder.createCommunity(context)
.withName("the last community is topLevelCommunityC")
@@ -2521,10 +2521,10 @@ public void testSubGroupOfSubmitterGroupAuthorizedSearch() throws Exception {
Collection collectionB = CollectionBuilder.createCollection(context, communityB)
.withName("collectionB")
.build();
- ResourcePolicyBuilder.createResourcePolicy(context)
+ ResourcePolicyBuilder.createResourcePolicy(context, null, groupService.findByName(context, "COLLECTION_"
+ + collectionA.getID() + "_SUBMIT"))
.withDspaceObject(collectionB)
.withAction(Constants.ADD)
- .withGroup(groupService.findByName(context, "COLLECTION_" + collectionA.getID() + "_SUBMIT"))
.build();
communityC = CommunityBuilder.createCommunity(context)
.withName("the last community is topLevelCommunityC")
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java
index a8417e84f809..1ab5a3203c08 100644
--- a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CrossRefImportMetadataSourceServiceIT.java
@@ -48,6 +48,24 @@ public class CrossRefImportMetadataSourceServiceIT extends AbstractLiveImportInt
@Autowired
private CrossRefImportMetadataSourceServiceImpl crossRefServiceImpl;
+ @Test
+ public void crossRefImportMetadataGetNoRecordsTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+ CloseableHttpClient originalHttpClient = liveImportClientImpl.getHttpClient();
+ CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class);
+ try {
+ liveImportClientImpl.setHttpClient(httpClient);
+ CloseableHttpResponse response = mockResponse("" , 404, "Not Found");
+ when(httpClient.execute(ArgumentMatchers.any())).thenReturn(response);
+
+ context.restoreAuthSystemState();
+ Collection recordsImported = crossRefServiceImpl.getRecords("test query", 0, 2);
+ assertEquals(0, recordsImported.size());
+ } finally {
+ liveImportClientImpl.setHttpClient(originalHttpClient);
+ }
+ }
+
@Test
public void crossRefImportMetadataGetRecordsTest() throws Exception {
context.turnOffAuthorisationSystem();
diff --git a/dspace-server-webapp/src/test/java/org/dspace/app/rest/CsrfRestControllerIT.java b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CsrfRestControllerIT.java
new file mode 100644
index 000000000000..1bfdc8feaff0
--- /dev/null
+++ b/dspace-server-webapp/src/test/java/org/dspace/app/rest/CsrfRestControllerIT.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.dspace.app.rest.security.DSpaceCsrfTokenRepository;
+import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.test.web.servlet.MockMvc;
+
+/**
+ * Integration test for the /api/security/csrf endpoint
+ *