mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge branch 'DSpace:main' into master
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
*/target/
|
||||
dspace/modules/*/target/
|
||||
Dockerfile.*
|
||||
dspace/src/main/docker/dspace-postgres-pgcrypto
|
||||
dspace/src/main/docker/dspace-postgres-pgcrypto-curl
|
||||
dspace/src/main/docker/dspace-postgres-loadsql
|
||||
dspace/src/main/docker/README.md
|
||||
dspace/src/main/docker-compose/
|
||||
|
189
.github/dependabot.yml
vendored
189
.github/dependabot.yml
vendored
@@ -13,6 +13,7 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
time: "02:00"
|
||||
# Allow up to 10 open PRs for dependencies
|
||||
open-pull-requests-limit: 10
|
||||
# Group together some upgrades in a single PR
|
||||
@@ -28,7 +29,7 @@ updates:
|
||||
- "com.google.code.findbugs:*"
|
||||
- "com.google.errorprone:*"
|
||||
- "com.puppycrawl.tools:checkstyle"
|
||||
- "org.sonatype.plugins:*"
|
||||
- "org.sonatype.*:*"
|
||||
exclude-patterns:
|
||||
# Exclude anything from Spring, as that is in a separate group
|
||||
- "org.springframework.*:*"
|
||||
@@ -43,9 +44,11 @@ updates:
|
||||
- "com.h2database:*"
|
||||
- "io.findify:s3mock*"
|
||||
- "io.netty:*"
|
||||
- "org.apache.httpcomponents.client5:*"
|
||||
- "org.hamcrest:*"
|
||||
- "org.mock-server:*"
|
||||
- "org.mockito:*"
|
||||
- "org.xmlunit:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
@@ -73,7 +76,6 @@ updates:
|
||||
patterns:
|
||||
- "org.hibernate.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Jakarta deps in a single PR
|
||||
jakarta:
|
||||
@@ -103,21 +105,36 @@ updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group Tika, bouncycastle, and asm because they are tightly integrated
|
||||
# and we theoretically want to keep them in sync.
|
||||
tika:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.tika:*:*"
|
||||
- "org.bouncycastle:*:*"
|
||||
- "org.ow2.asm:*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
# Don't try to auto-update any DSpace dependencies
|
||||
- dependency-name: "org.dspace:*"
|
||||
- dependency-name: "org.dspace.*:*"
|
||||
# Ignore major/minor updates for Hibernate. Only patch updates can be automated.
|
||||
- dependency-name: "org.hibernate.*:*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
# Ignore all major version updates for all dependencies. We'll only automate minor/patch updates.
|
||||
- dependency-name: "*"
|
||||
update-types: ["version-update:semver-major"]
|
||||
######################
|
||||
## dspace-8_x branch
|
||||
## dspace-9_x branch
|
||||
######################
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
target-branch: dspace-8_x
|
||||
target-branch: dspace-9_x
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
time: "02:00"
|
||||
# Allow up to 10 open PRs for dependencies
|
||||
open-pull-requests-limit: 10
|
||||
# Group together some upgrades in a single PR
|
||||
@@ -133,7 +150,7 @@ updates:
|
||||
- "com.google.code.findbugs:*"
|
||||
- "com.google.errorprone:*"
|
||||
- "com.puppycrawl.tools:checkstyle"
|
||||
- "org.sonatype.plugins:*"
|
||||
- "org.sonatype.*:*"
|
||||
exclude-patterns:
|
||||
# Exclude anything from Spring, as that is in a separate group
|
||||
- "org.springframework.*:*"
|
||||
@@ -148,9 +165,11 @@ updates:
|
||||
- "com.h2database:*"
|
||||
- "io.findify:s3mock*"
|
||||
- "io.netty:*"
|
||||
- "org.apache.httpcomponents.client5:*"
|
||||
- "org.hamcrest:*"
|
||||
- "org.mock-server:*"
|
||||
- "org.mockito:*"
|
||||
- "org.xmlunit:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
@@ -178,7 +197,6 @@ updates:
|
||||
patterns:
|
||||
- "org.hibernate.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Jakarta deps in a single PR
|
||||
jakarta:
|
||||
@@ -208,21 +226,36 @@ updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group Tika, bouncycastle, and asm because they are tightly integrated
|
||||
# and we theoretically want to keep them in sync.
|
||||
tika:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.tika:*:*"
|
||||
- "org.bouncycastle:*:*"
|
||||
- "org.ow2.asm:*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
# Don't try to auto-update any DSpace dependencies
|
||||
- dependency-name: "org.dspace:*"
|
||||
- dependency-name: "org.dspace.*:*"
|
||||
# Ignore major/minor updates for Hibernate. Only patch updates can be automated.
|
||||
- dependency-name: "org.hibernate.*:*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
# Ignore all major version updates for all dependencies. We'll only automate minor/patch updates.
|
||||
- dependency-name: "*"
|
||||
update-types: [ "version-update:semver-major" ]
|
||||
######################
|
||||
## dspace-7_x branch
|
||||
## dspace-8_x branch
|
||||
######################
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
target-branch: dspace-7_x
|
||||
target-branch: dspace-8_x
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
time: "02:00"
|
||||
# Allow up to 10 open PRs for dependencies
|
||||
open-pull-requests-limit: 10
|
||||
# Group together some upgrades in a single PR
|
||||
@@ -238,7 +271,7 @@ updates:
|
||||
- "com.google.code.findbugs:*"
|
||||
- "com.google.errorprone:*"
|
||||
- "com.puppycrawl.tools:checkstyle"
|
||||
- "org.sonatype.plugins:*"
|
||||
- "org.sonatype.*:*"
|
||||
exclude-patterns:
|
||||
# Exclude anything from Spring, as that is in a separate group
|
||||
- "org.springframework.*:*"
|
||||
@@ -253,9 +286,11 @@ updates:
|
||||
- "com.h2database:*"
|
||||
- "io.findify:s3mock*"
|
||||
- "io.netty:*"
|
||||
- "org.apache.httpcomponents.client5:*"
|
||||
- "org.hamcrest:*"
|
||||
- "org.mock-server:*"
|
||||
- "org.mockito:*"
|
||||
- "org.xmlunit:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
@@ -283,7 +318,6 @@ updates:
|
||||
patterns:
|
||||
- "org.hibernate.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Jakarta deps in a single PR
|
||||
jakarta:
|
||||
@@ -295,6 +329,127 @@ updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Spring deps in a single PR
|
||||
spring:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.springframework:*"
|
||||
- "org.springframework.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all WebJARs deps in a single PR
|
||||
webjars:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.webjars:*"
|
||||
- "org.webjars.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group Tika, bouncycastle, and asm because they are tightly integrated
|
||||
# and we theoretically want to keep them in sync.
|
||||
tika:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.tika:*:*"
|
||||
- "org.bouncycastle:*:*"
|
||||
- "org.ow2.asm:*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
# Don't try to auto-update any DSpace dependencies
|
||||
- dependency-name: "org.dspace:*"
|
||||
- dependency-name: "org.dspace.*:*"
|
||||
# Ignore major/minor updates for Hibernate. Only patch updates can be automated.
|
||||
- dependency-name: "org.hibernate.*:*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
# Ignore all major version updates for all dependencies. We'll only automate minor/patch updates.
|
||||
- dependency-name: "*"
|
||||
update-types: [ "version-update:semver-major" ]
|
||||
######################
|
||||
## dspace-7_x branch
|
||||
######################
|
||||
- package-ecosystem: "maven"
|
||||
directory: "/"
|
||||
target-branch: dspace-7_x
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
time: "02:00"
|
||||
# Allow up to 10 open PRs for dependencies
|
||||
open-pull-requests-limit: 10
|
||||
# Group together some upgrades in a single PR
|
||||
groups:
|
||||
# Group together all Build Tools in a single PR
|
||||
build-tools:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.maven.plugins:*"
|
||||
- "*:*-maven-plugin"
|
||||
- "*:maven-*-plugin"
|
||||
- "com.github.spotbugs:spotbugs"
|
||||
- "com.google.code.findbugs:*"
|
||||
- "com.google.errorprone:*"
|
||||
- "com.puppycrawl.tools:checkstyle"
|
||||
- "org.sonatype.*:*"
|
||||
exclude-patterns:
|
||||
# Exclude anything from Spring, as that is in a separate group
|
||||
- "org.springframework.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
test-tools:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "junit:*"
|
||||
- "com.github.stefanbirker:system-rules"
|
||||
- "com.h2database:*"
|
||||
- "io.findify:s3mock*"
|
||||
- "io.netty:*"
|
||||
- "org.hamcrest:*"
|
||||
- "org.mock-server:*"
|
||||
- "org.mockito:*"
|
||||
- "org.xmlunit:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Apache Commons deps in a single PR
|
||||
apache-commons:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.commons:*"
|
||||
- "commons-*:commons-*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all fasterxml deps in a single PR
|
||||
fasterxml:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "com.fasterxml:*"
|
||||
- "com.fasterxml.*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Hibernate deps in a single PR
|
||||
hibernate:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.hibernate.*:*"
|
||||
update-types:
|
||||
- "patch"
|
||||
# Group together all Javax deps in a single PR
|
||||
# NOTE: Javax is only used in 7.x and has been replaced by Jakarta in 8.x and later
|
||||
jakarta:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "javax.*:*"
|
||||
- "*:javax.mail"
|
||||
- "org.glassfish.jaxb:jaxb-runtime"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group together all Google deps in a single PR
|
||||
# NOTE: These Google deps are only used in 7.x and have been removed in 8.x and later
|
||||
google-apis:
|
||||
@@ -325,6 +480,17 @@ updates:
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
# Group Tika, bouncycastle, and asm because they are tightly integrated
|
||||
# and we theoretically want to keep them in sync.
|
||||
tika:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- "org.apache.tika:*:*"
|
||||
- "org.bouncycastle:*:*"
|
||||
- "org.ow2.asm:*:*"
|
||||
update-types:
|
||||
- "minor"
|
||||
- "patch"
|
||||
ignore:
|
||||
# Don't try to auto-update any DSpace dependencies
|
||||
- dependency-name: "org.dspace:*"
|
||||
@@ -336,6 +502,9 @@ updates:
|
||||
# See https://github.com/DSpace/DSpace/pull/9888#issuecomment-2408165545
|
||||
- dependency-name: "org.springframework.security:*"
|
||||
versions: [">=5.8.0"]
|
||||
# Ignore major/minor updates for Hibernate. Only patch updates can be automated.
|
||||
- dependency-name: "org.hibernate.*:*"
|
||||
update-types: ["version-update:semver-major", "version-update:semver-minor"]
|
||||
# Ignore all major version updates for all dependencies. We'll only automate minor/patch updates.
|
||||
- dependency-name: "*"
|
||||
update-types: [ "version-update:semver-major" ]
|
||||
|
51
.github/workflows/docker.yml
vendored
51
.github/workflows/docker.yml
vendored
@@ -113,39 +113,19 @@ jobs:
|
||||
REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_SOLR_URL }}
|
||||
REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_SOLR_URL }}
|
||||
|
||||
###########################################################
|
||||
# Build/Push the 'dspace/dspace-postgres-pgcrypto' image
|
||||
###########################################################
|
||||
dspace-postgres-pgcrypto:
|
||||
########################################################
|
||||
# Build/Push the 'dspace/dspace-postgres-loadsql' image
|
||||
########################################################
|
||||
dspace-postgres-loadsql:
|
||||
# Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace'
|
||||
if: github.repository == 'dspace/dspace'
|
||||
uses: ./.github/workflows/reusable-docker-build.yml
|
||||
with:
|
||||
build_id: dspace-postgres-pgcrypto-prod
|
||||
image_name: dspace/dspace-postgres-pgcrypto
|
||||
# Must build out of subdirectory to have access to install script for pgcrypto.
|
||||
build_id: dspace-postgres-loadsql
|
||||
image_name: dspace/dspace-postgres-loadsql
|
||||
# Must build out of subdirectory to have access to install script.
|
||||
# NOTE: this context will build the image based on the Dockerfile in the specified directory
|
||||
dockerfile_context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/
|
||||
secrets:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
|
||||
########################################################################
|
||||
# Build/Push the 'dspace/dspace-postgres-pgcrypto' image (-loadsql tag)
|
||||
########################################################################
|
||||
dspace-postgres-pgcrypto-loadsql:
|
||||
# Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace'
|
||||
if: github.repository == 'dspace/dspace'
|
||||
uses: ./.github/workflows/reusable-docker-build.yml
|
||||
with:
|
||||
build_id: dspace-postgres-pgcrypto-loadsql
|
||||
image_name: dspace/dspace-postgres-pgcrypto
|
||||
# Must build out of subdirectory to have access to install script for pgcrypto.
|
||||
# NOTE: this context will build the image based on the Dockerfile in the specified directory
|
||||
dockerfile_context: ./dspace/src/main/docker/dspace-postgres-pgcrypto-curl/
|
||||
# Suffix all tags with "-loadsql". Otherwise, it uses the same
|
||||
# tagging logic as the primary 'dspace/dspace-postgres-pgcrypto' image above.
|
||||
tags_flavor: suffix=-loadsql
|
||||
dockerfile_context: ./dspace/src/main/docker/dspace-postgres-loadsql/
|
||||
secrets:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}
|
||||
@@ -158,7 +138,7 @@ jobs:
|
||||
if: github.repository == 'dspace/dspace'
|
||||
runs-on: ubuntu-latest
|
||||
# Must run after all major images are built
|
||||
needs: [dspace, dspace-test, dspace-cli, dspace-postgres-pgcrypto, dspace-solr]
|
||||
needs: [dspace, dspace-test, dspace-cli, dspace-solr]
|
||||
env:
|
||||
# Override defaults dspace.server.url because backend starts at http://127.0.0.1:8080
|
||||
dspace__P__server__P__url: http://127.0.0.1:8080/server
|
||||
@@ -220,6 +200,19 @@ jobs:
|
||||
result=$(wget -O- -q http://127.0.0.1:8080/server/api/core/collections)
|
||||
echo "$result"
|
||||
echo "$result" | grep -oE "\"Dog in Yard\","
|
||||
# Verify basic backend logging is working.
|
||||
# 1. Access the top communities list. Verify that the "Before request" INFO statement is logged
|
||||
# 2. Access an invalid endpoint (and ignore 404 response). Verify that a "status:404" WARN statement is logged
|
||||
- name: Verify backend is logging properly
|
||||
run: |
|
||||
wget -O/dev/null -q http://127.0.0.1:8080/server/api/core/communities/search/top
|
||||
logs=$(docker compose -f docker-compose.yml logs -n 5 dspace)
|
||||
echo "$logs"
|
||||
echo "$logs" | grep -o "Before request \[GET /server/api/core/communities/search/top\]"
|
||||
wget -O/dev/null -q http://127.0.0.1:8080/server/api/does/not/exist || true
|
||||
logs=$(docker compose -f docker-compose.yml logs -n 5 dspace)
|
||||
echo "$logs"
|
||||
echo "$logs" | grep -o "status:404 exception: The repository type does.not was not found"
|
||||
# Verify Handle Server can be stared and is working properly
|
||||
# 1. First generate the "[dspace]/handle-server" folder with the sitebndl.zip
|
||||
# 2. Start the Handle Server (and wait 20 seconds to let it start up)
|
||||
|
11
.github/workflows/reusable-docker-build.yml
vendored
11
.github/workflows/reusable-docker-build.yml
vendored
@@ -72,7 +72,7 @@ env:
|
||||
REDEPLOY_SANDBOX_URL: ${{ secrets.REDEPLOY_SANDBOX_URL }}
|
||||
REDEPLOY_DEMO_URL: ${{ secrets.REDEPLOY_DEMO_URL }}
|
||||
# Current DSpace branches (and architecture) which are deployed to demo.dspace.org & sandbox.dspace.org respectively
|
||||
DEPLOY_DEMO_BRANCH: 'dspace-8_x'
|
||||
DEPLOY_DEMO_BRANCH: 'dspace-9_x'
|
||||
DEPLOY_SANDBOX_BRANCH: 'main'
|
||||
DEPLOY_ARCH: 'linux/amd64'
|
||||
# Registry used during building of Docker images. (All images are later copied to docker.io registry)
|
||||
@@ -86,17 +86,16 @@ jobs:
|
||||
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 }}
|
||||
# If ARM64, then use the Ubuntu ARM64 runner. Otherwise, use the Ubuntu AMD64 runner
|
||||
runs-on: ${{ matrix.arch == 'linux/arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||
|
||||
steps:
|
||||
# This step converts the slashes in the "arch" matrix values above into dashes & saves to env.ARCH_NAME
|
||||
@@ -122,10 +121,6 @@ jobs:
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# https://github.com/docker/setup-qemu-action
|
||||
- name: Set up QEMU emulation to build for multiple architectures
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -28,6 +28,9 @@ nbdist/
|
||||
nbactions.xml
|
||||
nb-configuration.xml
|
||||
|
||||
## Ignore project files created by Visual Studio Code
|
||||
.vscode/
|
||||
|
||||
## Ignore all *.properties file in root folder, EXCEPT build.properties (the default)
|
||||
## KEPT FOR BACKWARDS COMPATIBILITY WITH 5.x (build.properties is now replaced with local.cfg)
|
||||
/*.properties
|
||||
|
@@ -10,7 +10,7 @@ DSpace is a community built and supported project. We do not have a centralized
|
||||
## Contribute new code via a Pull Request
|
||||
|
||||
We accept [GitHub Pull Requests (PRs)](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) at any time from anyone.
|
||||
Contributors to each release are recognized in our [Release Notes](https://wiki.lyrasis.org/display/DSDOC8x/Release+Notes).
|
||||
Contributors to each release are recognized in our [Release Notes](https://wiki.lyrasis.org/display/DSDOC9x/Release+Notes).
|
||||
|
||||
Code Contribution Checklist
|
||||
- [ ] PRs _should_ be smaller in size (ideally less than 1,000 lines of code, not including comments & tests)
|
||||
|
@@ -50,6 +50,10 @@ ADD --chown=dspace dspace-oai/pom.xml /app/dspace-oai/
|
||||
RUN mkdir -p /app/dspace-rdf
|
||||
ADD --chown=dspace dspace-rdf/pom.xml /app/dspace-rdf/
|
||||
|
||||
# 'dspace-saml2' module POM
|
||||
RUN mkdir -p /app/dspace-saml2
|
||||
ADD --chown=dspace dspace-saml2/pom.xml /app/dspace-saml2/
|
||||
|
||||
# 'dspace-server-webapp' module POM
|
||||
RUN mkdir -p /app/dspace-server-webapp
|
||||
ADD --chown=dspace dspace-server-webapp/pom.xml /app/dspace-server-webapp/
|
||||
|
@@ -21,71 +21,74 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
Apache Software License, Version 2.0:
|
||||
|
||||
* Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net)
|
||||
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.12.261 - https://aws.amazon.com/sdkforjava)
|
||||
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.12.261 - https://aws.amazon.com/sdkforjava)
|
||||
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.261 - https://aws.amazon.com/sdkforjava)
|
||||
* JMES Path Query library (com.amazonaws:jmespath-java:1.12.261 - https://aws.amazon.com/sdkforjava)
|
||||
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.12.783 - https://aws.amazon.com/sdkforjava)
|
||||
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.12.783 - https://aws.amazon.com/sdkforjava)
|
||||
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.783 - https://aws.amazon.com/sdkforjava)
|
||||
* JMES Path Query library (com.amazonaws:jmespath-java:1.12.783 - https://aws.amazon.com/sdkforjava)
|
||||
* Titanium JSON-LD 1.1 (JRE11) (com.apicatalog:titanium-json-ld:1.3.2 - https://github.com/filip26/titanium-json-ld)
|
||||
* HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc)
|
||||
* com.drewnoakes:metadata-extractor (com.drewnoakes:metadata-extractor:2.19.0 - https://drewnoakes.com/code/exif/)
|
||||
* parso (com.epam:parso:2.0.14 - https://github.com/epam/parso)
|
||||
* ClassMate (com.fasterxml:classmate:1.6.0 - https://github.com/FasterXML/java-classmate)
|
||||
* 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)
|
||||
* Internet Time Utility (com.ethlo.time:itu:1.7.0 - https://github.com/ethlo/itu)
|
||||
* ClassMate (com.fasterxml:classmate:1.5.1 - https://github.com/FasterXML/java-classmate)
|
||||
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.19.0 - https://github.com/FasterXML/jackson)
|
||||
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.19.0 - https://github.com/FasterXML/jackson-core)
|
||||
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.19.0 - https://github.com/FasterXML/jackson)
|
||||
* Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.17.2 - https://github.com/FasterXML/jackson-dataformats-binary)
|
||||
* Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.15.2 - https://github.com/FasterXML/jackson-dataformats-binary)
|
||||
* Jackson-dataformat-TOML (com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2 - https://github.com/FasterXML/jackson-dataformats-text)
|
||||
* Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.16.2 - https://github.com/FasterXML/jackson-dataformats-text)
|
||||
* Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.15.4 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8)
|
||||
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.16.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
|
||||
* Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.18.3 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8)
|
||||
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.19.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
|
||||
* Jackson Jakarta-RS: base (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-base)
|
||||
* Jackson Jakarta-RS: JSON (com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:2.16.2 - https://github.com/FasterXML/jackson-jakarta-rs-providers/jackson-jakarta-rs-json-provider)
|
||||
* Jackson module: Jakarta XML Bind Annotations (jakarta.xml.bind) (com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.16.2 - https://github.com/FasterXML/jackson-modules-base)
|
||||
* Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.15.4 - 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)
|
||||
* Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.18.3 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names)
|
||||
* Java UUID Generator (com.fasterxml.uuid:java-uuid-generator:4.1.0 - https://github.com/cowtowncoder/java-uuid-generator)
|
||||
* Woodstox (com.fasterxml.woodstox:woodstox-core:6.5.1 - https://github.com/FasterXML/woodstox)
|
||||
* zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.16 - https://github.com/flipkart-incubator/zjsonpatch/)
|
||||
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.9.3 - https://github.com/ben-manes/caffeine)
|
||||
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:3.1.6 - https://github.com/ben-manes/caffeine)
|
||||
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:3.1.8 - https://github.com/ben-manes/caffeine)
|
||||
* JSON.simple (com.github.cliftonlabs:json-simple:3.0.2 - https://cliftonlabs.github.io/json-simple/)
|
||||
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
|
||||
* 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)
|
||||
* json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
|
||||
* json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
|
||||
* json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
|
||||
* msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
|
||||
* uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
|
||||
* JCIP Annotations under Apache License (com.github.stephenc.jcip:jcip-annotations:1.0-1 - http://stephenc.github.com/jcip-annotations)
|
||||
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.23.0 - https://github.com/google/google-api-java-client/google-api-client)
|
||||
* Google Analytics API v3-rev145-1.23.0 (com.google.apis:google-api-services-analytics:v3-rev145-1.23.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
|
||||
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
|
||||
* Gson (com.google.code.gson:gson:2.10.1 - https://github.com/google/gson/gson)
|
||||
* error-prone annotations (com.google.errorprone:error_prone_annotations:2.10.0 - https://errorprone.info/error_prone_annotations)
|
||||
* Gson (com.google.code.gson:gson:2.13.1 - https://github.com/google/gson)
|
||||
* error-prone annotations (com.google.errorprone:error_prone_annotations:2.38.0 - https://errorprone.info/error_prone_annotations)
|
||||
* Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
|
||||
* Guava: Google Core Libraries for Java (com.google.guava:guava:32.0.0-jre - https://github.com/google/guava)
|
||||
* Guava: Google Core Libraries for Java (JDK5 Backport) (com.google.guava:guava-jdk5:17.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
|
||||
* Guava: Google Core Libraries for Java (com.google.guava:guava:32.1.3-jre - https://github.com/google/guava)
|
||||
* Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
|
||||
* Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.23.0 - https://github.com/google/google-http-java-client/google-http-client)
|
||||
* 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)
|
||||
* Google Guice - Core Library (com.google.inject:guice:7.0.0 - https://github.com/google/guice/guice)
|
||||
* Google Guice - Extensions - AssistedInject (com.google.inject.extensions:guice-assistedinject:7.0.0 - https://github.com/google/guice/extensions-parent/guice-assistedinject)
|
||||
* 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.5 - https://jackcess.sourceforge.io)
|
||||
* Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.2 - http://jackcessencrypt.sf.net)
|
||||
* Jackcess (com.healthmarketscience.jackcess:jackcess:4.0.8 - https://jackcess.sourceforge.io)
|
||||
* Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:4.0.3 - 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)
|
||||
* 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:9.37.3 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
|
||||
* opencsv (com.opencsv:opencsv:5.9 - http://opencsv.sf.net)
|
||||
* JsonSchemaValidator (com.networknt:json-schema-validator:1.0.76 - https://github.com/networknt/json-schema-validator)
|
||||
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:9.28 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
|
||||
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:9.48 - https://bitbucket.org/connect2id/nimbus-jose-jwt)
|
||||
* opencsv (com.opencsv:opencsv:5.11 - 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)
|
||||
* mockwebserver (com.squareup.okhttp3:mockwebserver:4.12.0 - https://square.github.io/okhttp/)
|
||||
* okhttp (com.squareup.okhttp3:okhttp:4.12.0 - https://square.github.io/okhttp/)
|
||||
* okio (com.squareup.okio:okio:3.6.0 - https://github.com/square/okio/)
|
||||
* okio (com.squareup.okio:okio-jvm:3.6.0 - https://github.com/square/okio/)
|
||||
* 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)
|
||||
@@ -98,102 +101,113 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* scala-logging (com.typesafe.scala-logging:scala-logging_2.13:3.9.2 - https://github.com/lightbend/scala-logging)
|
||||
* JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk)
|
||||
* SparseBitSet (com.zaxxer:SparseBitSet:1.3 - https://github.com/brettwooldridge/SparseBitSet)
|
||||
* 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.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 BeanUtils (commons-beanutils:commons-beanutils:1.10.1 - https://commons.apache.org/proper/commons-beanutils)
|
||||
* Apache Commons CLI (commons-cli:commons-cli:1.9.0 - https://commons.apache.org/proper/commons-cli/)
|
||||
* Apache Commons Codec (commons-codec:commons-codec:1.18.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:2.1 - http://commons.apache.org/digester/)
|
||||
* Apache Commons IO (commons-io:commons-io:2.15.1 - https://commons.apache.org/proper/commons-io/)
|
||||
* Apache Commons IO (commons-io:commons-io:2.19.0 - 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.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/)
|
||||
* Apache Commons Logging (commons-logging:commons-logging:1.3.5 - https://commons.apache.org/proper/commons-logging/)
|
||||
* Apache Commons Validator (commons-validator:commons-validator:1.9.0 - http://commons.apache.org/proper/commons-validator/)
|
||||
* GeoJson POJOs for Jackson (de.grundid.opendatalab:geojson-jackson:1.14 - https://github.com/opendatalab-de/geojson-jackson)
|
||||
* broker-client (eu.openaire:broker-client:1.1.2 - http://api.openaire.eu/broker/broker-client)
|
||||
* OpenAIRE Funders Model (eu.openaire:funders-model:2.0.0 - https://api.openaire.eu)
|
||||
* Metrics Core (io.dropwizard.metrics:metrics-core:4.1.5 - https://metrics.dropwizard.io/metrics-core)
|
||||
* Metrics Core (io.dropwizard.metrics:metrics-core:4.2.25 - https://metrics.dropwizard.io/metrics-core)
|
||||
* Graphite Integration for Metrics (io.dropwizard.metrics:metrics-graphite:4.1.5 - https://metrics.dropwizard.io/metrics-graphite)
|
||||
* 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)
|
||||
* SWORD v2 Common Server Library (forked) (io.gdcc:sword2-server:2.0.0 - https://github.com/gdcc/sword2-server)
|
||||
* micrometer-commons (io.micrometer:micrometer-commons:1.12.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-core (io.micrometer:micrometer-core:1.12.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-jakarta9 (io.micrometer:micrometer-jakarta9:1.12.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-observation (io.micrometer:micrometer-observation:1.12.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* Netty/Buffer (io.netty:netty-buffer:4.1.106.Final - https://netty.io/netty-buffer/)
|
||||
* micrometer-commons (io.micrometer:micrometer-commons:1.14.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-commons (io.micrometer:micrometer-commons:1.14.7 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-core (io.micrometer:micrometer-core:1.14.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-jakarta9 (io.micrometer:micrometer-jakarta9:1.14.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-observation (io.micrometer:micrometer-observation:1.14.6 - https://github.com/micrometer-metrics/micrometer)
|
||||
* micrometer-observation (io.micrometer:micrometer-observation:1.14.7 - https://github.com/micrometer-metrics/micrometer)
|
||||
* 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.106.Final - https://netty.io/netty-common/)
|
||||
* Netty/Codec/HTTP (io.netty:netty-codec-http:4.1.86.Final - https://netty.io/netty-codec-http/)
|
||||
* Netty/Codec/HTTP2 (io.netty:netty-codec-http2:4.1.86.Final - https://netty.io/netty-codec-http2/)
|
||||
* Netty/Codec/Socks (io.netty:netty-codec-socks:4.1.86.Final - https://netty.io/netty-codec-socks/)
|
||||
* Netty/Common (io.netty:netty-common:4.1.99.Final - https://netty.io/netty-common/)
|
||||
* Netty/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/Handler/Proxy (io.netty:netty-handler-proxy:4.1.86.Final - https://netty.io/netty-handler-proxy/)
|
||||
* Netty/Resolver (io.netty:netty-resolver:4.1.99.Final - https://netty.io/netty-resolver/)
|
||||
* Netty/Transport (io.netty:netty-transport:4.1.106.Final - https://netty.io/netty-transport/)
|
||||
* Netty/TomcatNative [BoringSSL - Static] (io.netty:netty-tcnative-boringssl-static:2.0.56.Final - https://github.com/netty/netty-tcnative/netty-tcnative-boringssl-static/)
|
||||
* Netty/TomcatNative [OpenSSL - Classes] (io.netty:netty-tcnative-classes:2.0.56.Final - https://github.com/netty/netty-tcnative/netty-tcnative-classes/)
|
||||
* Netty/Transport (io.netty:netty-transport:4.1.99.Final - https://netty.io/netty-transport/)
|
||||
* Netty/Transport/Classes/Epoll (io.netty:netty-transport-classes-epoll:4.1.99.Final - https://netty.io/netty-transport-classes-epoll/)
|
||||
* Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.99.Final - https://netty.io/netty-transport-native-epoll/)
|
||||
* Netty/Transport/Native/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)
|
||||
* Prometheus Java Simpleclient (io.prometheus:simpleclient:0.16.0 - http://github.com/prometheus/client_java/simpleclient)
|
||||
* Prometheus Java Simpleclient Common (io.prometheus:simpleclient_common:0.16.0 - http://github.com/prometheus/client_java/simpleclient_common)
|
||||
* Prometheus Java Simpleclient Httpserver (io.prometheus:simpleclient_httpserver:0.16.0 - http://github.com/prometheus/client_java/simpleclient_httpserver)
|
||||
* Prometheus Java Span Context Supplier - Common (io.prometheus:simpleclient_tracer_common:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_common)
|
||||
* Prometheus Java Span Context Supplier - OpenTelemetry (io.prometheus:simpleclient_tracer_otel:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_otel)
|
||||
* Prometheus Java Span Context Supplier - OpenTelemetry Agent (io.prometheus:simpleclient_tracer_otel_agent:0.16.0 - http://github.com/prometheus/client_java/simpleclient_tracer/simpleclient_tracer_otel_agent)
|
||||
* Google S2 geometry library (io.sgr:s2-geometry-library-java:1.0.0 - https://github.com/sgr-io/s2-geometry-library-java)
|
||||
* Jandex: Core (io.smallrye:jandex:3.1.2 - https://smallrye.io)
|
||||
* swagger-annotations (io.swagger:swagger-annotations:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
|
||||
* swagger-compat-spec-parser (io.swagger:swagger-compat-spec-parser:1.0.52 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-compat-spec-parser)
|
||||
* swagger-core (io.swagger:swagger-core:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
|
||||
* swagger-models (io.swagger:swagger-models:1.6.2 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
|
||||
* swagger-parser (io.swagger:swagger-parser:1.0.52 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
|
||||
* swagger-annotations (io.swagger.core.v3:swagger-annotations:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
|
||||
* swagger-annotations (io.swagger:swagger-annotations:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
|
||||
* swagger-compat-spec-parser (io.swagger:swagger-compat-spec-parser:1.0.64 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-compat-spec-parser)
|
||||
* swagger-core (io.swagger:swagger-core:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
|
||||
* swagger-models (io.swagger:swagger-models:1.6.9 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
|
||||
* swagger-parser (io.swagger:swagger-parser:1.0.64 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
|
||||
* swagger-annotations (io.swagger.core.v3:swagger-annotations:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations)
|
||||
* swagger-annotations-jakarta (io.swagger.core.v3:swagger-annotations-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-annotations-jakarta)
|
||||
* swagger-core (io.swagger.core.v3:swagger-core:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
|
||||
* swagger-core (io.swagger.core.v3:swagger-core:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
|
||||
* swagger-core-jakarta (io.swagger.core.v3:swagger-core-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-core-jakarta)
|
||||
* swagger-integration-jakarta (io.swagger.core.v3:swagger-integration-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-integration-jakarta)
|
||||
* swagger-jaxrs2-jakarta (io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-jaxrs2-jakarta)
|
||||
* swagger-models (io.swagger.core.v3:swagger-models:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
|
||||
* swagger-models (io.swagger.core.v3:swagger-models:2.2.8 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
|
||||
* swagger-models-jakarta (io.swagger.core.v3:swagger-models-jakarta:2.2.21 - https://github.com/swagger-api/swagger-core/modules/swagger-models-jakarta)
|
||||
* swagger-parser (io.swagger.parser.v3:swagger-parser:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
|
||||
* swagger-parser (io.swagger.parser.v3:swagger-parser-core:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-core)
|
||||
* swagger-parser-v2-converter (io.swagger.parser.v3:swagger-parser-v2-converter:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v2-converter)
|
||||
* swagger-parser-v3 (io.swagger.parser.v3:swagger-parser-v3:2.0.23 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v3)
|
||||
* swagger-parser (io.swagger.parser.v3:swagger-parser:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser)
|
||||
* swagger-parser (io.swagger.parser.v3:swagger-parser-core:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-core)
|
||||
* swagger-parser-v2-converter (io.swagger.parser.v3:swagger-parser-v2-converter:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v2-converter)
|
||||
* swagger-parser-v3 (io.swagger.parser.v3:swagger-parser-v3:2.1.10 - http://nexus.sonatype.org/oss-repository-hosting.html/swagger-parser-project/modules/swagger-parser-v3)
|
||||
* Jakarta Dependency Injection (jakarta.inject:jakarta.inject-api:2.0.1 - https://github.com/eclipse-ee4j/injection-api)
|
||||
* Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:3.0.2 - https://beanvalidation.org)
|
||||
* JSR107 API and SPI (javax.cache:cache-api:1.1.1 - https://github.com/jsr107/jsr107spec)
|
||||
* javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
||||
* Bean Validation API (javax.validation:validation-api:1.1.0.Final - http://beanvalidation.org)
|
||||
* jdbm (jdbm:jdbm:1.0 - no url defined)
|
||||
* Joda-Time (joda-time:joda-time:2.12.5 - https://www.joda.org/joda-time/)
|
||||
* Joda-Time (joda-time:joda-time:2.12.7 - https://www.joda.org/joda-time/)
|
||||
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy)
|
||||
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.14.11 - 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)
|
||||
* json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.36.0 - https://github.com/lukas-krecan/JsonUnit/json-unit-core)
|
||||
* "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/)
|
||||
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.0 - https://urielch.github.io/)
|
||||
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:2.5.2 - https://urielch.github.io/)
|
||||
* JSON Small and Fast Parser (net.minidev:json-smart:2.5.0 - https://urielch.github.io/)
|
||||
* JSON Small and Fast Parser (net.minidev:json-smart:2.5.2 - https://urielch.github.io/)
|
||||
* java-support (net.shibboleth.utilities:java-support:8.4.2 - http://shibboleth.net/java-support/)
|
||||
* OGNL - Object Graph Navigation Library (ognl:ognl:3.3.4 - https://github.com/jkuhnert/ognl/)
|
||||
* Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core)
|
||||
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org)
|
||||
* Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser)
|
||||
* 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)
|
||||
* Apache Ant Core (org.apache.ant:ant:1.10.15 - https://ant.apache.org/)
|
||||
* Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.15 - https://ant.apache.org/)
|
||||
* Apache Commons BCEL (org.apache.bcel:bcel:6.10.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 Collections (org.apache.commons:commons-collections4:4.5.0 - https://commons.apache.org/proper/commons-collections/)
|
||||
* Apache Commons Compress (org.apache.commons:commons-compress:1.27.1 - https://commons.apache.org/proper/commons-compress/)
|
||||
* Apache Commons Configuration (org.apache.commons:commons-configuration2:2.12.0 - https://commons.apache.org/proper/commons-configuration/)
|
||||
* Apache Commons CSV (org.apache.commons:commons-csv:1.14.0 - https://commons.apache.org/proper/commons-csv/)
|
||||
* Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.13.0 - https://commons.apache.org/proper/commons-dbcp/)
|
||||
* Apache Commons Digester (org.apache.commons:commons-digester3:3.2 - http://commons.apache.org/digester/)
|
||||
* Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/)
|
||||
* Apache Commons Exec (org.apache.commons:commons-exec:1.4.0 - https://commons.apache.org/proper/commons-exec/)
|
||||
* Apache Commons Lang (org.apache.commons:commons-lang3:3.14.0 - https://commons.apache.org/proper/commons-lang/)
|
||||
* Apache Commons Lang (org.apache.commons:commons-lang3:3.17.0 - https://commons.apache.org/proper/commons-lang/)
|
||||
* Apache Commons Math (org.apache.commons:commons-math3:3.6.1 - http://commons.apache.org/proper/commons-math/)
|
||||
* Apache Commons 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)
|
||||
* Apache Commons Pool (org.apache.commons:commons-pool2:2.12.1 - https://commons.apache.org/proper/commons-pool/)
|
||||
* Apache Commons Text (org.apache.commons:commons-text:1.13.1 - 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)
|
||||
@@ -207,120 +221,130 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.16 - http://hc.apache.org/httpcomponents-core-ga)
|
||||
* Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.14 - http://hc.apache.org/httpcomponents-client-ga)
|
||||
* Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.1.3 - https://hc.apache.org/httpcomponents-client-5.0.x/5.1.3/httpclient5/)
|
||||
* Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.3.1 - https://hc.apache.org/httpcomponents-client-5.0.x/5.3.1/httpclient5/)
|
||||
* Apache HttpClient (org.apache.httpcomponents.client5:httpclient5:5.4.4 - https://hc.apache.org/httpcomponents-client-5.4.x/5.4.4/httpclient5/)
|
||||
* Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5/)
|
||||
* Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.2.4 - https://hc.apache.org/httpcomponents-core-5.2.x/5.2.4/httpcore5/)
|
||||
* Apache HttpComponents Core HTTP/1.1 (org.apache.httpcomponents.core5:httpcore5:5.3.4 - https://hc.apache.org/httpcomponents-core-5.3.x/5.3.4/httpcore5/)
|
||||
* Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.1.3 - https://hc.apache.org/httpcomponents-core-5.1.x/5.1.3/httpcore5-h2/)
|
||||
* Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.2.4 - https://hc.apache.org/httpcomponents-core-5.2.x/5.2.4/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:4.9.0 - https://jena.apache.org/apache-jena-libs/)
|
||||
* Apache Jena - ARQ (org.apache.jena:jena-arq:4.9.0 - https://jena.apache.org/jena-arq/)
|
||||
* Apache Jena - Base (org.apache.jena:jena-base:4.9.0 - https://jena.apache.org/jena-base/)
|
||||
* Apache Jena - Core (org.apache.jena:jena-core:4.9.0 - https://jena.apache.org/jena-core/)
|
||||
* Apache Jena - DBOE Base (org.apache.jena:jena-dboe-base:4.9.0 - https://jena.apache.org/jena-dboe-base/)
|
||||
* Apache Jena - DBOE Indexes (org.apache.jena:jena-dboe-index:4.9.0 - https://jena.apache.org/jena-dboe-index/)
|
||||
* Apache Jena - DBOE Storage (org.apache.jena:jena-dboe-storage:4.9.0 - https://jena.apache.org/jena-dboe-storage/)
|
||||
* Apache Jena - DBOE Transactional Datastructures (org.apache.jena:jena-dboe-trans-data:4.9.0 - https://jena.apache.org/jena-dboe-trans-data/)
|
||||
* Apache Jena - DBOE Transactions (org.apache.jena:jena-dboe-transaction:4.9.0 - https://jena.apache.org/jena-dboe-transaction/)
|
||||
* Apache Jena - IRI (org.apache.jena:jena-iri:4.9.0 - https://jena.apache.org/jena-iri/)
|
||||
* Apache Jena - RDF Connection (org.apache.jena:jena-rdfconnection:4.9.0 - https://jena.apache.org/jena-rdfconnection/)
|
||||
* Apache Jena - RDF Patch (org.apache.jena:jena-rdfpatch:4.9.0 - https://jena.apache.org/jena-rdfpatch/)
|
||||
* Apache Jena - SHACL (org.apache.jena:jena-shacl:4.9.0 - https://jena.apache.org/jena-shacl/)
|
||||
* Apache Jena - ShEx (org.apache.jena:jena-shex:4.9.0 - https://jena.apache.org/jena-shex/)
|
||||
* Apache Jena - TDB1 (Native Triple Store) (org.apache.jena:jena-tdb:4.9.0 - https://jena.apache.org/jena-tdb/)
|
||||
* Apache Jena - TDB2 (Native Triple Store) (org.apache.jena:jena-tdb2:4.9.0 - https://jena.apache.org/jena-tdb2/)
|
||||
* Apache HttpComponents Core HTTP/2 (org.apache.httpcomponents.core5:httpcore5-h2:5.3.4 - https://hc.apache.org/httpcomponents-core-5.3.x/5.3.4/httpcore5-h2/)
|
||||
* Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.12 - http://james.apache.org/mime4j/apache-mime4j-core)
|
||||
* Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.12 - http://james.apache.org/mime4j/apache-mime4j-dom)
|
||||
* jclouds blobstore core (org.apache.jclouds:jclouds-blobstore:2.7.0 - https://jclouds.apache.org/jclouds-blobstore/)
|
||||
* jclouds Components Core (org.apache.jclouds:jclouds-core:2.7.0 - https://jclouds.apache.org/jclouds-core/)
|
||||
* jclouds filesystem core (org.apache.jclouds.api:filesystem:2.7.0 - https://jclouds.apache.org/filesystem/)
|
||||
* jclouds s3 api (org.apache.jclouds.api:s3:2.7.0 - https://jclouds.apache.org/s3/)
|
||||
* jclouds sts api (org.apache.jclouds.api:sts:2.7.0 - https://jclouds.apache.org/sts/)
|
||||
* jclouds Amazon Simple Storage Service (S3) provider (org.apache.jclouds.provider:aws-s3:2.7.0 - https://jclouds.apache.org/aws-s3/)
|
||||
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:4.10.0 - https://jena.apache.org/apache-jena-libs/)
|
||||
* Apache Jena - ARQ (org.apache.jena:jena-arq:4.10.0 - https://jena.apache.org/jena-arq/)
|
||||
* Apache Jena - Base (org.apache.jena:jena-base:4.10.0 - https://jena.apache.org/jena-base/)
|
||||
* Apache Jena - Core (org.apache.jena:jena-core:4.10.0 - https://jena.apache.org/jena-core/)
|
||||
* Apache Jena - DBOE Base (org.apache.jena:jena-dboe-base:4.10.0 - https://jena.apache.org/jena-dboe-base/)
|
||||
* Apache Jena - DBOE Indexes (org.apache.jena:jena-dboe-index:4.10.0 - https://jena.apache.org/jena-dboe-index/)
|
||||
* Apache Jena - DBOE Storage (org.apache.jena:jena-dboe-storage:4.10.0 - https://jena.apache.org/jena-dboe-storage/)
|
||||
* Apache Jena - DBOE Transactional Datastructures (org.apache.jena:jena-dboe-trans-data:4.10.0 - https://jena.apache.org/jena-dboe-trans-data/)
|
||||
* Apache Jena - DBOE Transactions (org.apache.jena:jena-dboe-transaction:4.10.0 - https://jena.apache.org/jena-dboe-transaction/)
|
||||
* Apache Jena - IRI (org.apache.jena:jena-iri:4.10.0 - https://jena.apache.org/jena-iri/)
|
||||
* Apache Jena - RDF Connection (org.apache.jena:jena-rdfconnection:4.10.0 - https://jena.apache.org/jena-rdfconnection/)
|
||||
* Apache Jena - RDF Patch (org.apache.jena:jena-rdfpatch:4.10.0 - https://jena.apache.org/jena-rdfpatch/)
|
||||
* Apache Jena - SHACL (org.apache.jena:jena-shacl:4.10.0 - https://jena.apache.org/jena-shacl/)
|
||||
* Apache Jena - ShEx (org.apache.jena:jena-shex:4.10.0 - https://jena.apache.org/jena-shex/)
|
||||
* Apache Jena - TDB1 (Native Triple Store) (org.apache.jena:jena-tdb:4.10.0 - https://jena.apache.org/jena-tdb/)
|
||||
* Apache Jena - TDB2 (Native Triple Store) (org.apache.jena:jena-tdb2:4.10.0 - https://jena.apache.org/jena-tdb2/)
|
||||
* Kerby-kerb core (org.apache.kerby:kerb-core:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-core)
|
||||
* Kerby-kerb 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.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 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-1.2-api/)
|
||||
* Apache Log4j API (org.apache.logging.log4j:log4j-api:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-api/)
|
||||
* Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-core/)
|
||||
* Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-jul/)
|
||||
* Apache Log4j Layout for JSON template (org.apache.logging.log4j:log4j-layout-template-json:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-layout-template-json/)
|
||||
* Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j-impl/)
|
||||
* Apache Log4j SLF4J 2.0 Binding (org.apache.logging.log4j:log4j-slf4j2-impl:2.21.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j2-impl/)
|
||||
* Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.23.1 - https://logging.apache.org/log4j/2.x/log4j/log4j-web/)
|
||||
* 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/)
|
||||
* Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/)
|
||||
* SLF4J 2 Provider for Log4j API (org.apache.logging.log4j:log4j-slf4j2-impl:2.24.3 - https://logging.apache.org/log4j/2.x/log4j/log4j-slf4j2-impl/)
|
||||
* Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.17.2 - https://logging.apache.org/log4j/2.x/log4j-web/)
|
||||
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common)
|
||||
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
|
||||
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
|
||||
* Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori)
|
||||
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
|
||||
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
|
||||
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
|
||||
* Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs)
|
||||
* Lucene Classification (org.apache.lucene:lucene-classification:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-classification)
|
||||
* Lucene codecs (org.apache.lucene:lucene-codecs:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-codecs)
|
||||
* Lucene Core (org.apache.lucene:lucene-core:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-core)
|
||||
* Lucene Expressions (org.apache.lucene:lucene-expressions:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-expressions)
|
||||
* Lucene Grouping (org.apache.lucene:lucene-grouping:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-grouping)
|
||||
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-highlighter)
|
||||
* Lucene Join (org.apache.lucene:lucene-join:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-join)
|
||||
* Lucene Memory (org.apache.lucene:lucene-memory:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-memory)
|
||||
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-misc)
|
||||
* Lucene Queries (org.apache.lucene:lucene-queries:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-queries)
|
||||
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-queryparser)
|
||||
* Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-sandbox)
|
||||
* Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras)
|
||||
* Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-spatial3d)
|
||||
* Lucene Suggest (org.apache.lucene:lucene-suggest:8.11.4 - https://lucene.apache.org/lucene-parent/lucene-suggest)
|
||||
* Apache FontBox (org.apache.pdfbox:fontbox:2.0.34 - 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.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 PDFBox (org.apache.pdfbox:pdfbox:2.0.34 - https://www.apache.org/pdfbox-parent/pdfbox/)
|
||||
* Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.34 - https://www.apache.org/pdfbox-parent/pdfbox-tools/)
|
||||
* Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.34 - https://www.apache.org/pdfbox-parent/xmpbox/)
|
||||
* Apache POI - Common (org.apache.poi:poi:5.4.1 - https://poi.apache.org/)
|
||||
* Apache POI - API based on OPC and OOXML schemas (org.apache.poi:poi-ooxml:5.4.1 - https://poi.apache.org/)
|
||||
* Apache POI (org.apache.poi:poi-ooxml-lite:5.4.1 - https://poi.apache.org/)
|
||||
* Apache POI (org.apache.poi:poi-scratchpad:5.4.1 - https://poi.apache.org/)
|
||||
* Apache XML Security for Java (org.apache.santuario:xmlsec:2.3.4 - https://santuario.apache.org/)
|
||||
* Apache Solr Core (org.apache.solr:solr-core:8.11.4 - https://lucene.apache.org/solr-parent/solr-core)
|
||||
* Apache Solr Solrj (org.apache.solr:solr-solrj:8.11.4 - https://lucene.apache.org/solr-parent/solr-solrj)
|
||||
* Apache Standard Taglib Implementation (org.apache.taglibs:taglibs-standard-impl:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-impl)
|
||||
* Apache Standard Taglib Specification API (org.apache.taglibs:taglibs-standard-spec:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-spec)
|
||||
* Apache Thrift (org.apache.thrift:libthrift:0.18.1 - http://thrift.apache.org)
|
||||
* Apache 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:10.1.24 - https://tomcat.apache.org/)
|
||||
* tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:10.1.24 - https://tomcat.apache.org/)
|
||||
* tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:10.1.24 - 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/)
|
||||
* Apache Thrift (org.apache.thrift:libthrift:0.19.0 - http://thrift.apache.org)
|
||||
* Apache Tika core (org.apache.tika:tika-core:2.9.4 - https://tika.apache.org/)
|
||||
* Apache Tika Apple parser module (org.apache.tika:tika-parser-apple-module:2.9.4 - https://tika.apache.org/tika-parser-apple-module/)
|
||||
* Apache Tika audiovideo parser module (org.apache.tika:tika-parser-audiovideo-module:2.9.4 - https://tika.apache.org/tika-parser-audiovideo-module/)
|
||||
* Apache Tika cad parser module (org.apache.tika:tika-parser-cad-module:2.9.4 - https://tika.apache.org/tika-parser-cad-module/)
|
||||
* Apache Tika code parser module (org.apache.tika:tika-parser-code-module:2.9.4 - https://tika.apache.org/tika-parser-code-module/)
|
||||
* Apache Tika crypto parser module (org.apache.tika:tika-parser-crypto-module:2.9.4 - https://tika.apache.org/tika-parser-crypto-module/)
|
||||
* Apache Tika digest commons (org.apache.tika:tika-parser-digest-commons:2.9.4 - https://tika.apache.org/tika-parser-digest-commons/)
|
||||
* Apache Tika font parser module (org.apache.tika:tika-parser-font-module:2.9.4 - https://tika.apache.org/tika-parser-font-module/)
|
||||
* Apache Tika html parser module (org.apache.tika:tika-parser-html-module:2.9.4 - https://tika.apache.org/tika-parser-html-module/)
|
||||
* Apache Tika image parser module (org.apache.tika:tika-parser-image-module:2.9.4 - https://tika.apache.org/tika-parser-image-module/)
|
||||
* Apache Tika mail commons (org.apache.tika:tika-parser-mail-commons:2.9.4 - https://tika.apache.org/tika-parser-mail-commons/)
|
||||
* Apache Tika mail parser module (org.apache.tika:tika-parser-mail-module:2.9.4 - https://tika.apache.org/tika-parser-mail-module/)
|
||||
* Apache Tika Microsoft parser module (org.apache.tika:tika-parser-microsoft-module:2.9.4 - https://tika.apache.org/tika-parser-microsoft-module/)
|
||||
* Apache Tika miscellaneous office format parser module (org.apache.tika:tika-parser-miscoffice-module:2.9.4 - https://tika.apache.org/tika-parser-miscoffice-module/)
|
||||
* Apache Tika news parser module (org.apache.tika:tika-parser-news-module:2.9.4 - https://tika.apache.org/tika-parser-news-module/)
|
||||
* Apache Tika OCR parser module (org.apache.tika:tika-parser-ocr-module:2.9.4 - https://tika.apache.org/tika-parser-ocr-module/)
|
||||
* Apache Tika PDF parser module (org.apache.tika:tika-parser-pdf-module:2.9.4 - https://tika.apache.org/tika-parser-pdf-module/)
|
||||
* Apache Tika package parser module (org.apache.tika:tika-parser-pkg-module:2.9.4 - https://tika.apache.org/tika-parser-pkg-module/)
|
||||
* Apache Tika text parser module (org.apache.tika:tika-parser-text-module:2.9.4 - https://tika.apache.org/tika-parser-text-module/)
|
||||
* Apache Tika WARC parser module (org.apache.tika:tika-parser-webarchive-module:2.9.4 - https://tika.apache.org/tika-parser-webarchive-module/)
|
||||
* Apache Tika XML parser module (org.apache.tika:tika-parser-xml-module:2.9.4 - https://tika.apache.org/tika-parser-xml-module/)
|
||||
* Apache Tika XMP commons (org.apache.tika:tika-parser-xmp-commons:2.9.4 - https://tika.apache.org/tika-parser-xmp-commons/)
|
||||
* Apache Tika ZIP commons (org.apache.tika:tika-parser-zip-commons:2.9.4 - https://tika.apache.org/tika-parser-zip-commons/)
|
||||
* Apache Tika standard parser package (org.apache.tika:tika-parsers-standard-package:2.9.4 - https://tika.apache.org/tika-parsers/tika-parsers-standard/tika-parsers-standard-package/)
|
||||
* tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:10.1.40 - https://tomcat.apache.org/)
|
||||
* tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:10.1.40 - https://tomcat.apache.org/)
|
||||
* tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:10.1.40 - https://tomcat.apache.org/)
|
||||
* Apache Velocity - Engine (org.apache.velocity:velocity-engine-core:2.4.1 - http://velocity.apache.org/engine/devel/velocity-engine-core/)
|
||||
* Apache Velocity - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.3 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/)
|
||||
* Apache Velocity Tools - Generic tools (org.apache.velocity.tools:velocity-tools-generic:3.1 - https://velocity.apache.org/tools/devel/velocity-tools-generic/)
|
||||
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/)
|
||||
* Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/)
|
||||
* XmlBeans (org.apache.xmlbeans:xmlbeans:5.2.0 - https://xmlbeans.apache.org/)
|
||||
* XmlBeans (org.apache.xmlbeans:xmlbeans:5.3.0 - https://xmlbeans.apache.org/)
|
||||
* Apache ZooKeeper - Server (org.apache.zookeeper:zookeeper:3.6.2 - http://zookeeper.apache.org/zookeeper)
|
||||
* Apache ZooKeeper - Jute (org.apache.zookeeper:zookeeper-jute:3.6.2 - http://zookeeper.apache.org/zookeeper-jute)
|
||||
* org.apiguardian:apiguardian-api (org.apiguardian:apiguardian-api:1.1.2 - https://github.com/apiguardian-team/apiguardian)
|
||||
* AssertJ Core (org.assertj:assertj-core:3.24.2 - https://assertj.github.io/doc/#assertj-core)
|
||||
* AssertJ Core (org.assertj:assertj-core:3.26.3 - https://assertj.github.io/doc/#assertj-core)
|
||||
* Evo Inflector (org.atteo:evo-inflector:1.3 - http://atteo.org/static/evo-inflector)
|
||||
* Awaitility (org.awaitility:awaitility:4.2.1 - http://awaitility.org)
|
||||
* attoparser (org.attoparser:attoparser:2.0.7.RELEASE - https://www.attoparser.org)
|
||||
* Awaitility (org.awaitility:awaitility:4.2.2 - http://awaitility.org)
|
||||
* jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/)
|
||||
* TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/)
|
||||
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.6 - http://woodstox.codehaus.org)
|
||||
* Cryptacular Library (org.cryptacular:cryptacular:1.2.5 - http://www.cryptacular.org)
|
||||
* jems (org.dmfs:jems:1.18 - https://github.com/dmfs/jems)
|
||||
* rfc3986-uri (org.dmfs:rfc3986-uri:0.8.1 - https://github.com/dmfs/uri-toolkit)
|
||||
* Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty)
|
||||
@@ -335,124 +359,134 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client)
|
||||
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty)
|
||||
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
|
||||
* Jetty :: 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 :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.57.v20241219 - https://jetty.org/jetty-deploy/)
|
||||
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.57.v20241219 - https://jetty.org/jetty-http/)
|
||||
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.57.v20241219 - https://jetty.org/jetty-io/)
|
||||
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx)
|
||||
* Jetty :: 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.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 :: Security (org.eclipse.jetty:jetty-security:9.4.57.v20241219 - https://jetty.org/jetty-security/)
|
||||
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.57.v20241219 - https://jetty.org/jetty-server/)
|
||||
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.57.v20241219 - https://jetty.org/jetty-servlet/)
|
||||
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty)
|
||||
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets)
|
||||
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util)
|
||||
* Jetty :: Utilities :: 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 :: Utilities (org.eclipse.jetty:jetty-util:9.4.57.v20241219 - https://jetty.org/jetty-util/)
|
||||
* Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.57.v20241219 - https://jetty.org/jetty-util-ajax/)
|
||||
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.57.v20241219 - https://jetty.org/jetty-webapp/)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.57.v20241219 - https://jetty.org/jetty-xml/)
|
||||
* Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api)
|
||||
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client)
|
||||
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common)
|
||||
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.57.v20241219 - https://jetty.org/http2-parent/http2-common/)
|
||||
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack)
|
||||
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
|
||||
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server)
|
||||
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server)
|
||||
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
|
||||
* Ehcache (org.ehcache:ehcache:3.10.8 - http://ehcache.org)
|
||||
* flyway-core (org.flywaydb:flyway-core:10.10.0 - https://flywaydb.org/flyway-core)
|
||||
* flyway-database-postgresql (org.flywaydb:flyway-database-postgresql:10.10.0 - https://flywaydb.org/flyway-database-postgresql)
|
||||
* flyway-core (org.flywaydb:flyway-core:10.22.0 - https://flywaydb.org/flyway-core)
|
||||
* flyway-database-postgresql (org.flywaydb:flyway-database-postgresql:10.22.0 - https://flywaydb.org/flyway-database-postgresql)
|
||||
* Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.8 - https://github.com/Gagravarr/VorbisJava)
|
||||
* Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.8 - https://github.com/Gagravarr/VorbisJava)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:8.0.1.Final - http://hibernate.org/validator/hibernate-validator)
|
||||
* Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:8.0.1.Final - http://hibernate.org/validator/hibernate-validator-cdi)
|
||||
* org.immutables.value-annotations (org.immutables:value-annotations:2.9.2 - http://immutables.org/value-annotations)
|
||||
* 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.29.2-GA - http://www.javassist.org/)
|
||||
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.4.3.Final - http://www.jboss.org)
|
||||
* Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
|
||||
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.6.1.Final - http://www.jboss.org)
|
||||
* JDOM (org.jdom:jdom2:2.0.6.1 - http://www.jdom.org)
|
||||
* jtwig-core (org.jtwig:jtwig-core:5.87.0.RELEASE - http://jtwig.org)
|
||||
* jtwig-reflection (org.jtwig:jtwig-reflection:5.87.0.RELEASE - http://jtwig.org)
|
||||
* jtwig-spring (org.jtwig:jtwig-spring:5.87.0.RELEASE - http://jtwig.org)
|
||||
* jtwig-spring-boot-starter (org.jtwig:jtwig-spring-boot-starter:5.87.0.RELEASE - http://jtwig.org)
|
||||
* jtwig-web (org.jtwig:jtwig-web:5.87.0.RELEASE - http://jtwig.org)
|
||||
* IntelliJ IDEA Annotations (org.jetbrains:annotations:13.0 - http://www.jetbrains.org)
|
||||
* Kotlin Stdlib (org.jetbrains.kotlin:kotlin-stdlib:1.8.21 - https://kotlinlang.org/)
|
||||
* Kotlin Stdlib Common (org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21 - https://kotlinlang.org/)
|
||||
* Kotlin Stdlib Jdk7 (org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.21 - https://kotlinlang.org/)
|
||||
* Kotlin Stdlib Jdk8 (org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 - https://kotlinlang.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)
|
||||
* MockServer JUnit 4 Integration (org.mock-server:mockserver-junit-rule:5.11.2 - http://www.mock-server.com)
|
||||
* MockServer & Proxy Netty (org.mock-server:mockserver-netty:5.11.2 - http://www.mock-server.com)
|
||||
* 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)
|
||||
* Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api)
|
||||
* jwarc (org.netpreserve:jwarc:0.29.0 - https://github.com/iipc/jwarc)
|
||||
* MockServer Java Client (org.mock-server:mockserver-client-java:5.15.0 - https://www.mock-server.com)
|
||||
* MockServer Core (org.mock-server:mockserver-core:5.15.0 - https://www.mock-server.com)
|
||||
* MockServer JUnit 4 Integration (org.mock-server:mockserver-junit-rule:5.15.0 - https://www.mock-server.com)
|
||||
* MockServer & Proxy Netty (org.mock-server:mockserver-netty:5.15.0 - https://www.mock-server.com)
|
||||
* jwarc (org.netpreserve:jwarc:0.31.1 - 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)
|
||||
* org.roaringbitmap:RoaringBitmap (org.roaringbitmap:RoaringBitmap:0.9.45 - https://github.com/RoaringBitmap/RoaringBitmap)
|
||||
* org.roaringbitmap:shims (org.roaringbitmap:shims:0.9.45 - https://github.com/RoaringBitmap/RoaringBitmap)
|
||||
* OpenSAML :: Core (org.opensaml:opensaml-core:4.3.2 - http://shibboleth.net/opensaml-core/)
|
||||
* OpenSAML :: Messaging API (org.opensaml:opensaml-messaging-api:4.3.2 - http://shibboleth.net/opensaml-messaging-api/)
|
||||
* OpenSAML :: Profile API (org.opensaml:opensaml-profile-api:4.3.2 - http://shibboleth.net/opensaml-profile-api/)
|
||||
* OpenSAML :: SAML Provider API (org.opensaml:opensaml-saml-api:4.3.2 - http://shibboleth.net/opensaml-saml-api/)
|
||||
* OpenSAML :: SAML Provider Implementations (org.opensaml:opensaml-saml-impl:4.3.2 - http://shibboleth.net/opensaml-saml-impl/)
|
||||
* OpenSAML :: Security API (org.opensaml:opensaml-security-api:4.3.2 - http://shibboleth.net/opensaml-security-api/)
|
||||
* OpenSAML :: Security Implementation (org.opensaml:opensaml-security-impl:4.3.2 - http://shibboleth.net/opensaml-security-impl/)
|
||||
* OpenSAML :: SOAP Provider API (org.opensaml:opensaml-soap-api:4.3.2 - http://shibboleth.net/opensaml-soap-api/)
|
||||
* OpenSAML :: SOAP Provider Implementations (org.opensaml:opensaml-soap-impl:4.3.2 - http://shibboleth.net/opensaml-soap-impl/)
|
||||
* OpenSAML :: Storage API (org.opensaml:opensaml-storage-api:4.3.2 - http://shibboleth.net/opensaml-storage-api/)
|
||||
* OpenSAML :: XML Security API (org.opensaml:opensaml-xmlsec-api:4.3.2 - http://shibboleth.net/opensaml-xmlsec-api/)
|
||||
* OpenSAML :: XML Security Implementation (org.opensaml:opensaml-xmlsec-impl:4.3.2 - http://shibboleth.net/opensaml-xmlsec-impl/)
|
||||
* org.roaringbitmap:RoaringBitmap (org.roaringbitmap:RoaringBitmap:1.0.0 - https://github.com/RoaringBitmap/RoaringBitmap)
|
||||
* RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/)
|
||||
* Scala Library (org.scala-lang:scala-library:2.13.11 - https://www.scala-lang.org/)
|
||||
* Scala Library (org.scala-lang:scala-library:2.13.2 - https://www.scala-lang.org/)
|
||||
* Scala Compiler (org.scala-lang:scala-reflect:2.13.0 - https://www.scala-lang.org/)
|
||||
* scala-collection-compat (org.scala-lang.modules:scala-collection-compat_2.13:2.1.6 - http://www.scala-lang.org/)
|
||||
* scala-java8-compat (org.scala-lang.modules:scala-java8-compat_2.13:0.9.0 - http://www.scala-lang.org/)
|
||||
* scala-parser-combinators (org.scala-lang.modules:scala-parser-combinators_2.13:1.1.2 - http://www.scala-lang.org/)
|
||||
* scala-xml (org.scala-lang.modules:scala-xml_2.13:1.3.0 - http://www.scala-lang.org/)
|
||||
* JSONassert (org.skyscreamer:jsonassert:1.5.1 - https://github.com/skyscreamer/JSONassert)
|
||||
* JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:2.0.11 - http://www.slf4j.org)
|
||||
* Spring AOP (org.springframework:spring-aop:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Beans (org.springframework:spring-beans:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Context (org.springframework:spring-context:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Context Support (org.springframework:spring-context-support:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Core (org.springframework:spring-core:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Expression Language (SpEL) (org.springframework:spring-expression:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Commons Logging Bridge (org.springframework:spring-jcl:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring JDBC (org.springframework:spring-jdbc:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Object/Relational Mapping (org.springframework:spring-orm:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring TestContext Framework (org.springframework:spring-test:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Transaction (org.springframework:spring-tx:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Web (org.springframework:spring-web:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Web MVC (org.springframework:spring-webmvc:6.1.8 - https://github.com/spring-projects/spring-framework)
|
||||
* spring-boot (org.springframework.boot:spring-boot:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-actuator (org.springframework.boot:spring-boot-actuator:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:3.2.6 - 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:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-test (org.springframework.boot:spring-boot-test:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:3.2.6 - https://spring.io/projects/spring-boot)
|
||||
* Spring Data Core (org.springframework.data:spring-data-commons:3.2.6 - https://spring.io/projects/spring-data)
|
||||
* Spring Data REST - Core (org.springframework.data:spring-data-rest-core:4.2.6 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core)
|
||||
* Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:4.2.6 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
|
||||
* Spring HATEOAS (org.springframework.hateoas:spring-hateoas:2.2.2 - https://github.com/spring-projects/spring-hateoas)
|
||||
* JSONassert (org.skyscreamer:jsonassert:1.5.3 - https://github.com/skyscreamer/JSONassert)
|
||||
* JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:2.0.17 - http://www.slf4j.org)
|
||||
* Spring AOP (org.springframework:spring-aop:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Beans (org.springframework:spring-beans:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Context (org.springframework:spring-context:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Context Support (org.springframework:spring-context-support:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Core (org.springframework:spring-core:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Expression Language (SpEL) (org.springframework:spring-expression:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Commons Logging Bridge (org.springframework:spring-jcl:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring JDBC (org.springframework:spring-jdbc:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Object/Relational Mapping (org.springframework:spring-orm:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring TestContext Framework (org.springframework:spring-test:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Transaction (org.springframework:spring-tx:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Web (org.springframework:spring-web:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* Spring Web MVC (org.springframework:spring-webmvc:6.2.7 - https://github.com/spring-projects/spring-framework)
|
||||
* spring-boot (org.springframework.boot:spring-boot:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-actuator (org.springframework.boot:spring-boot-actuator:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-actuator-autoconfigure (org.springframework.boot:spring-boot-actuator-autoconfigure:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-autoconfigure (org.springframework.boot:spring-boot-autoconfigure:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter (org.springframework.boot:spring-boot-starter:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-actuator (org.springframework.boot:spring-boot-starter-actuator:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-aop (org.springframework.boot:spring-boot-starter-aop:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-cache (org.springframework.boot:spring-boot-starter-cache:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-data-rest (org.springframework.boot:spring-boot-starter-data-rest:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-json (org.springframework.boot:spring-boot-starter-json:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-log4j2 (org.springframework.boot:spring-boot-starter-log4j2:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-security (org.springframework.boot:spring-boot-starter-security:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-test (org.springframework.boot:spring-boot-starter-test:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-thymeleaf (org.springframework.boot:spring-boot-starter-thymeleaf:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-tomcat (org.springframework.boot:spring-boot-starter-tomcat:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-starter-web (org.springframework.boot:spring-boot-starter-web:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-test (org.springframework.boot:spring-boot-test:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* spring-boot-test-autoconfigure (org.springframework.boot:spring-boot-test-autoconfigure:3.4.5 - https://spring.io/projects/spring-boot)
|
||||
* Spring Data Core (org.springframework.data:spring-data-commons:3.4.5 - https://spring.io/projects/spring-data)
|
||||
* Spring Data REST - Core (org.springframework.data:spring-data-rest-core:4.4.5 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core)
|
||||
* Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:4.4.5 - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
|
||||
* Spring HATEOAS (org.springframework.hateoas:spring-hateoas:2.4.1 - https://github.com/spring-projects/spring-hateoas)
|
||||
* Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:3.0.0 - https://github.com/spring-projects/spring-plugin/spring-plugin-core)
|
||||
* spring-security-config (org.springframework.security:spring-security-config:6.2.4 - https://spring.io/projects/spring-security)
|
||||
* spring-security-core (org.springframework.security:spring-security-core:6.2.4 - https://spring.io/projects/spring-security)
|
||||
* spring-security-crypto (org.springframework.security:spring-security-crypto:6.2.4 - https://spring.io/projects/spring-security)
|
||||
* spring-security-test (org.springframework.security:spring-security-test:6.2.4 - https://spring.io/projects/spring-security)
|
||||
* spring-security-web (org.springframework.security:spring-security-web:6.2.4 - https://spring.io/projects/spring-security)
|
||||
* spring-security-config (org.springframework.security:spring-security-config:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* spring-security-core (org.springframework.security:spring-security-core:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* spring-security-crypto (org.springframework.security:spring-security-crypto:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* spring-security-saml2-service-provider (org.springframework.security:spring-security-saml2-service-provider:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* spring-security-test (org.springframework.security:spring-security-test:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* spring-security-web (org.springframework.security:spring-security-web:6.4.5 - https://spring.io/projects/spring-security)
|
||||
* thymeleaf (org.thymeleaf:thymeleaf:3.1.3.RELEASE - http://www.thymeleaf.org/thymeleaf-lib/thymeleaf)
|
||||
* thymeleaf-spring6 (org.thymeleaf:thymeleaf-spring6:3.1.3.RELEASE - http://www.thymeleaf.org/thymeleaf-lib/thymeleaf-spring6)
|
||||
* unbescape (org.unbescape:unbescape:1.1.6.RELEASE - http://www.unbescape.org)
|
||||
* snappy-java (org.xerial.snappy:snappy-java:1.1.10.1 - https://github.com/xerial/snappy-java)
|
||||
* xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/)
|
||||
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.10.0 - https://www.xmlunit.org/)
|
||||
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.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:2.2 - https://bitbucket.org/snakeyaml/snakeyaml)
|
||||
* software.amazon.ion:ion-java (software.amazon.ion:ion-java:1.0.2 - https://github.com/amznlabs/ion-java/)
|
||||
* org.xmlunit:xmlunit-placeholders (org.xmlunit:xmlunit-placeholders:2.9.1 - https://www.xmlunit.org/xmlunit-placeholders/)
|
||||
* SnakeYAML (org.yaml:snakeyaml:2.3 - https://bitbucket.org/snakeyaml/snakeyaml)
|
||||
* Xerces2-j (xerces:xercesImpl:2.12.2 - https://xerces.apache.org/xerces2-j/)
|
||||
|
||||
BSD License:
|
||||
@@ -463,27 +497,31 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.13.4 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
|
||||
* curvesapi (com.github.virtuald:curvesapi:1.08 - https://github.com/virtuald/curvesapi)
|
||||
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.15.0 - https://developers.google.com/protocol-buffers/protobuf-java/)
|
||||
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.23.3 - https://developers.google.com/protocol-buffers/protobuf-java/)
|
||||
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.24.3 - https://developers.google.com/protocol-buffers/protobuf-java/)
|
||||
* JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/)
|
||||
* dnsjava (dnsjava:dnsjava:2.1.9 - http://www.dnsjava.org)
|
||||
* jmustache (com.samskivert:jmustache:1.15 - http://github.com/samskivert/jmustache)
|
||||
* dnsjava (dnsjava:dnsjava:3.6.3 - https://github.com/dnsjava/dnsjava)
|
||||
* jaxen (jaxen:jaxen:2.0.0 - http://www.cafeconleche.org/jaxen/jaxen)
|
||||
* ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.13.1 - https://www.antlr.org/antlr4-runtime/)
|
||||
* ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.13.2 - https://www.antlr.org/antlr4-runtime/)
|
||||
* commons-compiler (org.codehaus.janino:commons-compiler:3.1.8 - http://janino-compiler.github.io/commons-compiler/)
|
||||
* 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.8 - https://github.com/exparity/hamcrest-date)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* Hamcrest (org.hamcrest:hamcrest:2.2 - http://hamcrest.org/JavaHamcrest/)
|
||||
* Hamcrest Core (org.hamcrest:hamcrest-core:2.2 - http://hamcrest.org/JavaHamcrest/)
|
||||
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/)
|
||||
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.2.2 - http://hdrhistogram.github.io/HdrHistogram/)
|
||||
* JBibTeX (org.jbibtex:jbibtex:1.0.20 - http://www.jbibtex.org)
|
||||
* asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/)
|
||||
* asm-analysis (org.ow2.asm:asm-analysis:8.0.1 - http://asm.ow2.io/)
|
||||
* asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/)
|
||||
* asm-tree (org.ow2.asm:asm-tree:8.0.1 - http://asm.ow2.io/)
|
||||
* asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
|
||||
* PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.3 - https://jdbc.postgresql.org)
|
||||
* PostgreSQL JDBC Driver (org.postgresql:postgresql:42.7.5 - https://jdbc.postgresql.org)
|
||||
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections)
|
||||
* JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio)
|
||||
* XZ for Java (org.tukaani:xz:1.10 - https://tukaani.org/xz/java.html)
|
||||
* XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/)
|
||||
|
||||
CC0:
|
||||
@@ -497,7 +535,7 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:2.3.1 - http://jaxb.java.net/jaxb-bundles/jaxb-impl)
|
||||
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca)
|
||||
* Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api)
|
||||
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.0.0 - https://projects.eclipse.org/projects/ee4j.servlet)
|
||||
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.1.0 - https://projects.eclipse.org/projects/ee4j.servlet)
|
||||
* jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta)
|
||||
* JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/)
|
||||
* javax.annotation API (javax.annotation:javax.annotation-api:1.3 - http://jcp.org/en/jsr/detail?id=250)
|
||||
@@ -506,13 +544,13 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* jaxb-api (javax.xml.bind:jaxb-api:2.3.1 - https://github.com/javaee/jaxb-spec/jaxb-api)
|
||||
* JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight)
|
||||
* Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail)
|
||||
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
|
||||
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
|
||||
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
|
||||
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
|
||||
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
|
||||
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
|
||||
* OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator)
|
||||
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
|
||||
Cordra (Version 2) License Agreement:
|
||||
@@ -536,8 +574,8 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* JAXB Core (org.glassfish.jaxb:jaxb-core:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
|
||||
* JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
|
||||
* TXW2 Runtime (org.glassfish.jaxb:txw2:4.0.5 - https://eclipse-ee4j.github.io/jaxb-ri/)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* MIME streaming extension (org.jvnet.mimepull:mimepull:1.9.15 - https://github.com/eclipse-ee4j/metro-mimepull)
|
||||
* org.locationtech.jts:jts-core (org.locationtech.jts:jts-core:1.19.0 - https://www.locationtech.org/projects/technology.jts/jts-modules/jts-core)
|
||||
@@ -546,16 +584,15 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
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.2.224 - https://h2database.com)
|
||||
* H2 Database Engine (com.h2database:h2:2.3.232 - https://h2database.com)
|
||||
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:2.1.1 - https://projects.eclipse.org/projects/ee4j.ca)
|
||||
* Jakarta Expression Language API (jakarta.el:jakarta.el-api:5.0.1 - https://projects.eclipse.org/projects/ee4j.el)
|
||||
* Jakarta Mail API (jakarta.mail:jakarta.mail-api:2.1.3 - https://projects.eclipse.org/projects/ee4j/jakarta.mail-api)
|
||||
* Jakarta Persistence API (jakarta.persistence:jakarta.persistence-api:3.1.0 - https://github.com/eclipse-ee4j/jpa-api)
|
||||
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.0.0 - https://projects.eclipse.org/projects/ee4j.servlet)
|
||||
* Jakarta Servlet (jakarta.servlet:jakarta.servlet-api:6.1.0 - https://projects.eclipse.org/projects/ee4j.servlet)
|
||||
* jakarta.transaction API (jakarta.transaction:jakarta.transaction-api:2.0.1 - https://projects.eclipse.org/projects/ee4j.jta)
|
||||
* Jakarta RESTful WS API (jakarta.ws.rs:jakarta.ws.rs-api:3.1.0 - https://github.com/eclipse-ee4j/jaxrs-api)
|
||||
* JUnit (junit:junit:4.13.2 - http://junit.org)
|
||||
* AspectJ Weaver (org.aspectj:aspectjweaver:1.9.22 - https://www.eclipse.org/aspectj/)
|
||||
* AspectJ Weaver (org.aspectj:aspectjweaver:1.9.24 - https://www.eclipse.org/aspectj/)
|
||||
* Angus Mail default provider (org.eclipse.angus:jakarta.mail:2.0.3 - http://eclipse-ee4j.github.io/angus-mail/jakarta.mail)
|
||||
* 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/)
|
||||
@@ -569,65 +606,72 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-client)
|
||||
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.15.v20190215 - http://www.eclipse.org/jetty)
|
||||
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-continuation)
|
||||
* Jetty :: 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 :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.57.v20241219 - https://jetty.org/jetty-deploy/)
|
||||
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.57.v20241219 - https://jetty.org/jetty-http/)
|
||||
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.57.v20241219 - https://jetty.org/jetty-io/)
|
||||
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-jmx)
|
||||
* Jetty :: 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.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 :: Security (org.eclipse.jetty:jetty-security:9.4.57.v20241219 - https://jetty.org/jetty-security/)
|
||||
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.57.v20241219 - https://jetty.org/jetty-server/)
|
||||
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.57.v20241219 - https://jetty.org/jetty-servlet/)
|
||||
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.15.v20190215 - http://www.eclipse.org/jetty)
|
||||
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-servlets)
|
||||
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-util)
|
||||
* Jetty :: Utilities :: 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 :: Utilities (org.eclipse.jetty:jetty-util:9.4.57.v20241219 - https://jetty.org/jetty-util/)
|
||||
* Jetty :: Utilities :: Ajax(JSON) (org.eclipse.jetty:jetty-util-ajax:9.4.57.v20241219 - https://jetty.org/jetty-util-ajax/)
|
||||
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.57.v20241219 - https://jetty.org/jetty-webapp/)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.53.v20231009 - https://eclipse.org/jetty/jetty-xml)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.54.v20240208 - https://eclipse.org/jetty/jetty-xml)
|
||||
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.57.v20241219 - https://jetty.org/jetty-xml/)
|
||||
* Jetty :: ALPN :: API (org.eclipse.jetty.alpn:alpn-api:1.1.3.v20160715 - http://www.eclipse.org/jetty/alpn-api)
|
||||
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-client)
|
||||
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.54.v20240208 - https://eclipse.org/jetty/http2-parent/http2-common)
|
||||
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.57.v20241219 - https://jetty.org/http2-parent/http2-common/)
|
||||
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-hpack)
|
||||
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
|
||||
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.15.v20190215 - https://eclipse.org/jetty/http2-parent/http2-server)
|
||||
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.53.v20231009 - https://eclipse.org/jetty/http2-parent/http2-server)
|
||||
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
|
||||
* JSON-P Default Provider (org.glassfish:jakarta.json:2.0.1 - https://github.com/eclipse-ee4j/jsonp)
|
||||
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
|
||||
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
|
||||
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
|
||||
* HK2 API module (org.glassfish.hk2:hk2-api:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
|
||||
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
|
||||
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils)
|
||||
* OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator)
|
||||
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.5 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:3.0.6 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* 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.5.0 - https://github.com/albfernandez/juniversalchardet)
|
||||
|
||||
GNU Lesser General Public License (LGPL):
|
||||
|
||||
* juniversalchardet (com.github.albfernandez:juniversalchardet:2.5.0 - https://github.com/albfernandez/juniversalchardet)
|
||||
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
|
||||
* 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)
|
||||
* json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
|
||||
* json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
|
||||
* json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
|
||||
* msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
|
||||
* uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
|
||||
* openpdf (com.github.librepdf:openpdf:2.0.3 - https://github.com/LibrePDF/OpenPDF/openpdf)
|
||||
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/)
|
||||
* JHighlight (org.codelibs:jhighlight:1.1.0 - https://github.com/codelibs/jhighlight)
|
||||
* Cryptacular Library (org.cryptacular:cryptacular:1.2.5 - http://www.cryptacular.org)
|
||||
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:6.0.6.Final - http://hibernate.org)
|
||||
* Hibernate ORM - hibernate-core (org.hibernate.orm:hibernate-core:6.4.8.Final - https://hibernate.org/orm)
|
||||
* Hibernate ORM - hibernate-jcache (org.hibernate.orm:hibernate-jcache:6.4.8.Final - https://hibernate.org/orm)
|
||||
* Hibernate ORM - hibernate-jpamodelgen (org.hibernate.orm:hibernate-jpamodelgen:6.4.8.Final - https://hibernate.org/orm)
|
||||
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
|
||||
* Javassist (org.javassist:javassist:3.29.2-GA - http://www.javassist.org/)
|
||||
* Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
|
||||
* Flying Saucer Core Renderer (org.xhtmlrenderer:flying-saucer-core:9.12.0 - http://code.google.com/p/flying-saucer/flying-saucer-core/)
|
||||
* Flying Saucer PDF Rendering (org.xhtmlrenderer:flying-saucer-pdf:9.12.0 - http://code.google.com/p/flying-saucer/flying-saucer-pdf/)
|
||||
* XOM (xom:xom:1.3.9 - https://xom.nu)
|
||||
|
||||
Go License:
|
||||
@@ -648,25 +692,22 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* better-files (com.github.pathikrit:better-files_2.13:3.9.1 - https://github.com/pathikrit/better-files)
|
||||
* Java SemVer (com.github.zafarkhaja:java-semver:0.9.0 - https://github.com/zafarkhaja/jsemver)
|
||||
* dd-plist (com.googlecode.plist:dd-plist:1.28 - http://www.github.com/3breadt/dd-plist)
|
||||
* DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.10 - https://github.com/dbmdz/iiif-apis)
|
||||
* DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.11 - https://github.com/dbmdz/iiif-apis)
|
||||
* s3mock (io.findify:s3mock_2.13:0.2.6 - https://github.com/findify/s3mock)
|
||||
* ClassGraph (io.github.classgraph:classgraph:4.8.165 - https://github.com/classgraph/classgraph)
|
||||
* JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.4 - http://jopt-simple.github.io/jopt-simple)
|
||||
* 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-jdk15on:1.67 - http://www.bouncycastle.org/java.html)
|
||||
* Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk18on:1.78.1 - https://www.bouncycastle.org/java.html)
|
||||
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.67 - http://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)
|
||||
* Bouncy Castle JavaMail S/MIME APIs (org.bouncycastle:bcmail-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
|
||||
* Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
|
||||
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
|
||||
* Bouncy Castle ASN.1 Extension and Utility APIs (org.bouncycastle:bcutil-jdk18on:1.80 - https://www.bouncycastle.org/download/bouncy-castle-java/)
|
||||
* org.brotli:dec (org.brotli:dec:0.1.2 - http://brotli.org/dec)
|
||||
* Checker Qual (org.checkerframework:checker-qual:3.31.0 - https://checkerframework.org)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* Checker Qual (org.checkerframework:checker-qual:3.49.3 - https://checkerframework.org/)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* 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)
|
||||
* SLF4J API Module (org.slf4j:slf4j-api:2.0.11 - http://www.slf4j.org)
|
||||
* SLF4J Extensions Module (org.slf4j:slf4j-ext:1.7.28 - http://www.slf4j.org)
|
||||
* SLF4J API Module (org.slf4j:slf4j-api:2.0.17 - http://www.slf4j.org)
|
||||
* HAL Browser (org.webjars:hal-browser:ad9b865 - http://webjars.org)
|
||||
* toastr (org.webjars.bowergithub.codeseven:toastr:2.1.4 - http://webjars.org)
|
||||
* backbone (org.webjars.bowergithub.jashkenas:backbone:1.4.1 - https://www.webjars.org)
|
||||
@@ -674,28 +715,29 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
* 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)
|
||||
* core-js (org.webjars.npm:core-js:3.42.0 - https://www.webjars.org)
|
||||
* @json-editor/json-editor (org.webjars.npm:json-editor__json-editor:2.15.2 - https://www.webjars.org)
|
||||
|
||||
Mozilla Public License:
|
||||
|
||||
* 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.29.2-GA - http://www.javassist.org/)
|
||||
* juniversalchardet (com.github.albfernandez:juniversalchardet:2.5.0 - https://github.com/albfernandez/juniversalchardet)
|
||||
* openpdf (com.github.librepdf:openpdf:2.0.3 - https://github.com/LibrePDF/OpenPDF/openpdf)
|
||||
* H2 Database Engine (com.h2database:h2:2.3.232 - https://h2database.com)
|
||||
* Saxon-HE (net.sf.saxon:Saxon-HE:9.9.1-8 - http://www.saxonica.com/)
|
||||
* Javassist (org.javassist:javassist:3.30.2-GA - https://www.javassist.org/)
|
||||
* Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino)
|
||||
|
||||
Public Domain:
|
||||
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.12 - http://hdrhistogram.github.io/HdrHistogram/)
|
||||
* HdrHistogram (org.hdrhistogram:HdrHistogram:2.2.2 - http://hdrhistogram.github.io/HdrHistogram/)
|
||||
* JSON in Java (org.json:json:20231013 - https://github.com/douglascrockford/JSON-java)
|
||||
* 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:
|
||||
|
||||
@@ -703,16 +745,16 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
|
||||
|
||||
Unicode/ICU License:
|
||||
|
||||
* ICU4J (com.ibm.icu:icu4j:62.1 - http://icu-project.org/)
|
||||
* ICU4J (com.ibm.icu:icu4j:62.2 - http://icu-project.org/)
|
||||
|
||||
W3C license:
|
||||
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
|
||||
jQuery license:
|
||||
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.5 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
|
||||
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:3.1.10 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
|
||||
* jersey-media-multipart (org.glassfish.jersey.media:jersey-media-multipart:3.1.3 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-media-multipart)
|
||||
|
@@ -33,18 +33,18 @@ Prior versions of DSpace (v6.x and below) used two different UIs (XMLUI and JSPU
|
||||
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.lyrasis.org/display/DSDOC/).
|
||||
|
||||
The latest DSpace Installation instructions are available at:
|
||||
https://wiki.lyrasis.org/display/DSDOC8x/Installing+DSpace
|
||||
https://wiki.lyrasis.org/display/DSDOC9x/Installing+DSpace
|
||||
|
||||
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL)
|
||||
and a servlet container (usually Tomcat) in order to function.
|
||||
More information about these and all other prerequisites can be found in the Installation instructions above.
|
||||
|
||||
## Running DSpace 8 in Docker
|
||||
## Running DSpace 9 in Docker
|
||||
|
||||
NOTE: At this time, we do not have production-ready Docker images for DSpace.
|
||||
That said, we do have quick-start Docker Compose scripts for development or testing purposes.
|
||||
|
||||
See [Running DSpace 8 with Docker Compose](dspace/src/main/docker-compose/README.md)
|
||||
See [Running DSpace 9 with Docker Compose](dspace/src/main/docker-compose/README.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
|
@@ -7,4 +7,5 @@
|
||||
<!-- TODO: We should have these turned on. But, currently there's a known bug with indentation checks
|
||||
on JMockIt Expectations blocks and similar. See https://github.com/checkstyle/checkstyle/issues/3739 -->
|
||||
<suppress checks="Indentation" files="src[/\\]test[/\\]java"/>
|
||||
<suppress checks="Regexp" files="DSpaceHttpClientFactory\.java"/>
|
||||
</suppressions>
|
||||
|
@@ -136,5 +136,22 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
|
||||
<module name="OneStatementPerLine"/>
|
||||
<!-- Require that "catch" statements are not empty (must at least contain a comment) -->
|
||||
<module name="EmptyCatchBlock"/>
|
||||
|
||||
<!-- Require to use DSpaceHttpClientFactory.getClient() statement instead of creating directly the client -->
|
||||
<module name="Regexp">
|
||||
<property name="format" value="HttpClientBuilder\.create\s*\(\s*\)" />
|
||||
<property name="message" value="Use DSpaceHttpClientFactory.getClient() instead of HttpClientBuilder.create()" />
|
||||
<property name="illegalPattern" value="true"/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
<!-- Require to use DSpaceHttpClientFactory.getClient() statement instead of creating directly the client -->
|
||||
<module name="Regexp">
|
||||
<property name="format" value="HttpClients\.createDefault\s*\(\s*\)" />
|
||||
<property name="message" value="Use DSpaceHttpClientFactory.getClient() instead of HttpClients.createDefault()" />
|
||||
<property name="illegalPattern" value="true"/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
|
||||
|
||||
</module>
|
||||
</module>
|
||||
|
@@ -24,6 +24,8 @@ services:
|
||||
db__P__url: 'jdbc:postgresql://dspacedb:5432/dspace'
|
||||
# solr.server: Ensure we are using the 'dspacesolr' image for Solr
|
||||
solr__P__server: http://dspacesolr:8983/solr
|
||||
# matomo.tracker.url: Ensure we are using the 'matomo' image for Matomo
|
||||
matomo__P__tracker__P__url: http://matomo
|
||||
# proxies.trusted.ipranges: This setting is required for a REST API running in Docker to trust requests
|
||||
# from the host machine. This IP range MUST correspond to the 'dspacenet' subnet defined above.
|
||||
proxies__P__trusted__P__ipranges: '172.23.0'
|
||||
@@ -63,13 +65,12 @@ services:
|
||||
# DSpace PostgreSQL database container
|
||||
dspacedb:
|
||||
container_name: dspacedb
|
||||
# Uses a custom Postgres image with pgcrypto installed
|
||||
image: "${DOCKER_REGISTRY:-docker.io}/${DOCKER_OWNER:-dspace}/dspace-postgres-pgcrypto:${DSPACE_VER:-latest}"
|
||||
build:
|
||||
# Must build out of subdirectory to have access to install script for pgcrypto
|
||||
context: ./dspace/src/main/docker/dspace-postgres-pgcrypto/
|
||||
# Uses the base PostgreSQL image
|
||||
image: "docker.io/postgres:${POSTGRES_VERSION:-15}"
|
||||
environment:
|
||||
PGDATA: /pgdata
|
||||
POSTGRES_DB: dspace
|
||||
POSTGRES_USER: dspace
|
||||
POSTGRES_PASSWORD: dspace
|
||||
networks:
|
||||
dspacenet:
|
||||
@@ -91,7 +92,7 @@ services:
|
||||
additional_contexts:
|
||||
solrconfigs: ./dspace/solr/
|
||||
args:
|
||||
SOLR_VERSION: "${SOLR_VER:-8.11}"
|
||||
SOLR_VERSION: "${SOLR_VER:-9.8}"
|
||||
networks:
|
||||
dspacenet:
|
||||
ports:
|
||||
@@ -103,10 +104,15 @@ services:
|
||||
volumes:
|
||||
# Keep Solr data directory between reboots
|
||||
- solr_data:/var/solr/data
|
||||
# NOTE: We are not running Solr as "root", but we need root permissions to copy our cores to the mounted
|
||||
# /var/solr/data directory. Then we start Solr as the "solr" user.
|
||||
user: root
|
||||
# Initialize all DSpace Solr cores then start Solr:
|
||||
# * First, run precreate-core to create the core (if it doesn't yet exist). If exists already, this is a no-op
|
||||
# * Second, copy configsets to this core:
|
||||
# Updates to Solr configs require the container to be rebuilt/restarted: `docker compose -p d7 up -d --build dspacesolr`
|
||||
# * Third, ensure all new folders are owned by "solr" user
|
||||
# * Finally, start Solr as the "solr" user via the provided solr-foreground script
|
||||
entrypoint:
|
||||
- /bin/bash
|
||||
- '-c'
|
||||
@@ -124,7 +130,8 @@ services:
|
||||
cp -r /opt/solr/server/solr/configsets/qaevent/* qaevent
|
||||
precreate-core suggestion /opt/solr/server/solr/configsets/suggestion
|
||||
cp -r /opt/solr/server/solr/configsets/suggestion/* suggestion
|
||||
exec solr -f
|
||||
chown -R solr:solr /var/solr
|
||||
runuser -u solr -- solr-foreground
|
||||
volumes:
|
||||
assetstore:
|
||||
pgdata:
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<parent>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>9.0-SNAPSHOT</version>
|
||||
<version>10.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<version>3.6.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
@@ -177,7 +177,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>workflow-curation</id>
|
||||
@@ -500,10 +500,6 @@
|
||||
<groupId>jakarta.annotation</groupId>
|
||||
<artifactId>jakarta.annotation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.el</groupId>
|
||||
<artifactId>jakarta.el-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jaxen</groupId>
|
||||
<artifactId>jaxen</artifactId>
|
||||
@@ -516,10 +512,6 @@
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>fontbox</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ibm.icu</groupId>
|
||||
<artifactId>icu4j</artifactId>
|
||||
@@ -657,11 +649,18 @@
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- guava is needed by OAuth, Guice, Mockserver, ORCID, s3mock, Solr, JClouds -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Gson is needed by JENA, borker-client, OAuth, Handle and JClouds -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
@@ -735,7 +734,7 @@
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>1.12.781</version>
|
||||
<version>1.12.788</version>
|
||||
</dependency>
|
||||
|
||||
<!-- TODO: This may need to be replaced with the "orcid-model" artifact once this ticket is resolved:
|
||||
@@ -776,7 +775,7 @@
|
||||
<dependency>
|
||||
<groupId>com.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>5.10</version>
|
||||
<version>5.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Email templating -->
|
||||
@@ -789,7 +788,7 @@
|
||||
<dependency>
|
||||
<groupId>org.xmlunit</groupId>
|
||||
<artifactId>xmlunit-core</artifactId>
|
||||
<version>2.10.0</version>
|
||||
<version>2.10.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -864,5 +863,86 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- JClouds Assetstorage Support -->
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds</groupId>
|
||||
<artifactId>jclouds-core</artifactId>
|
||||
<version>${jclouds.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds</groupId>
|
||||
<artifactId>jclouds-blobstore</artifactId>
|
||||
<version>${jclouds.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>jakarta.ws.rs</groupId>
|
||||
<artifactId>jakarta.ws.rs-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds.api</groupId>
|
||||
<artifactId>filesystem</artifactId>
|
||||
<version>${jclouds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.jclouds.provider</groupId>
|
||||
<artifactId>aws-s3</artifactId>
|
||||
<version>${jclouds.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- required frontpage generation -->
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf</artifactId>
|
||||
<version>3.1.3.RELEASE</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.xhtmlrenderer</groupId>
|
||||
<artifactId>flying-saucer-pdf</artifactId>
|
||||
<version>9.13.1</version>
|
||||
<exclusions>
|
||||
<!-- Conflicts with Hibernate. Use version that is brought in via Hibernate -->
|
||||
<exclusion>
|
||||
<groupId>net.bytebuddy</groupId>
|
||||
<artifactId>byte-buddy</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@@ -8,8 +8,10 @@
|
||||
package org.dspace.access.status;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.dspace.content.AccessStatus;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
@@ -21,22 +23,37 @@ public interface AccessStatusHelper {
|
||||
* Calculate the access status for the item.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item
|
||||
* @param item the item
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
* @param type the type of calculation
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getAccessStatusFromItem(Context context, Item item, Date threshold)
|
||||
throws SQLException;
|
||||
public AccessStatus getAccessStatusFromItem(Context context,
|
||||
Item item, LocalDate threshold, String type) throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve embargo information for the item
|
||||
* Calculate the anonymous access status for the item.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to check for embargo information
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an embargo date
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getEmbargoFromItem(Context context, Item item, Date threshold) throws SQLException;
|
||||
public AccessStatus getAnonymousAccessStatusFromItem(Context context,
|
||||
Item item, LocalDate threshold) throws SQLException;
|
||||
|
||||
/**
|
||||
* Calculate the access status for the bitstream.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param bitstream the bitstream
|
||||
* @param threshold the embargo threshold date
|
||||
* @param type the type of calculation
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public AccessStatus getAccessStatusFromBitstream(Context context,
|
||||
Bitstream bitstream, LocalDate threshold, String type) throws SQLException;
|
||||
}
|
||||
|
@@ -10,9 +10,13 @@ package org.dspace.access.status;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.access.status.service.AccessStatusService;
|
||||
import org.dspace.content.AccessStatus;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.service.PluginService;
|
||||
@@ -23,10 +27,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* Implementation for the access status calculation service.
|
||||
*/
|
||||
public class AccessStatusServiceImpl implements AccessStatusService {
|
||||
private static final Logger log = LogManager.getLogger(AccessStatusServiceImpl.class);
|
||||
|
||||
// Plugin implementation, set from the DSpace configuration by init().
|
||||
protected AccessStatusHelper helper = null;
|
||||
|
||||
protected Date forever_date = null;
|
||||
protected LocalDate forever_date = null;
|
||||
|
||||
protected String itemCalculationType = null;
|
||||
protected String bitstreamCalculationType = null;
|
||||
|
||||
@Autowired(required = true)
|
||||
protected ConfigurationService configurationService;
|
||||
@@ -56,20 +65,39 @@ public class AccessStatusServiceImpl implements AccessStatusService {
|
||||
int month = configurationService.getIntProperty("access.status.embargo.forever.month");
|
||||
int day = configurationService.getIntProperty("access.status.embargo.forever.day");
|
||||
|
||||
forever_date = Date.from(LocalDate.of(year, month, day)
|
||||
forever_date = LocalDate.of(year, month, day)
|
||||
.atStartOfDay()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toInstant());
|
||||
.toLocalDate();
|
||||
|
||||
itemCalculationType = getAccessStatusCalculationType("access.status.for-user.item");
|
||||
bitstreamCalculationType = getAccessStatusCalculationType("access.status.for-user.bitstream");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccessStatus(Context context, Item item) throws SQLException {
|
||||
return helper.getAccessStatusFromItem(context, item, forever_date);
|
||||
public AccessStatus getAccessStatus(Context context, Item item) throws SQLException {
|
||||
return helper.getAccessStatusFromItem(context, item, forever_date, itemCalculationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmbargoFromItem(Context context, Item item) throws SQLException {
|
||||
return helper.getEmbargoFromItem(context, item, forever_date);
|
||||
public AccessStatus getAnonymousAccessStatus(Context context, Item item) throws SQLException {
|
||||
return helper.getAnonymousAccessStatusFromItem(context, item, forever_date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessStatus getAccessStatus(Context context, Bitstream bitstream) throws SQLException {
|
||||
return helper.getAccessStatusFromBitstream(context, bitstream, forever_date, bitstreamCalculationType);
|
||||
}
|
||||
|
||||
private String getAccessStatusCalculationType(String key) {
|
||||
String value = configurationService.getProperty(key, DefaultAccessStatusHelper.STATUS_FOR_ANONYMOUS);
|
||||
if (!StringUtils.equalsIgnoreCase(value, DefaultAccessStatusHelper.STATUS_FOR_ANONYMOUS) &&
|
||||
!StringUtils.equalsIgnoreCase(value, DefaultAccessStatusHelper.STATUS_FOR_CURRENT_USER)) {
|
||||
log.warn("The configuration parameter \"" + key
|
||||
+ "\" contains an invalid value. Valid values include: 'anonymous' and 'current'.");
|
||||
value = DefaultAccessStatusHelper.STATUS_FOR_ANONYMOUS;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
@@ -8,16 +8,18 @@
|
||||
package org.dspace.access.status;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.authorize.service.ResourcePolicyService;
|
||||
import org.dspace.content.AccessStatus;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
@@ -26,21 +28,23 @@ import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
|
||||
/**
|
||||
* Default plugin implementation of the access status helper.
|
||||
* The getAccessStatusFromItem method provides a simple logic to
|
||||
* calculate the access status of an item based on the policies of
|
||||
* the primary or the first bitstream in the original bundle.
|
||||
* Users can override this method for enhanced functionality.
|
||||
*
|
||||
* The getEmbargoInformationFromItem method provides a simple logic to
|
||||
* * retrieve embargo information of bitstreams from an item based on the policies of
|
||||
* * the primary or the first bitstream in the original bundle.
|
||||
* * Users can override this method for enhanced functionality.
|
||||
*
|
||||
* The methods provides a simple logic to calculate the access status
|
||||
* of an item based on the policies of the primary or the first bitstream
|
||||
* in the original bundle. Users can override those methods for
|
||||
* enhanced functionality.
|
||||
*/
|
||||
public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
public static final String STATUS_FOR_CURRENT_USER = "current";
|
||||
public static final String STATUS_FOR_ANONYMOUS = "anonymous";
|
||||
|
||||
public static final String EMBARGO = "embargo";
|
||||
public static final String METADATA_ONLY = "metadata.only";
|
||||
public static final String OPEN_ACCESS = "open.access";
|
||||
@@ -53,13 +57,15 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
AuthorizeServiceFactory.getInstance().getResourcePolicyService();
|
||||
protected AuthorizeService authorizeService =
|
||||
AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
||||
protected GroupService groupService =
|
||||
EPersonServiceFactory.getInstance().getGroupService();
|
||||
|
||||
public DefaultAccessStatusHelper() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the item's policies to determine an access status value.
|
||||
* Look at the item's primary or first bitstream policies to determine an access status value.
|
||||
* It is also considering a date threshold for embargoes and restrictions.
|
||||
*
|
||||
* If the item is null, simply returns the "unknown" value.
|
||||
@@ -67,14 +73,70 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
* @param context the DSpace context
|
||||
* @param item the item to check for embargoes
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
* @param type the type of calculation
|
||||
* @return the access status
|
||||
*/
|
||||
@Override
|
||||
public String getAccessStatusFromItem(Context context, Item item, Date threshold)
|
||||
public AccessStatus getAccessStatusFromItem(Context context, Item item, LocalDate threshold, String type)
|
||||
throws SQLException {
|
||||
if (item == null) {
|
||||
return UNKNOWN;
|
||||
return new AccessStatus(UNKNOWN, null);
|
||||
}
|
||||
Bitstream bitstream = getPrimaryOrFirstBitstreamInOriginalBundle(item);
|
||||
if (bitstream == null) {
|
||||
return new AccessStatus(METADATA_ONLY, null);
|
||||
}
|
||||
return getAccessStatusFromBitstream(context, bitstream, threshold, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the bitstream policies to determine an access status value.
|
||||
* It is also considering a date threshold for embargoes and restrictions.
|
||||
*
|
||||
* If the bitstream is null, simply returns the "unknown" value.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param bitstream the bitstream to check for embargoes
|
||||
* @param threshold the embargo threshold date
|
||||
* @param type the type of calculation
|
||||
* @return the access status
|
||||
*/
|
||||
@Override
|
||||
public AccessStatus getAccessStatusFromBitstream(Context context,
|
||||
Bitstream bitstream, LocalDate threshold, String type) throws SQLException {
|
||||
if (bitstream == null) {
|
||||
return new AccessStatus(UNKNOWN, null);
|
||||
}
|
||||
List<ResourcePolicy> policies = getReadPolicies(context, bitstream, type);
|
||||
LocalDate availabilityDate = findAvailabilityDate(policies, threshold);
|
||||
// Get the access status based on the availability date
|
||||
String accessStatus = getAccessStatusFromAvailabilityDate(availabilityDate, threshold);
|
||||
return new AccessStatus(accessStatus, availabilityDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the anonymous policies of the primary (or first)
|
||||
* bitstream of the item to retrieve its embargo.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item
|
||||
* @param threshold the embargo threshold date
|
||||
* @return the access status
|
||||
*/
|
||||
@Override
|
||||
public AccessStatus getAnonymousAccessStatusFromItem(Context context, Item item, LocalDate threshold)
|
||||
throws SQLException {
|
||||
return getAccessStatusFromItem(context, item, threshold, STATUS_FOR_ANONYMOUS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look in the item's original bundle. First, try to get the primary bitstream.
|
||||
* If the bitstream is null, simply returns the first one.
|
||||
*
|
||||
* @param item the DSpace item
|
||||
* @return the bitstream
|
||||
*/
|
||||
private Bitstream getPrimaryOrFirstBitstreamInOriginalBundle(Item item) {
|
||||
// Consider only the original bundles.
|
||||
List<Bundle> bundles = item.getBundles(Constants.DEFAULT_BUNDLE_NAME);
|
||||
// Check for primary bitstreams first.
|
||||
@@ -92,157 +154,159 @@ public class DefaultAccessStatusHelper implements AccessStatusHelper {
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
return calculateAccessStatusForDso(context, bitstream, threshold);
|
||||
return bitstream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the DSpace object's policies to determine an access status value.
|
||||
* Retrieves the anonymous read policies for a DSpace object
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param dso the DSpace object
|
||||
* @return a list of policies
|
||||
*/
|
||||
private List<ResourcePolicy> getAnonymousReadPolicies(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
// Only consider read policies. Use the find without a group
|
||||
// as it's not returning all expected values
|
||||
List<ResourcePolicy> readPolicies = resourcePolicyService.find(context, dso, Constants.READ);
|
||||
// Filter the policies with the anonymous group
|
||||
List<ResourcePolicy> filteredPolicies = readPolicies.stream()
|
||||
.filter(p -> p.getGroup() != null && StringUtils.equals(p.getGroup().getName(), Group.ANONYMOUS))
|
||||
.collect(Collectors.toList());
|
||||
return filteredPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current user read policies for a DSpace object
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param dso the DSpace object
|
||||
* @return a list of policies
|
||||
*/
|
||||
private List<ResourcePolicy> getCurrentUserReadPolicies(Context context, DSpaceObject dso)
|
||||
throws SQLException {
|
||||
// First, look if the current user can read the object
|
||||
boolean canRead = authorizeService.authorizeActionBoolean(context, dso, Constants.READ);
|
||||
// If it's true, it can't be an embargo or a restriction, shortcircuit the process
|
||||
// and return a null value (indicating an open access)
|
||||
if (canRead) {
|
||||
return null;
|
||||
}
|
||||
// Only consider read policies
|
||||
List<ResourcePolicy> policies = resourcePolicyService.find(context, dso, Constants.READ);
|
||||
// Only calculate the embargo date for the current user
|
||||
EPerson currentUser = context.getCurrentUser();
|
||||
List<ResourcePolicy> readPolicies = new ArrayList<ResourcePolicy>();
|
||||
for (ResourcePolicy policy : policies) {
|
||||
EPerson eperson = policy.getEPerson();
|
||||
if (eperson != null && currentUser != null && eperson.getID() == currentUser.getID()) {
|
||||
readPolicies.add(policy);
|
||||
continue;
|
||||
}
|
||||
Group group = policy.getGroup();
|
||||
if (group != null && groupService.isMember(context, currentUser, group)) {
|
||||
readPolicies.add(policy);
|
||||
}
|
||||
}
|
||||
return readPolicies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the read policies for a DSpace object based on the type
|
||||
*
|
||||
* If the type is current, consider the current logged in user
|
||||
* If the type is anonymous, only consider the anonymous group
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param dso the DSpace object
|
||||
* @param type the type of calculation
|
||||
* @return a list of policies
|
||||
*/
|
||||
private List<ResourcePolicy> getReadPolicies(Context context, DSpaceObject dso, String type)
|
||||
throws SQLException {
|
||||
if (StringUtils.equalsIgnoreCase(type, STATUS_FOR_CURRENT_USER)) {
|
||||
return getCurrentUserReadPolicies(context, dso);
|
||||
} else {
|
||||
// Only calculate the status for the anonymous group read policies
|
||||
return getAnonymousReadPolicies(context, dso);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the read policies to retrieve the access status availability date.
|
||||
*
|
||||
* @param readPolicies the read policies
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an availability date
|
||||
*/
|
||||
private LocalDate findAvailabilityDate(List<ResourcePolicy> readPolicies, LocalDate threshold) {
|
||||
// If the list is null, the object is readable
|
||||
if (readPolicies == null) {
|
||||
return null;
|
||||
}
|
||||
// If there's no policies, return the threshold date (restriction)
|
||||
if (readPolicies.size() == 0) {
|
||||
return threshold;
|
||||
}
|
||||
LocalDate availabilityDate = null;
|
||||
LocalDate currentDate = LocalDate.now();
|
||||
boolean takeMostRecentDate = true;
|
||||
// Looks at all read policies
|
||||
for (ResourcePolicy policy : readPolicies) {
|
||||
boolean isValid = resourcePolicyService.isDateValid(policy);
|
||||
// If any policy is valid, the object is accessible
|
||||
if (isValid) {
|
||||
return null;
|
||||
}
|
||||
// There may be an active embargo
|
||||
LocalDate startDate = policy.getStartDate();
|
||||
// Ignore policy with no start date or which is expired
|
||||
if (startDate == null || startDate.isBefore(currentDate)) {
|
||||
continue;
|
||||
}
|
||||
// Policy with a start date over the threshold (restriction)
|
||||
// overrides the embargos
|
||||
if (!startDate.isBefore(threshold)) {
|
||||
takeMostRecentDate = false;
|
||||
}
|
||||
// Take the most recent embargo date if there is no restriction, otherwise
|
||||
// take the highest date (account for rare cases where more than one resource
|
||||
// policy exists)
|
||||
if (availabilityDate == null) {
|
||||
availabilityDate = startDate;
|
||||
} else if (takeMostRecentDate) {
|
||||
availabilityDate = startDate.isBefore(availabilityDate) ? startDate : availabilityDate;
|
||||
} else {
|
||||
availabilityDate = startDate.isAfter(availabilityDate) ? startDate : availabilityDate;
|
||||
}
|
||||
}
|
||||
return availabilityDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the DSpace object availability date to determine an access status value.
|
||||
*
|
||||
* If the object is null, returns the "metadata.only" value.
|
||||
* If any policy attached to the object is valid for the anonymous group,
|
||||
* returns the "open.access" value.
|
||||
* Otherwise, if the policy start date is before the embargo threshold date,
|
||||
* returns the "embargo" value.
|
||||
* Every other cases return the "restricted" value.
|
||||
* If there's no availability date, returns the "open.access" value.
|
||||
* If the availability date is after or equal to the embargo
|
||||
* threshold date, returns the "restricted" value.
|
||||
* Every other cases return the "embargo" value.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param dso the DSpace object
|
||||
* @param threshold the embargo threshold date
|
||||
* @param availabilityDate the DSpace object availability date
|
||||
* @param threshold the embargo threshold date
|
||||
* @return an access status value
|
||||
*/
|
||||
private String calculateAccessStatusForDso(Context context, DSpaceObject dso, Date threshold)
|
||||
throws SQLException {
|
||||
if (dso == null) {
|
||||
return METADATA_ONLY;
|
||||
}
|
||||
// Only consider read policies.
|
||||
List<ResourcePolicy> policies = authorizeService
|
||||
.getPoliciesActionFilter(context, dso, Constants.READ);
|
||||
int openAccessCount = 0;
|
||||
int embargoCount = 0;
|
||||
int restrictedCount = 0;
|
||||
int unknownCount = 0;
|
||||
// Looks at all read policies.
|
||||
for (ResourcePolicy policy : policies) {
|
||||
boolean isValid = resourcePolicyService.isDateValid(policy);
|
||||
Group group = policy.getGroup();
|
||||
// The group must not be null here. However,
|
||||
// if it is, consider this as an unexpected case.
|
||||
if (group == null) {
|
||||
unknownCount++;
|
||||
} else if (StringUtils.equals(group.getName(), Group.ANONYMOUS)) {
|
||||
// Only calculate the status for the anonymous group.
|
||||
if (isValid) {
|
||||
// If the policy is valid, the anonymous group have access
|
||||
// to the bitstream.
|
||||
openAccessCount++;
|
||||
} else {
|
||||
Date startDate = policy.getStartDate();
|
||||
if (startDate != null && !startDate.before(threshold)) {
|
||||
// If the policy start date have a value and if this value
|
||||
// is equal or superior to the configured forever date, the
|
||||
// access status is also restricted.
|
||||
restrictedCount++;
|
||||
} else {
|
||||
// If the current date is not between the policy start date
|
||||
// and end date, the access status is embargo.
|
||||
embargoCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (openAccessCount > 0) {
|
||||
private String getAccessStatusFromAvailabilityDate(LocalDate availabilityDate, LocalDate threshold) {
|
||||
// If there is no availability date, it's an open access.
|
||||
if (availabilityDate == null) {
|
||||
return OPEN_ACCESS;
|
||||
}
|
||||
if (embargoCount > 0 && restrictedCount == 0) {
|
||||
return EMBARGO;
|
||||
// If the policy start date have a value and if this value
|
||||
// is equal or superior to the configured forever date, the
|
||||
// access status is also restricted.
|
||||
if (!availabilityDate.isBefore(threshold)) {
|
||||
return RESTRICTED;
|
||||
}
|
||||
if (unknownCount > 0) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
return RESTRICTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look at the policies of the primary (or first) bitstream of the item to retrieve its embargo.
|
||||
*
|
||||
* If the item is null, simply returns an empty map with no embargo information.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to embargo
|
||||
* @return an access status value
|
||||
*/
|
||||
@Override
|
||||
public String getEmbargoFromItem(Context context, Item item, Date threshold)
|
||||
throws SQLException {
|
||||
Date embargoDate;
|
||||
|
||||
// If Item status is not "embargo" then return a null embargo date.
|
||||
String accessStatus = getAccessStatusFromItem(context, item, threshold);
|
||||
|
||||
if (item == null || !accessStatus.equals(EMBARGO)) {
|
||||
return null;
|
||||
}
|
||||
// Consider only the original bundles.
|
||||
List<Bundle> bundles = item.getBundles(Constants.DEFAULT_BUNDLE_NAME);
|
||||
// Check for primary bitstreams first.
|
||||
Bitstream bitstream = bundles.stream()
|
||||
.map(bundle -> bundle.getPrimaryBitstream())
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (bitstream == null) {
|
||||
// If there is no primary bitstream,
|
||||
// take the first bitstream in the bundles.
|
||||
bitstream = bundles.stream()
|
||||
.map(bundle -> bundle.getBitstreams())
|
||||
.flatMap(List::stream)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (bitstream == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
embargoDate = this.retrieveShortestEmbargo(context, bitstream);
|
||||
|
||||
return embargoDate != null ? embargoDate.toString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Date retrieveShortestEmbargo(Context context, Bitstream bitstream) throws SQLException {
|
||||
Date embargoDate = null;
|
||||
// Only consider read policies.
|
||||
List<ResourcePolicy> policies = authorizeService
|
||||
.getPoliciesActionFilter(context, bitstream, Constants.READ);
|
||||
|
||||
// Looks at all read policies.
|
||||
for (ResourcePolicy policy : policies) {
|
||||
boolean isValid = resourcePolicyService.isDateValid(policy);
|
||||
Group group = policy.getGroup();
|
||||
|
||||
if (group != null && StringUtils.equals(group.getName(), Group.ANONYMOUS)) {
|
||||
// Only calculate the status for the anonymous group.
|
||||
if (!isValid) {
|
||||
// If the policy is not valid there is an active embargo
|
||||
Date startDate = policy.getStartDate();
|
||||
|
||||
if (startDate != null && !startDate.before(Date.from(Instant.now()))) {
|
||||
// There is an active embargo: aim to take the shortest embargo (account for rare cases where
|
||||
// more than one resource policy exists)
|
||||
if (embargoDate == null) {
|
||||
embargoDate = startDate;
|
||||
} else {
|
||||
embargoDate = startDate.before(embargoDate) ? startDate : embargoDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return embargoDate;
|
||||
return EMBARGO;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ package org.dspace.access.status.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.content.AccessStatus;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
@@ -39,19 +41,29 @@ public interface AccessStatusService {
|
||||
* Calculate the access status for an Item while considering the forever embargo date threshold.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item
|
||||
* @return an access status value
|
||||
* @param item the item
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getAccessStatus(Context context, Item item) throws SQLException;
|
||||
public AccessStatus getAccessStatus(Context context, Item item) throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve embargo information for the item
|
||||
* Calculate the anonymous access status for an Item while considering the forever embargo date threshold.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param item the item to check for embargo information
|
||||
* @return an embargo date
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public String getEmbargoFromItem(Context context, Item item) throws SQLException;
|
||||
public AccessStatus getAnonymousAccessStatus(Context context, Item item) throws SQLException;
|
||||
|
||||
/**
|
||||
* Calculate the access status for a bitstream while considering the forever embargo date threshold.
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param bitstream the bitstream
|
||||
* @return the access status
|
||||
* @throws SQLException An exception that provides information on a database access error or other errors.
|
||||
*/
|
||||
public AccessStatus getAccessStatus(Context context, Bitstream bitstream) throws SQLException;
|
||||
}
|
||||
|
@@ -9,12 +9,12 @@ package org.dspace.administer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.ProcessStatus;
|
||||
import org.dspace.core.Context;
|
||||
@@ -96,7 +96,7 @@ public class ProcessCleaner extends DSpaceRunnable<ProcessCleanerConfiguration<P
|
||||
private void performDeletion(Context context) throws SQLException, IOException, AuthorizeException {
|
||||
|
||||
List<ProcessStatus> statuses = getProcessToDeleteStatuses();
|
||||
Date creationDate = calculateCreationDate();
|
||||
Instant creationDate = calculateCreationDate();
|
||||
|
||||
handler.logInfo("Searching for processes with status: " + statuses);
|
||||
List<Process> processes = processService.findByStatusAndCreationTimeOlderThan(context, statuses, creationDate);
|
||||
@@ -126,8 +126,8 @@ public class ProcessCleaner extends DSpaceRunnable<ProcessCleanerConfiguration<P
|
||||
return statuses;
|
||||
}
|
||||
|
||||
private Date calculateCreationDate() {
|
||||
return DateUtils.addDays(new Date(), -days);
|
||||
private Instant calculateCreationDate() {
|
||||
return Instant.now().minus(days, ChronoUnit.DAYS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.administer;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -18,6 +17,7 @@ import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -49,8 +49,9 @@ public class RegistryImporter {
|
||||
*/
|
||||
public static Document loadXML(String filename)
|
||||
throws IOException, ParserConfigurationException, SAXException {
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
// This XML builder will *not* disable external entities as XML
|
||||
// registries are considered trusted content
|
||||
DocumentBuilder builder = XMLUtils.getTrustedDocumentBuilder();
|
||||
|
||||
Document document = builder.parse(new File(filename));
|
||||
|
||||
|
@@ -13,7 +13,6 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -21,7 +20,15 @@ import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.CommandLineParser;
|
||||
import org.apache.commons.cli.DefaultParser;
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.BitstreamFormat;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
@@ -41,7 +48,7 @@ import org.xml.sax.SAXException;
|
||||
* <P>
|
||||
* <code>RegistryLoader -bitstream bitstream-formats.xml</code>
|
||||
* <P>
|
||||
* <code>RegistryLoader -dc dc-types.xml</code>
|
||||
* <code>RegistryLoader -metadata dc-types.xml</code>
|
||||
*
|
||||
* @author Robert Tansley
|
||||
* @version $Revision$
|
||||
@@ -50,7 +57,7 @@ public class RegistryLoader {
|
||||
/**
|
||||
* log4j category
|
||||
*/
|
||||
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RegistryLoader.class);
|
||||
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(RegistryLoader.class);
|
||||
|
||||
protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
|
||||
.getBitstreamFormatService();
|
||||
@@ -67,50 +74,99 @@ public class RegistryLoader {
|
||||
* @throws Exception if error
|
||||
*/
|
||||
public static void main(String[] argv) throws Exception {
|
||||
String usage = "Usage: " + RegistryLoader.class.getName()
|
||||
+ " (-bitstream | -metadata) registry-file.xml";
|
||||
|
||||
Context context = null;
|
||||
// Set up command-line options and parse arguments
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
Options options = createCommandLineOptions();
|
||||
|
||||
try {
|
||||
context = new Context();
|
||||
CommandLine line = parser.parse(options, argv);
|
||||
|
||||
// Check if help option was entered or no options provided
|
||||
if (line.hasOption('h') || line.getOptions().length == 0) {
|
||||
printHelp(options);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
Context context = new Context();
|
||||
|
||||
// Can't update registries anonymously, so we need to turn off
|
||||
// authorisation
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
// Work out what we're loading
|
||||
if (argv[0].equalsIgnoreCase("-bitstream")) {
|
||||
RegistryLoader.loadBitstreamFormats(context, argv[1]);
|
||||
} else if (argv[0].equalsIgnoreCase("-metadata")) {
|
||||
// Call MetadataImporter, as it handles Metadata schema updates
|
||||
MetadataImporter.loadRegistry(argv[1], true);
|
||||
} else {
|
||||
System.err.println(usage);
|
||||
try {
|
||||
// Work out what we're loading
|
||||
if (line.hasOption('b')) {
|
||||
String filename = line.getOptionValue('b');
|
||||
if (StringUtils.isEmpty(filename)) {
|
||||
System.err.println("No file path provided for bitstream format registry");
|
||||
printHelp(options);
|
||||
System.exit(1);
|
||||
}
|
||||
RegistryLoader.loadBitstreamFormats(context, filename);
|
||||
} else if (line.hasOption('m')) {
|
||||
String filename = line.getOptionValue('m');
|
||||
if (StringUtils.isEmpty(filename)) {
|
||||
System.err.println("No file path provided for metadata registry");
|
||||
printHelp(options);
|
||||
System.exit(1);
|
||||
}
|
||||
// Call MetadataImporter, as it handles Metadata schema updates
|
||||
MetadataImporter.loadRegistry(filename, true);
|
||||
} else {
|
||||
System.err.println("No registry type specified");
|
||||
printHelp(options);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Commit changes and close Context
|
||||
context.complete();
|
||||
System.exit(0);
|
||||
} catch (Exception e) {
|
||||
log.fatal(LogHelper.getHeader(context, "error_loading_registries", ""), e);
|
||||
System.err.println("Error: \n - " + e.getMessage());
|
||||
System.exit(1);
|
||||
} finally {
|
||||
// Clean up our context, if it still exists & it was never completed
|
||||
if (context != null && context.isValid()) {
|
||||
context.abort();
|
||||
}
|
||||
}
|
||||
|
||||
// Commit changes and close Context
|
||||
context.complete();
|
||||
|
||||
System.exit(0);
|
||||
} catch (ArrayIndexOutOfBoundsException ae) {
|
||||
System.err.println(usage);
|
||||
|
||||
} catch (ParseException e) {
|
||||
System.err.println("Error parsing command-line arguments: " + e.getMessage());
|
||||
printHelp(options);
|
||||
System.exit(1);
|
||||
} catch (Exception e) {
|
||||
log.fatal(LogHelper.getHeader(context, "error_loading_registries",
|
||||
""), e);
|
||||
|
||||
System.err.println("Error: \n - " + e.getMessage());
|
||||
System.exit(1);
|
||||
} finally {
|
||||
// Clean up our context, if it still exists & it was never completed
|
||||
if (context != null && context.isValid()) {
|
||||
context.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the command-line options
|
||||
* @return the command-line options
|
||||
*/
|
||||
private static Options createCommandLineOptions() {
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("b", "bitstream", true, "load bitstream format registry from specified file");
|
||||
options.addOption("m", "metadata", true, "load metadata registry from specified file");
|
||||
options.addOption("h", "help", false, "print this help message");
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the help message
|
||||
* @param options the command-line options
|
||||
*/
|
||||
private static void printHelp(Options options) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("RegistryLoader",
|
||||
"Load bitstream format or metadata registries into the database\n",
|
||||
options,
|
||||
"\nExamples:\n" +
|
||||
" RegistryLoader -b bitstream-formats.xml\n" +
|
||||
" RegistryLoader -m dc-types.xml",
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Bitstream Format metadata
|
||||
*
|
||||
@@ -210,8 +266,9 @@ public class RegistryLoader {
|
||||
*/
|
||||
private static Document loadXML(String filename) throws IOException,
|
||||
ParserConfigurationException, SAXException {
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
// This XML builder will *not* disable external entities as XML
|
||||
// registries are considered trusted content
|
||||
DocumentBuilder builder = XMLUtils.getTrustedDocumentBuilder();
|
||||
|
||||
return builder.parse(new File(filename));
|
||||
}
|
||||
@@ -221,7 +278,7 @@ public class RegistryLoader {
|
||||
* contains:
|
||||
* <P>
|
||||
* <code>
|
||||
* <foo><mimetype>application/pdf</mimetype></foo>
|
||||
* <foo><mimetype>application/pdf</mimetype></foo>
|
||||
* </code>
|
||||
* passing this the <code>foo</code> node and <code>mimetype</code> will
|
||||
* return <code>application/pdf</code>.
|
||||
@@ -262,10 +319,10 @@ public class RegistryLoader {
|
||||
* document contains:
|
||||
* <P>
|
||||
* <code>
|
||||
* <foo>
|
||||
* <bar>val1</bar>
|
||||
* <bar>val2</bar>
|
||||
* </foo>
|
||||
* <foo>
|
||||
* <bar>val1</bar>
|
||||
* <bar>val2</bar>
|
||||
* </foo>
|
||||
* </code>
|
||||
* passing this the <code>foo</code> node and <code>bar</code> will
|
||||
* return <code>val1</code> and <code>val2</code>.
|
||||
|
@@ -27,7 +27,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -43,6 +42,7 @@ import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
@@ -613,8 +613,8 @@ public class StructBuilder {
|
||||
*/
|
||||
private static org.w3c.dom.Document loadXML(InputStream input)
|
||||
throws IOException, ParserConfigurationException, SAXException {
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
// This builder factory does not disable external DTD, entities, etc.
|
||||
DocumentBuilder builder = XMLUtils.getTrustedDocumentBuilder();
|
||||
|
||||
org.w3c.dom.Document document = builder.parse(input);
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.alerts;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import jakarta.persistence.Cacheable;
|
||||
import jakarta.persistence.Column;
|
||||
@@ -17,8 +17,6 @@ import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
@@ -46,8 +44,7 @@ public class SystemWideAlert implements ReloadableEntity<Integer> {
|
||||
private String allowSessions;
|
||||
|
||||
@Column(name = "countdown_to")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date countdownTo;
|
||||
private ZonedDateTime countdownTo;
|
||||
|
||||
@Column(name = "active")
|
||||
private boolean active;
|
||||
@@ -115,7 +112,7 @@ public class SystemWideAlert implements ReloadableEntity<Integer> {
|
||||
*
|
||||
* @return the date to which will be count down when the system-wide alert is active
|
||||
*/
|
||||
public Date getCountdownTo() {
|
||||
public ZonedDateTime getCountdownTo() {
|
||||
return countdownTo;
|
||||
}
|
||||
|
||||
@@ -124,7 +121,7 @@ public class SystemWideAlert implements ReloadableEntity<Integer> {
|
||||
*
|
||||
* @param countdownTo The date to which will be count down
|
||||
*/
|
||||
public void setCountdownTo(final Date countdownTo) {
|
||||
public void setCountdownTo(final ZonedDateTime countdownTo) {
|
||||
this.countdownTo = countdownTo;
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.alerts;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -39,7 +39,7 @@ public class SystemWideAlertServiceImpl implements SystemWideAlertService {
|
||||
@Override
|
||||
public SystemWideAlert create(final Context context, final String message,
|
||||
final AllowSessionsEnum allowSessionsType,
|
||||
final Date countdownTo, final boolean active) throws SQLException,
|
||||
final ZonedDateTime countdownTo, final boolean active) throws SQLException,
|
||||
AuthorizeException {
|
||||
if (!authorizeService.isAdmin(context)) {
|
||||
throw new AuthorizeException(
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.alerts.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.alerts.AllowSessionsEnum;
|
||||
@@ -35,7 +35,7 @@ public interface SystemWideAlertService {
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
SystemWideAlert create(Context context, String message, AllowSessionsEnum allowSessionsType,
|
||||
Date countdownTo, boolean active
|
||||
ZonedDateTime countdownTo, boolean active
|
||||
) throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
|
@@ -16,10 +16,10 @@ import static org.dspace.core.Constants.CONTENT_BUNDLE_NAME;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -154,7 +154,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
}
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
mapper.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
|
||||
BulkAccessControlInput accessControl;
|
||||
context = new Context(Context.Mode.BATCH_EDIT);
|
||||
setEPerson(context);
|
||||
@@ -312,7 +312,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
* check the validation of access condition,
|
||||
* the access condition name must equal to one of configured access conditions,
|
||||
* then call {@link AccessConditionOption#validateResourcePolicy(
|
||||
* Context, String, Date, Date)} if exception happens so, it's invalid.
|
||||
* Context, String, LocalDate, LocalDate)} if exception happens so, it's invalid.
|
||||
*
|
||||
* @param accessCondition the accessCondition
|
||||
* @throws BulkAccessControlException if the accessCondition is invalid
|
||||
@@ -416,7 +416,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
discoverQuery.setQuery(query);
|
||||
discoverQuery.setStart(start);
|
||||
discoverQuery.setMaxResults(limit);
|
||||
|
||||
discoverQuery.setSortField("search.resourceid", DiscoverQuery.SORT_ORDER.asc);
|
||||
return discoverQuery;
|
||||
}
|
||||
|
||||
@@ -596,8 +596,8 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
|
||||
String name = accessCondition.getName();
|
||||
String description = accessCondition.getDescription();
|
||||
Date startDate = accessCondition.getStartDate();
|
||||
Date endDate = accessCondition.getEndDate();
|
||||
LocalDate startDate = accessCondition.getStartDate();
|
||||
LocalDate endDate = accessCondition.getEndDate();
|
||||
|
||||
try {
|
||||
accessConditionOption.createResourcePolicy(context, obj, name, description, startDate, endDate);
|
||||
@@ -651,7 +651,7 @@ public class BulkAccessControl extends DSpaceRunnable<BulkAccessControlScriptCon
|
||||
}
|
||||
|
||||
private void AppendAccessConditionsInfo(StringBuilder message, List<AccessCondition> accessConditions) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
DateTimeFormatter dateFormat = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
message.append("{");
|
||||
|
||||
for (int i = 0; i < accessConditions.size(); i++) {
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.bulkaccesscontrol.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import org.dspace.app.bulkaccesscontrol.BulkAccessControl;
|
||||
@@ -25,15 +25,15 @@ public class AccessCondition {
|
||||
private String description;
|
||||
|
||||
@JsonDeserialize(using = MultiFormatDateDeserializer.class)
|
||||
private Date startDate;
|
||||
private LocalDate startDate;
|
||||
|
||||
@JsonDeserialize(using = MultiFormatDateDeserializer.class)
|
||||
private Date endDate;
|
||||
private LocalDate endDate;
|
||||
|
||||
public AccessCondition() {
|
||||
}
|
||||
|
||||
public AccessCondition(String name, String description, Date startDate, Date endDate) {
|
||||
public AccessCondition(String name, String description, LocalDate startDate, LocalDate endDate) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.startDate = startDate;
|
||||
@@ -48,11 +48,11 @@ public class AccessCondition {
|
||||
return description;
|
||||
}
|
||||
|
||||
public Date getStartDate() {
|
||||
public LocalDate getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
public Date getEndDate() {
|
||||
public LocalDate getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
@@ -457,7 +458,7 @@ public class DSpaceCSV implements Serializable {
|
||||
List<Collection> collections = i.getCollections();
|
||||
for (Collection c : collections) {
|
||||
// Only add if it is not the owning collection
|
||||
if (!c.getHandle().equals(owningCollectionHandle)) {
|
||||
if (!Objects.equals(c.getHandle(), owningCollectionHandle)) {
|
||||
line.add("collection", c.getHandle());
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* 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.bulkedit;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.content.MetadataDSpaceCsvExportServiceImpl;
|
||||
import org.dspace.content.MetadataField;
|
||||
import org.dspace.content.factory.ContentReportServiceFactory;
|
||||
import org.dspace.content.service.MetadataDSpaceCsvExportService;
|
||||
import org.dspace.contentreport.Filter;
|
||||
import org.dspace.contentreport.FilteredItems;
|
||||
import org.dspace.contentreport.FilteredItemsQuery;
|
||||
import org.dspace.contentreport.QueryOperator;
|
||||
import org.dspace.contentreport.QueryPredicate;
|
||||
import org.dspace.contentreport.service.ContentReportService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.kernel.ServiceManager;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* Metadata exporter to allow the batch export of metadata from a Filtered Items content report execution into a file
|
||||
*
|
||||
* @author Jean-François Morin (Université Laval)
|
||||
*/
|
||||
public class MetadataExportFilteredItemsReport extends DSpaceRunnable
|
||||
<MetadataExportFilteredItemsReportScriptConfiguration<MetadataExportFilteredItemsReport>> {
|
||||
|
||||
private static final String EXPORT_CSV = "exportCSV";
|
||||
public static final String DEFAULT_FILENAME = "metadataExportFilteredItems.csv";
|
||||
private boolean help = false;
|
||||
private String[] collectionUuids;
|
||||
private String[] queryPredicates;
|
||||
private String[] queryFilters;
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
private ContentReportService contentReportService;
|
||||
private EPersonService ePersonService;
|
||||
private MetadataDSpaceCsvExportService metadataDSpaceCsvExportService;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public MetadataExportFilteredItemsReportScriptConfiguration<MetadataExportFilteredItemsReport>
|
||||
getScriptConfiguration() {
|
||||
return new DSpace().getServiceManager()
|
||||
.getServiceByName("metadata-export-filtered-items-report",
|
||||
MetadataExportFilteredItemsReportScriptConfiguration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
ServiceManager serviceManager = new DSpace().getServiceManager();
|
||||
configurationService = serviceManager.getServicesByType(ConfigurationService.class).get(0);
|
||||
contentReportService = ContentReportServiceFactory.getInstance().getContentReportService();
|
||||
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
||||
metadataDSpaceCsvExportService = serviceManager.getServiceByName(
|
||||
MetadataDSpaceCsvExportServiceImpl.class.getCanonicalName(),
|
||||
MetadataDSpaceCsvExportService.class);
|
||||
|
||||
if (commandLine.hasOption('h')) {
|
||||
help = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (commandLine.hasOption('c')) {
|
||||
collectionUuids = commandLine.getOptionValues('c');
|
||||
}
|
||||
|
||||
if (commandLine.hasOption("qp")) {
|
||||
queryPredicates = commandLine.getOptionValues("qp");
|
||||
}
|
||||
|
||||
if (commandLine.hasOption('f')) {
|
||||
queryFilters = commandLine.getOptionValues('f');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalRun() throws Exception {
|
||||
if (help) {
|
||||
loghelpinfo();
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
handler.logDebug("starting content report export");
|
||||
|
||||
Context context = new Context();
|
||||
context.setCurrentUser(ePersonService.find(context, getEpersonIdentifier()));
|
||||
|
||||
List<String> collUuids = List.of();
|
||||
if (collectionUuids != null) {
|
||||
// Using a temporary Set to eliminate duplicates, if any
|
||||
Set<String> setUuids = arrayToStream(collectionUuids)
|
||||
.map(uuids -> uuids.split("[^0-9A-Fa-f\\-]+"))
|
||||
.flatMap(Arrays::stream)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
collUuids = new ArrayList<>(setUuids);
|
||||
}
|
||||
|
||||
List<QueryPredicate> predicates = List.of();
|
||||
if (queryPredicates != null) {
|
||||
predicates = arrayToStream(queryPredicates)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.map(pred -> buildPredicate(context, pred))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
Set<Filter> filters = EnumSet.noneOf(Filter.class);
|
||||
if (queryFilters != null) {
|
||||
Arrays.stream(queryFilters)
|
||||
.map(Filter::getFilters)
|
||||
.flatMap(Set::stream)
|
||||
.filter(f -> f != null)
|
||||
.forEach(filters::add);
|
||||
}
|
||||
|
||||
handler.logDebug("building query");
|
||||
FilteredItemsQuery query = FilteredItemsQuery.of(
|
||||
collUuids, predicates, 0, Integer.MAX_VALUE, filters, List.of());
|
||||
handler.logDebug("creating iterator");
|
||||
|
||||
FilteredItems items = contentReportService.findFilteredItems(context, query);
|
||||
handler.logDebug("creating dspacecsv");
|
||||
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, items.getItems().iterator(),
|
||||
true, handler);
|
||||
handler.logDebug("writing to file " + getFileNameOrExportFile());
|
||||
handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV);
|
||||
context.restoreAuthSystemState();
|
||||
context.complete();
|
||||
}
|
||||
|
||||
protected void loghelpinfo() {
|
||||
handler.logInfo("metadata-export-filtered-items-report");
|
||||
}
|
||||
|
||||
protected String getFileNameOrExportFile() {
|
||||
return configurationService.getProperty("contentreport.metadataquery.csv.filename.default", DEFAULT_FILENAME);
|
||||
}
|
||||
|
||||
private static Stream<String> arrayToStream(String... array) {
|
||||
return Optional.ofNullable(array)
|
||||
.stream()
|
||||
.flatMap(Arrays::stream)
|
||||
.filter(StringUtils::isNotBlank);
|
||||
}
|
||||
|
||||
private QueryPredicate buildPredicate(Context context, String exp) {
|
||||
String[] tokens = exp.split("\\:");
|
||||
String field = tokens.length > 0 ? tokens[0].trim() : "";
|
||||
QueryOperator operator = tokens.length > 1 ? QueryOperator.get(tokens[1].trim()) : null;
|
||||
String value = tokens.length > 2 ? StringUtils.trimToEmpty(tokens[2]) : "";
|
||||
|
||||
try {
|
||||
List<MetadataField> fields = contentReportService.getMetadataFields(context, field);
|
||||
return QueryPredicate.of(fields, operator, value);
|
||||
} catch (SQLException e) {
|
||||
throw new IllegalArgumentException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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.bulkedit;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* The CLI version of the {@link MetadataExportFilteredItemsReport} script
|
||||
*
|
||||
* @author Jean-François Morin (Université Laval)
|
||||
*/
|
||||
public class MetadataExportFilteredItemsReportCli extends MetadataExportFilteredItemsReport {
|
||||
|
||||
@Override
|
||||
protected String getFileNameOrExportFile() {
|
||||
return Optional.ofNullable(commandLine.getOptionValue('n'))
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.orElseGet(() -> super.getFileNameOrExportFile());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.bulkedit;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* This is the CLI version of the {@link MetadataExportFilteredItemsReportScriptConfiguration} class that handles the
|
||||
* configuration for the {@link MetadataExportFilteredItemsReportCli} script
|
||||
*
|
||||
* @author Jean-François Morin (Université Laval)
|
||||
*/
|
||||
public class MetadataExportFilteredItemsReportCliScriptConfiguration
|
||||
extends MetadataExportFilteredItemsReportScriptConfiguration<MetadataExportFilteredItemsReportCli> {
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = super.getOptions();
|
||||
String filename = configurationService.getProperty("contentreport.metadataquery.csv.filename.default",
|
||||
MetadataExportFilteredItemsReport.DEFAULT_FILENAME);
|
||||
options.addOption("n", "filename", true, "the filename to export to (default: " + filename + ")");
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* 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.bulkedit;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
|
||||
/**
|
||||
* The {@link ScriptConfiguration} for the {@link MetadataExportFilteredItemsReport} script
|
||||
*
|
||||
* @author Jean-François Morin (Université Laval)
|
||||
*/
|
||||
public class MetadataExportFilteredItemsReportScriptConfiguration<T extends MetadataExportFilteredItemsReport>
|
||||
extends ScriptConfiguration<T> {
|
||||
|
||||
private Class<T> dspaceRunnableclass;
|
||||
|
||||
@Override
|
||||
public Class<T> getDspaceRunnableClass() {
|
||||
return dspaceRunnableclass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
|
||||
dspaceRunnableclass = dspaceRunnableClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
if (options == null) {
|
||||
Options options = new Options();
|
||||
options.addOption("c", "collections", true,
|
||||
"UUIDs of collections to search for eligible records");
|
||||
options.getOption("c").setType(String.class);
|
||||
options.addOption("qp", "queryPredicates", true,
|
||||
"Predicates or field queries used as criteria to filter records");
|
||||
options.getOption("qp").setType(String.class);
|
||||
options.addOption("f", "filters", true, """
|
||||
Filters from the org.dspace.contentreport.Filter enumeration
|
||||
used to filter records. Any filtered included here is considered as being selected,
|
||||
and is considered unselected otherwise.""");
|
||||
options.getOption("f").setType(String.class);
|
||||
options.addOption("h", "help", false, "help");
|
||||
|
||||
super.options = options;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -143,7 +143,7 @@ public class MetadataExportSearch extends DSpaceRunnable<MetadataExportSearchScr
|
||||
|
||||
Iterator<Item> itemIterator = searchService.iteratorSearch(context, dso, discoverQuery);
|
||||
handler.logDebug("creating dspacecsv");
|
||||
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, itemIterator, true);
|
||||
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService.export(context, itemIterator, true, handler);
|
||||
handler.logDebug("writing to file " + getFileNameOrExportFile());
|
||||
handler.writeFilestream(context, getFileNameOrExportFile(), dSpaceCSV.getInputStream(), EXPORT_CSV);
|
||||
context.restoreAuthSystemState();
|
||||
|
@@ -23,6 +23,7 @@ import java.util.UUID;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.RelationshipUtils;
|
||||
@@ -89,7 +90,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
/**
|
||||
* The authority controlled fields
|
||||
*/
|
||||
protected static Set<String> authorityControlled;
|
||||
protected Set<String> authorityControlled;
|
||||
|
||||
/**
|
||||
* The prefix of the authority controlled field
|
||||
@@ -742,10 +743,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
if (value == null || !value.contains(csv.getAuthoritySeparator())) {
|
||||
simplyCopyValue(value, dcv);
|
||||
} else {
|
||||
String[] parts = value.split(csv.getAuthoritySeparator());
|
||||
dcv.setValue(parts[0]);
|
||||
dcv.setAuthority(parts[1]);
|
||||
dcv.setConfidence((parts.length > 2 ? Integer.valueOf(parts[2]) : Choices.CF_ACCEPTED));
|
||||
resolveValueAndAuthority(value, dcv);
|
||||
}
|
||||
|
||||
// fromAuthority==null: with the current implementation metadata values from external authority sources
|
||||
@@ -1145,12 +1143,12 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
}
|
||||
|
||||
// look up the value and authority in solr
|
||||
List<AuthorityValue> byValue = authorityValueService.findByValue(c, schema, element, qualifier, value);
|
||||
List<AuthorityValue> byValue = authorityValueService.findByValue(schema, element, qualifier, value);
|
||||
AuthorityValue authorityValue = null;
|
||||
if (byValue.isEmpty()) {
|
||||
String toGenerate = fromAuthority.generateString() + value;
|
||||
String field = schema + "_" + element + (StringUtils.isNotBlank(qualifier) ? "_" + qualifier : "");
|
||||
authorityValue = authorityValueService.generate(c, toGenerate, value, field);
|
||||
authorityValue = authorityValueService.generate(toGenerate, value, field);
|
||||
dcv.setAuthority(toGenerate);
|
||||
} else {
|
||||
authorityValue = byValue.get(0);
|
||||
@@ -1162,10 +1160,7 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
} else if (value == null || !value.contains(csv.getAuthoritySeparator())) {
|
||||
simplyCopyValue(value, dcv);
|
||||
} else {
|
||||
String[] parts = value.split(csv.getEscapedAuthoritySeparator());
|
||||
dcv.setValue(parts[0]);
|
||||
dcv.setAuthority(parts[1]);
|
||||
dcv.setConfidence((parts.length > 2 ? Integer.valueOf(parts[2]) : Choices.CF_ACCEPTED));
|
||||
resolveValueAndAuthority(value, dcv);
|
||||
}
|
||||
return dcv;
|
||||
}
|
||||
@@ -1176,6 +1171,35 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
dcv.setConfidence(Choices.CF_UNSET);
|
||||
}
|
||||
|
||||
private void resolveValueAndAuthority(String value, BulkEditMetadataValue dcv) {
|
||||
// Cells with valid authority are composed of three parts ~ <value>, <authority>, <confidence>
|
||||
// The value itself may also include the authority separator though
|
||||
String[] parts = value.split(csv.getEscapedAuthoritySeparator());
|
||||
|
||||
// If we don't have enough parts, assume the whole string is the value
|
||||
if (parts.length < 3) {
|
||||
simplyCopyValue(value, dcv);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// The last part of the cell must be a confidence value (integer)
|
||||
int confidence = Integer.parseInt(parts[parts.length - 1]);
|
||||
String authority = parts[parts.length - 2];
|
||||
String plainValue = String.join(
|
||||
csv.getAuthoritySeparator(),
|
||||
ArrayUtils.subarray(parts, 0, parts.length - 2)
|
||||
);
|
||||
|
||||
dcv.setValue(plainValue);
|
||||
dcv.setAuthority(authority);
|
||||
dcv.setConfidence(confidence);
|
||||
} catch (NumberFormatException e) {
|
||||
// Otherwise assume the whole string is the value
|
||||
simplyCopyValue(value, dcv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to find if a String occurs in an array of Strings
|
||||
*
|
||||
@@ -1368,10 +1392,10 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
/**
|
||||
* is the field is defined as authority controlled
|
||||
*/
|
||||
private static boolean isAuthorityControlledField(String md) {
|
||||
private boolean isAuthorityControlledField(String md) {
|
||||
String mdf = md.contains(":") ? StringUtils.substringAfter(md, ":") : md;
|
||||
mdf = StringUtils.substringBefore(mdf, "[");
|
||||
return authorityControlled.contains(mdf);
|
||||
return authorityControlled.contains(mdf) || authorityControlled.contains(md);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1802,5 +1826,4 @@ public class MetadataImport extends DSpaceRunnable<MetadataImportScriptConfigura
|
||||
String targetType, String originType, String originTypeName) {
|
||||
return RelationshipUtils.matchRelationshipType(relTypes, targetType, originType, originTypeName);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -9,9 +9,8 @@ package org.dspace.app.checker;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -149,7 +148,7 @@ public final class ChecksumChecker {
|
||||
+ " old results from the database.");
|
||||
}
|
||||
|
||||
Date processStart = Calendar.getInstance().getTime();
|
||||
Instant processStart = Instant.now();
|
||||
|
||||
BitstreamDispatcher dispatcher = null;
|
||||
|
||||
@@ -180,10 +179,8 @@ public final class ChecksumChecker {
|
||||
// run checker process for specified duration
|
||||
try {
|
||||
dispatcher = new LimitedDurationDispatcher(
|
||||
new SimpleDispatcher(context, processStart, true), new Date(
|
||||
System.currentTimeMillis()
|
||||
+ Utils.parseDuration(line
|
||||
.getOptionValue('d'))));
|
||||
new SimpleDispatcher(context, processStart, true), Instant.ofEpochMilli(
|
||||
Instant.now().toEpochMilli() + Utils.parseDuration(line.getOptionValue('d'))));
|
||||
} catch (Exception e) {
|
||||
LOG.fatal("Couldn't parse " + line.getOptionValue('d')
|
||||
+ " as a duration: ", e);
|
||||
|
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.client;
|
||||
|
||||
import static org.apache.commons.collections4.ListUtils.emptyIfNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.HttpResponseInterceptor;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Factory of {@link HttpClient} with common configurations.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class DSpaceHttpClientFactory {
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
private DSpaceProxyRoutePlanner proxyRoutePlanner;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<HttpRequestInterceptor> requestInterceptors;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<HttpResponseInterceptor> responseInterceptors;
|
||||
|
||||
/**
|
||||
* Get an instance of {@link DSpaceHttpClientFactory} from the Spring context.
|
||||
* @return the bean instance
|
||||
*/
|
||||
public static DSpaceHttpClientFactory getInstance() {
|
||||
return new DSpace().getSingletonService(DSpaceHttpClientFactory.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance of {@link HttpClient} setting the proxy if configured.
|
||||
*
|
||||
* @return the client
|
||||
*/
|
||||
public CloseableHttpClient build() {
|
||||
return build(HttpClientBuilder.create(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* return a Builder if an instance of {@link HttpClient} pre-setting the proxy if configured.
|
||||
*
|
||||
* @return the client
|
||||
*/
|
||||
public HttpClientBuilder builder(boolean setProxy) {
|
||||
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
|
||||
if (setProxy) {
|
||||
clientBuilder.setRoutePlanner(proxyRoutePlanner);
|
||||
}
|
||||
getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
|
||||
getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
|
||||
return clientBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance of {@link HttpClient} without setting the proxy, even if
|
||||
* configured.
|
||||
*
|
||||
* @return the client
|
||||
*/
|
||||
public CloseableHttpClient buildWithoutProxy() {
|
||||
return build(HttpClientBuilder.create(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance of {@link HttpClient} setting the proxy if configured,
|
||||
* disabling automatic retries and setting the maximum total connection.
|
||||
*
|
||||
* @param maxConnTotal the maximum total connection value
|
||||
* @return the client
|
||||
*/
|
||||
public CloseableHttpClient buildWithoutAutomaticRetries(int maxConnTotal) {
|
||||
HttpClientBuilder clientBuilder = HttpClientBuilder.create()
|
||||
.disableAutomaticRetries()
|
||||
.setMaxConnTotal(maxConnTotal);
|
||||
return build(clientBuilder, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an instance of {@link HttpClient} setting the proxy if configured with
|
||||
* the given request configuration.
|
||||
* @param requestConfig the request configuration
|
||||
* @return the client
|
||||
*/
|
||||
public CloseableHttpClient buildWithRequestConfig(RequestConfig requestConfig) {
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
|
||||
.setDefaultRequestConfig(requestConfig);
|
||||
return build(httpClientBuilder, true);
|
||||
}
|
||||
|
||||
private CloseableHttpClient build(HttpClientBuilder clientBuilder, boolean setProxy) {
|
||||
if (setProxy) {
|
||||
clientBuilder.setRoutePlanner(proxyRoutePlanner);
|
||||
}
|
||||
getRequestInterceptors().forEach(clientBuilder::addInterceptorLast);
|
||||
getResponseInterceptors().forEach(clientBuilder::addInterceptorLast);
|
||||
return clientBuilder.build();
|
||||
}
|
||||
|
||||
public ConfigurationService getConfigurationService() {
|
||||
return configurationService;
|
||||
}
|
||||
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
public List<HttpRequestInterceptor> getRequestInterceptors() {
|
||||
return emptyIfNull(requestInterceptors);
|
||||
}
|
||||
|
||||
public void setRequestInterceptors(List<HttpRequestInterceptor> requestInterceptors) {
|
||||
this.requestInterceptors = requestInterceptors;
|
||||
}
|
||||
|
||||
public List<HttpResponseInterceptor> getResponseInterceptors() {
|
||||
return emptyIfNull(responseInterceptors);
|
||||
}
|
||||
|
||||
public void setResponseInterceptors(List<HttpResponseInterceptor> responseInterceptors) {
|
||||
this.responseInterceptors = responseInterceptors;
|
||||
}
|
||||
|
||||
public DSpaceProxyRoutePlanner getProxyRoutePlanner() {
|
||||
return proxyRoutePlanner;
|
||||
}
|
||||
|
||||
public void setProxyRoutePlanner(DSpaceProxyRoutePlanner proxyRoutePlanner) {
|
||||
this.proxyRoutePlanner = proxyRoutePlanner;
|
||||
}
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.impl.conn.DefaultRoutePlanner;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
|
||||
/**
|
||||
* Extension of {@link DefaultRoutePlanner} that determine the proxy based on
|
||||
* the configuration service, ignoring configured hosts.
|
||||
*
|
||||
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
|
||||
*
|
||||
*/
|
||||
public class DSpaceProxyRoutePlanner extends DefaultRoutePlanner {
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
public DSpaceProxyRoutePlanner(ConfigurationService configurationService) {
|
||||
super(null);
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context) throws HttpException {
|
||||
if (isTargetHostConfiguredToBeIgnored(target)) {
|
||||
return null;
|
||||
}
|
||||
String proxyHost = configurationService.getProperty("http.proxy.host");
|
||||
String proxyPort = configurationService.getProperty("http.proxy.port");
|
||||
if (StringUtils.isAnyBlank(proxyHost, proxyPort)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new HttpHost(proxyHost, Integer.parseInt(proxyPort), "http");
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("Invalid proxy port configuration: " + proxyPort);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isTargetHostConfiguredToBeIgnored(HttpHost target) {
|
||||
String[] hostsToIgnore = configurationService.getArrayProperty("http.proxy.hosts-to-ignore");
|
||||
if (ArrayUtils.isEmpty(hostsToIgnore)) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(hostsToIgnore)
|
||||
.anyMatch(host -> matchesHost(host, target.getHostName()));
|
||||
}
|
||||
|
||||
private boolean matchesHost(String hostPattern, String hostName) {
|
||||
if (hostName.equals(hostPattern)) {
|
||||
return true;
|
||||
} else if (hostPattern.startsWith("*")) {
|
||||
return hostName.endsWith(StringUtils.removeStart(hostPattern, "*"));
|
||||
} else if (hostPattern.endsWith("*")) {
|
||||
return hostName.startsWith(StringUtils.removeEnd(hostPattern, "*"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -18,10 +18,11 @@ import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.SQLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -678,7 +679,7 @@ public class ItemExportServiceImpl implements ItemExportService {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
String fileName = assembleFileName("item", eperson,
|
||||
new Date());
|
||||
LocalDate.now());
|
||||
String workParentDir = getExportWorkDirectory()
|
||||
+ System.getProperty("file.separator")
|
||||
+ fileName;
|
||||
@@ -750,16 +751,16 @@ public class ItemExportServiceImpl implements ItemExportService {
|
||||
|
||||
@Override
|
||||
public String assembleFileName(String type, EPerson eperson,
|
||||
Date date) throws Exception {
|
||||
LocalDate date) throws Exception {
|
||||
// to format the date
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MMM_dd");
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MMM_dd");
|
||||
String downloadDir = getExportDownloadDirectory(eperson);
|
||||
// used to avoid name collision
|
||||
int count = 1;
|
||||
boolean exists = true;
|
||||
String fileName = null;
|
||||
while (exists) {
|
||||
fileName = type + "_export_" + sdf.format(date) + "_" + count + "_"
|
||||
fileName = type + "_export_" + formatter.format(date) + "_" + count + "_"
|
||||
+ eperson.getID();
|
||||
exists = new File(downloadDir
|
||||
+ System.getProperty("file.separator") + fileName + ".zip")
|
||||
@@ -915,14 +916,12 @@ public class ItemExportServiceImpl implements ItemExportService {
|
||||
public void deleteOldExportArchives(EPerson eperson) throws Exception {
|
||||
int hours = configurationService
|
||||
.getIntProperty("org.dspace.app.itemexport.life.span.hours");
|
||||
Calendar now = Calendar.getInstance();
|
||||
now.setTime(new Date());
|
||||
now.add(Calendar.HOUR, -hours);
|
||||
Instant modifiedTime = Instant.now().minus(hours, ChronoUnit.HOURS);
|
||||
File downloadDir = new File(getExportDownloadDirectory(eperson));
|
||||
if (downloadDir.exists()) {
|
||||
File[] files = downloadDir.listFiles();
|
||||
for (File file : files) {
|
||||
if (file.lastModified() < now.getTimeInMillis()) {
|
||||
if (file.lastModified() < modifiedTime.toEpochMilli()) {
|
||||
if (!file.delete()) {
|
||||
logError("Unable to delete export file");
|
||||
}
|
||||
@@ -935,9 +934,7 @@ public class ItemExportServiceImpl implements ItemExportService {
|
||||
@Override
|
||||
public void deleteOldExportArchives() throws Exception {
|
||||
int hours = configurationService.getIntProperty("org.dspace.app.itemexport.life.span.hours");
|
||||
Calendar now = Calendar.getInstance();
|
||||
now.setTime(new Date());
|
||||
now.add(Calendar.HOUR, -hours);
|
||||
Instant modifiedTime = Instant.now().minus(hours, ChronoUnit.HOURS);
|
||||
File downloadDir = new File(configurationService.getProperty("org.dspace.app.itemexport.download.dir"));
|
||||
if (downloadDir.exists()) {
|
||||
// Get a list of all the sub-directories, potentially one for each ePerson.
|
||||
@@ -946,7 +943,7 @@ public class ItemExportServiceImpl implements ItemExportService {
|
||||
// For each sub-directory delete any old files.
|
||||
File[] files = dir.listFiles();
|
||||
for (File file : files) {
|
||||
if (file.lastModified() < now.getTimeInMillis()) {
|
||||
if (file.lastModified() < modifiedTime.toEpochMilli()) {
|
||||
if (!file.delete()) {
|
||||
logError("Unable to delete old files");
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
package org.dspace.app.itemexport.service;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -130,7 +130,7 @@ public interface ItemExportService {
|
||||
* @throws Exception if error
|
||||
*/
|
||||
public String assembleFileName(String type, EPerson eperson,
|
||||
Date date) throws Exception;
|
||||
LocalDate date) throws Exception;
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -11,11 +11,9 @@ import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -23,7 +21,7 @@ import java.util.List;
|
||||
*/
|
||||
public class BatchUpload {
|
||||
|
||||
private Date date;
|
||||
private Instant date;
|
||||
private File dir;
|
||||
private boolean successful;
|
||||
private int itemsImported;
|
||||
@@ -65,9 +63,7 @@ public class BatchUpload {
|
||||
|
||||
String dirName = dir.getName();
|
||||
long timeMillis = Long.parseLong(dirName);
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
calendar.setTimeInMillis(timeMillis);
|
||||
this.date = calendar.getTime();
|
||||
this.date = Instant.ofEpochMilli(timeMillis);
|
||||
|
||||
try {
|
||||
this.itemsImported = countLines(dir + File.separator + "mapfile");
|
||||
@@ -149,7 +145,7 @@ public class BatchUpload {
|
||||
*
|
||||
* @return Date
|
||||
*/
|
||||
public Date getDate() {
|
||||
public Instant getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
@@ -190,14 +186,12 @@ public class BatchUpload {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formatted date (DD/MM/YY)
|
||||
* Get formatted date (YYYY-MM-DDThh:mm:ssZ)
|
||||
*
|
||||
* @return date as string
|
||||
*/
|
||||
public String getDateFormatted() {
|
||||
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm");
|
||||
|
||||
return df.format(date);
|
||||
return DateTimeFormatter.ISO_INSTANT.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -14,8 +14,9 @@ import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
@@ -156,7 +157,7 @@ public class ItemImport extends DSpaceRunnable<ItemImportScriptConfiguration> {
|
||||
return;
|
||||
}
|
||||
|
||||
Date startTime = new Date();
|
||||
Instant startTime = Instant.now();
|
||||
Context context = new Context(Context.Mode.BATCH_EDIT);
|
||||
|
||||
setMapFile();
|
||||
@@ -254,12 +255,12 @@ public class ItemImport extends DSpaceRunnable<ItemImportScriptConfiguration> {
|
||||
}
|
||||
}
|
||||
|
||||
Date endTime = new Date();
|
||||
handler.logInfo("Started: " + startTime.getTime());
|
||||
handler.logInfo("Ended: " + endTime.getTime());
|
||||
Instant endTime = Instant.now();
|
||||
handler.logInfo("Started: " + DateTimeFormatter.ISO_INSTANT.format(startTime));
|
||||
handler.logInfo("Ended: " + DateTimeFormatter.ISO_INSTANT.format(endTime));
|
||||
handler.logInfo(
|
||||
"Elapsed time: " + ((endTime.getTime() - startTime.getTime()) / 1000) + " secs (" + (endTime
|
||||
.getTime() - startTime.getTime()) + " msecs)");
|
||||
"Elapsed time: " + ((endTime.toEpochMilli() - startTime.toEpochMilli()) / 1000) + " secs (" +
|
||||
(endTime.toEpochMilli() - startTime.toEpochMilli()) + " msecs)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -29,13 +29,15 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.sql.SQLException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -47,7 +49,6 @@ import java.util.UUID;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.xpath.XPath;
|
||||
@@ -67,6 +68,7 @@ import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.itemimport.service.ItemImportService;
|
||||
import org.dspace.app.util.LocalSchemaFilenameFilter;
|
||||
import org.dspace.app.util.RelationshipUtils;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
@@ -179,6 +181,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
@Autowired(required = true)
|
||||
protected MetadataValueService metadataValueService;
|
||||
|
||||
protected DocumentBuilder builder;
|
||||
|
||||
protected String tempWorkDir;
|
||||
|
||||
protected boolean isTest = false;
|
||||
@@ -742,15 +746,22 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
myitem = wi.getItem();
|
||||
}
|
||||
|
||||
// normalize and validate path to make sure itemname doesn't contain path traversal
|
||||
Path itemPath = new File(path + File.separatorChar + itemname + File.separatorChar)
|
||||
.toPath().normalize();
|
||||
if (!itemPath.startsWith(path)) {
|
||||
throw new IOException("Illegal item metadata path: '" + itemPath);
|
||||
}
|
||||
// Normalization chops off the last separator, and we need to put it back
|
||||
String itemPathDir = itemPath.toString() + File.separatorChar;
|
||||
|
||||
// now fill out dublin core for item
|
||||
loadMetadata(c, myitem, path + File.separatorChar + itemname
|
||||
+ File.separatorChar);
|
||||
loadMetadata(c, myitem, itemPathDir);
|
||||
|
||||
// and the bitstreams from the contents file
|
||||
// process contents file, add bistreams and bundles, return any
|
||||
// non-standard permissions
|
||||
List<String> options = processContentsFile(c, myitem, path
|
||||
+ File.separatorChar + itemname, "contents");
|
||||
List<String> options = processContentsFile(c, myitem, itemPathDir, "contents");
|
||||
|
||||
if (useWorkflow) {
|
||||
// don't process handle file
|
||||
@@ -768,8 +779,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
}
|
||||
} else {
|
||||
// only process handle file if not using workflow system
|
||||
String myhandle = processHandleFile(c, myitem, path
|
||||
+ File.separatorChar + itemname, "handle");
|
||||
String myhandle = processHandleFile(c, myitem, itemPathDir, "handle");
|
||||
|
||||
// put item in system
|
||||
if (!isTest) {
|
||||
@@ -1001,6 +1011,34 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures a file path does not attempt to access files outside the designated parent directory.
|
||||
*
|
||||
* @param parentDir The absolute path to the parent directory that should contain the file
|
||||
* @param fileName The name or path of the file to validate
|
||||
* @throws IOException If an error occurs while resolving canonical paths, or the file path attempts
|
||||
* to access a location outside the parent directory
|
||||
*/
|
||||
private void validateFilePath(String parentDir, String fileName) throws IOException {
|
||||
File parent = new File(parentDir);
|
||||
File file = new File(fileName);
|
||||
|
||||
// If the fileName is not an absolute path, we resolve it against the parentDir
|
||||
if (!file.isAbsolute()) {
|
||||
file = new File(parent, fileName);
|
||||
}
|
||||
|
||||
String parentCanonicalPath = parent.getCanonicalPath();
|
||||
String fileCanonicalPath = file.getCanonicalPath();
|
||||
|
||||
if (!fileCanonicalPath.startsWith(parentCanonicalPath)) {
|
||||
log.error("File path outside of canonical root requested: fileCanonicalPath={} does not begin " +
|
||||
"with parentCanonicalPath={}", fileCanonicalPath, parentCanonicalPath);
|
||||
throw new IOException("Illegal file path '" + fileName + "' encountered. This references a path " +
|
||||
"outside of the import package. Please see the system logs for more details.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the collections file inside the item directory. If there
|
||||
* is one and it is not empty return a list of collections in
|
||||
@@ -1201,6 +1239,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
sDescription = sDescription.replaceFirst("description:", "");
|
||||
}
|
||||
|
||||
validateFilePath(path, sFilePath);
|
||||
registerBitstream(c, i, iAssetstore, sFilePath, sBundle, sDescription);
|
||||
logInfo("\tRegistering Bitstream: " + sFilePath
|
||||
+ "\tAssetstore: " + iAssetstore
|
||||
@@ -1414,6 +1453,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
return;
|
||||
}
|
||||
|
||||
validateFilePath(path, fileName);
|
||||
String fullpath = path + File.separatorChar + fileName;
|
||||
|
||||
// get an input stream
|
||||
@@ -1425,11 +1465,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
|
||||
if (bundleName == null) {
|
||||
// is it license.txt?
|
||||
if ("license.txt".equals(fileName)) {
|
||||
newBundleName = "LICENSE";
|
||||
if (Constants.LICENSE_BITSTREAM_NAME.equals(fileName)) {
|
||||
newBundleName = Constants.LICENSE_BUNDLE_NAME;
|
||||
} else {
|
||||
// call it ORIGINAL
|
||||
newBundleName = "ORIGINAL";
|
||||
newBundleName = Constants.CONTENT_BUNDLE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1493,11 +1533,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
|
||||
if (StringUtils.isBlank(bundleName)) {
|
||||
// is it license.txt?
|
||||
if (bitstreamPath.endsWith("license.txt")) {
|
||||
newBundleName = "LICENSE";
|
||||
if (bitstreamPath.endsWith(Constants.LICENSE_BITSTREAM_NAME)) {
|
||||
newBundleName = Constants.LICENSE_BUNDLE_NAME;
|
||||
} else {
|
||||
// call it ORIGINAL
|
||||
newBundleName = "ORIGINAL";
|
||||
newBundleName = Constants.CONTENT_BUNDLE_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1888,9 +1928,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
*/
|
||||
protected Document loadXML(String filename) throws IOException,
|
||||
ParserConfigurationException, SAXException {
|
||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
||||
.newDocumentBuilder();
|
||||
|
||||
DocumentBuilder builder = XMLUtils.getDocumentBuilder();
|
||||
return builder.parse(new File(filename));
|
||||
}
|
||||
|
||||
@@ -2039,8 +2077,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
*/
|
||||
protected String generateRandomFilename(boolean hidden) {
|
||||
String filename = String.format("%s", RandomStringUtils.randomAlphanumeric(8));
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmm");
|
||||
String datePart = sdf.format(new Date());
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm");
|
||||
String datePart = formatter.format(LocalDateTime.now(ZoneOffset.UTC));
|
||||
filename = datePart + "_" + filename;
|
||||
|
||||
return filename;
|
||||
@@ -2102,8 +2140,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
|
||||
"org.dspace.app.batchitemimport.work.dir") + File.separator + "batchuploads" + File.separator
|
||||
+ context
|
||||
.getCurrentUser()
|
||||
.getID() + File.separator + (isResume ? theResumeDir : (new GregorianCalendar())
|
||||
.getTimeInMillis());
|
||||
.getID() + File.separator + (isResume ? theResumeDir : Instant.now().toEpochMilli());
|
||||
File importDirFile = new File(importDir);
|
||||
if (!importDirFile.exists()) {
|
||||
boolean success = importDirFile.mkdirs();
|
||||
|
@@ -27,6 +27,7 @@ import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.BitstreamFormatService;
|
||||
import org.dspace.content.service.InstallItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
@@ -138,10 +139,10 @@ public class AddBitstreamsAction extends UpdateBitstreamsAction {
|
||||
String newBundleName = ce.bundlename;
|
||||
|
||||
if (ce.bundlename == null) { // should be required but default convention established
|
||||
if (ce.filename.equals("license.txt")) {
|
||||
newBundleName = "LICENSE";
|
||||
if (ce.filename.equals(Constants.LICENSE_BITSTREAM_NAME)) {
|
||||
newBundleName = Constants.LICENSE_BUNDLE_NAME;
|
||||
} else {
|
||||
newBundleName = "ORIGINAL";
|
||||
newBundleName = Constants.CONTENT_BUNDLE_NAME;
|
||||
}
|
||||
}
|
||||
ItemUpdate.pr(" Bitstream " + ce.filename + " to be added to bundle: " + newBundleName);
|
||||
|
@@ -23,8 +23,6 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
@@ -33,6 +31,7 @@ import javax.xml.transform.TransformerFactory;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.LocalSchemaFilenameFilter;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
@@ -52,7 +51,6 @@ public class ItemArchive {
|
||||
|
||||
public static final String DUBLIN_CORE_XML = "dublin_core.xml";
|
||||
|
||||
protected static DocumentBuilder builder = null;
|
||||
protected Transformer transformer = null;
|
||||
|
||||
protected List<DtoMetadata> dtomList = null;
|
||||
@@ -95,14 +93,14 @@ public class ItemArchive {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(new File(dir, DUBLIN_CORE_XML));
|
||||
itarch.dtomList = MetadataUtilities.loadDublinCore(getDocumentBuilder(), is);
|
||||
itarch.dtomList = MetadataUtilities.loadDublinCore(XMLUtils.getDocumentBuilder(), is);
|
||||
|
||||
//The code to search for local schema files was copied from org.dspace.app.itemimport
|
||||
// .ItemImportServiceImpl.java
|
||||
File file[] = dir.listFiles(new LocalSchemaFilenameFilter());
|
||||
for (int i = 0; i < file.length; i++) {
|
||||
is = new FileInputStream(file[i]);
|
||||
itarch.dtomList.addAll(MetadataUtilities.loadDublinCore(getDocumentBuilder(), is));
|
||||
itarch.dtomList.addAll(MetadataUtilities.loadDublinCore(XMLUtils.getDocumentBuilder(), is));
|
||||
}
|
||||
} finally {
|
||||
if (is != null) {
|
||||
@@ -126,14 +124,6 @@ public class ItemArchive {
|
||||
return itarch;
|
||||
}
|
||||
|
||||
protected static DocumentBuilder getDocumentBuilder()
|
||||
throws ParserConfigurationException {
|
||||
if (builder == null) {
|
||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for Transformer
|
||||
*
|
||||
@@ -318,7 +308,7 @@ public class ItemArchive {
|
||||
|
||||
try {
|
||||
out = new FileOutputStream(new File(dir, "dublin_core.xml"));
|
||||
Document doc = MetadataUtilities.writeDublinCore(getDocumentBuilder(), undoDtomList);
|
||||
Document doc = MetadataUtilities.writeDublinCore(XMLUtils.getDocumentBuilder(), undoDtomList);
|
||||
MetadataUtilities.writeDocument(doc, getTransformer(), out);
|
||||
|
||||
// if undo has delete bitstream
|
||||
|
@@ -14,9 +14,9 @@ import java.io.FileWriter;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -332,7 +332,7 @@ public class ItemUpdate {
|
||||
}
|
||||
}
|
||||
|
||||
pr("ItemUpdate - initializing run on " + (new Date()).toString());
|
||||
pr("ItemUpdate - initializing run on " + (Instant.now()).toString());
|
||||
|
||||
context = new Context(Context.Mode.BATCH_EDIT);
|
||||
iu.setEPerson(context, iu.eperson);
|
||||
|
@@ -19,6 +19,7 @@ import java.util.TreeMap;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.scripts.DSpaceRunnable.StepResult;
|
||||
@@ -314,7 +315,7 @@ public class ScriptLauncher {
|
||||
String config = kernelImpl.getConfigurationService().getProperty("dspace.dir") +
|
||||
System.getProperty("file.separator") + "config" +
|
||||
System.getProperty("file.separator") + "launcher.xml";
|
||||
SAXBuilder saxBuilder = new SAXBuilder();
|
||||
SAXBuilder saxBuilder = XMLUtils.getSAXBuilder();
|
||||
Document doc = null;
|
||||
try {
|
||||
doc = saxBuilder.build(config);
|
||||
|
@@ -11,9 +11,9 @@ import static java.lang.String.format;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@@ -21,7 +21,6 @@ import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -48,6 +47,10 @@ import org.dspace.event.Event;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
import org.dspace.versioning.factory.VersionServiceFactory;
|
||||
import org.dspace.versioning.service.VersionHistoryService;
|
||||
import org.dspace.web.ContextUtil;
|
||||
|
||||
/**
|
||||
@@ -63,6 +66,9 @@ public class LDNMessageConsumer implements Consumer {
|
||||
private ConfigurationService configurationService;
|
||||
private ItemService itemService;
|
||||
private BitstreamService bitstreamService;
|
||||
private final String RESUBMISSION_SUFFIX = "-resubmission";
|
||||
private final String ENDORSEMENT_PATTERN = "request-endorsement";
|
||||
private final String REVIEW_PATTERN = "request-review";
|
||||
|
||||
@Override
|
||||
public void initialize() throws Exception {
|
||||
@@ -83,6 +89,9 @@ public class LDNMessageConsumer implements Consumer {
|
||||
}
|
||||
|
||||
Item item = (Item) event.getSubject(context);
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
createManualLDNMessages(context, item);
|
||||
createAutomaticLDNMessages(context, item);
|
||||
}
|
||||
@@ -90,10 +99,24 @@ public class LDNMessageConsumer implements Consumer {
|
||||
private void createManualLDNMessages(Context context, Item item) throws SQLException, JsonProcessingException {
|
||||
List<NotifyPatternToTrigger> patternsToTrigger =
|
||||
notifyPatternToTriggerService.findByItem(context, item);
|
||||
// Note that multiple patterns can be submitted and not all support resubmission
|
||||
// 1. Extract all patterns that accept resubmissions, i.e. endorsement and review
|
||||
List<Integer> patternsSupportingResubmission = patternsToTrigger.stream()
|
||||
.filter(p -> p.getPattern().equals(REVIEW_PATTERN) || p.getPattern().equals(ENDORSEMENT_PATTERN))
|
||||
.map(NotifyPatternToTrigger::getID).toList();
|
||||
|
||||
String resubmissionReplyToID = null;
|
||||
|
||||
for (NotifyPatternToTrigger patternToTrigger : patternsToTrigger) {
|
||||
// Only try to fetch resubmission ID if the pattern support resubmission
|
||||
if (patternsSupportingResubmission.contains(patternToTrigger.getID())) {
|
||||
resubmissionReplyToID = findResubmissionReplyToUUID(context, item, patternToTrigger.getNotifyService());
|
||||
}
|
||||
|
||||
createLDNMessage(context,patternToTrigger.getItem(),
|
||||
patternToTrigger.getNotifyService(), patternToTrigger.getPattern());
|
||||
patternToTrigger.getNotifyService(),
|
||||
patternToTrigger.getPattern(),
|
||||
resubmissionReplyToID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,11 +127,33 @@ public class LDNMessageConsumer implements Consumer {
|
||||
for (NotifyServiceInboundPattern inboundPattern : inboundPatterns) {
|
||||
if (StringUtils.isEmpty(inboundPattern.getConstraint()) ||
|
||||
evaluateFilter(context, item, inboundPattern.getConstraint())) {
|
||||
createLDNMessage(context, item, inboundPattern.getNotifyService(), inboundPattern.getPattern());
|
||||
createLDNMessage(context, item, inboundPattern.getNotifyService(),
|
||||
inboundPattern.getPattern(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String findResubmissionReplyToUUID(Context context, Item item, NotifyServiceEntity service)
|
||||
throws SQLException {
|
||||
// 1.1 Check whether this is a new version submission
|
||||
VersionHistoryService versionHistoryService = VersionServiceFactory.getInstance()
|
||||
.getVersionHistoryService();
|
||||
VersionHistory versionHistory = versionHistoryService.findByItem(context, item);
|
||||
|
||||
if (versionHistory != null) {
|
||||
Version currentVersion = versionHistoryService.getVersion(context, versionHistory, item);
|
||||
Version previousVersion = versionHistoryService.getPrevious(context, versionHistory, currentVersion);
|
||||
if (previousVersion != null) {
|
||||
// 1.2 and a TentativeReject notification, matching the current pattern's service, was received for the
|
||||
// previous item version
|
||||
return ldnMessageService.findEndorsementOrReviewResubmissionIdByItem(context,
|
||||
previousVersion.getItem(), service);
|
||||
}
|
||||
}
|
||||
// New submission (new item, or previous version with a tentativeReject notification not found)
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean evaluateFilter(Context context, Item item, String constraint) {
|
||||
LogicalStatement filter =
|
||||
new DSpace().getServiceManager().getServiceByName(constraint, LogicalStatement.class);
|
||||
@@ -116,19 +161,37 @@ public class LDNMessageConsumer implements Consumer {
|
||||
return filter != null && filter.getResult(context, item);
|
||||
}
|
||||
|
||||
private void createLDNMessage(Context context, Item item, NotifyServiceEntity service, String pattern)
|
||||
throws SQLException, JsonMappingException, JsonProcessingException {
|
||||
|
||||
LDN ldn = getLDNMessage(pattern);
|
||||
private void createLDNMessage(Context context, Item item, NotifyServiceEntity service, String pattern,
|
||||
String resubmissionID)
|
||||
throws SQLException, JsonProcessingException {
|
||||
// Amend current pattern name to trigger
|
||||
// Endorsement or Review offer resubmissions: append '-resubmission' to pattern name to choose the correct
|
||||
// LDN message template: e.g. request-endorsement-resubmission or request-review-resubmission
|
||||
LDN ldn = (resubmissionID != null)
|
||||
? getLDNMessage(pattern + RESUBMISSION_SUFFIX) : getLDNMessage(pattern);
|
||||
LDNMessageEntity ldnMessage =
|
||||
ldnMessageService.create(context, format("urn:uuid:%s", UUID.randomUUID()));
|
||||
ldnMessageService.create(context, format("urn:uuid:%s", UUID.randomUUID()));
|
||||
|
||||
ldnMessage.setObject(item);
|
||||
ldnMessage.setTarget(service);
|
||||
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_QUEUED);
|
||||
ldnMessage.setQueueTimeout(new Date());
|
||||
ldnMessage.setQueueTimeout(Instant.now());
|
||||
|
||||
appendGeneratedMessage(ldn, ldnMessage, pattern);
|
||||
String actorID = null;
|
||||
if (service.isUsesActorEmailId()) {
|
||||
// If the service has been configured to use actorEmailId, we use the submitter's email and name
|
||||
if (item.getSubmitter() != null) {
|
||||
actorID = item.getSubmitter().getEmail();
|
||||
} else {
|
||||
// Use configured fallback email (defaults to mail.admin property)
|
||||
actorID = configurationService.getProperty("ldn.notification.email.submitter.fallback");
|
||||
}
|
||||
}
|
||||
appendGeneratedMessage(ldn,
|
||||
ldnMessage,
|
||||
actorID,
|
||||
(actorID != null && item.getSubmitter() != null) ? item.getSubmitter().getFullName() : null,
|
||||
resubmissionID);
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Notification notification = mapper.readValue(ldnMessage.getMessage(), Notification.class);
|
||||
@@ -139,6 +202,10 @@ public class LDNMessageConsumer implements Consumer {
|
||||
Collections.sort(notificationTypeArrayList);
|
||||
ldnMessage.setActivityStreamType(notificationTypeArrayList.get(0));
|
||||
ldnMessage.setCoarNotifyType(notificationTypeArrayList.get(1));
|
||||
// If a resubmission, set inReplyTo
|
||||
if (resubmissionID != null) {
|
||||
ldnMessage.setInReplyTo(ldnMessageService.find(context, resubmissionID));
|
||||
}
|
||||
|
||||
ldnMessageService.update(context, ldnMessage);
|
||||
}
|
||||
@@ -151,11 +218,16 @@ public class LDNMessageConsumer implements Consumer {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendGeneratedMessage(LDN ldn, LDNMessageEntity ldnMessage, String pattern) {
|
||||
private void appendGeneratedMessage(LDN ldn, LDNMessageEntity ldnMessage, String actorID, String actorName,
|
||||
String resubmissionId) {
|
||||
Item item = (Item) ldnMessage.getObject();
|
||||
ldn.addArgument(getUiUrl());
|
||||
if (actorID != null) {
|
||||
ldn.addArgument("mailto:" + actorID);
|
||||
} else {
|
||||
ldn.addArgument(getUiUrl());
|
||||
}
|
||||
ldn.addArgument(configurationService.getProperty("ldn.notify.inbox"));
|
||||
ldn.addArgument(configurationService.getProperty("dspace.name"));
|
||||
ldn.addArgument(actorName != null ? actorName : configurationService.getProperty("dspace.name"));
|
||||
ldn.addArgument(Objects.requireNonNullElse(ldnMessage.getTarget().getUrl(), ""));
|
||||
ldn.addArgument(Objects.requireNonNullElse(ldnMessage.getTarget().getLdnUrl(), ""));
|
||||
ldn.addArgument(getUiUrl() + "/handle/" + ldnMessage.getObject().getHandle());
|
||||
@@ -166,6 +238,17 @@ public class LDNMessageConsumer implements Consumer {
|
||||
ldn.addArgument(getRelationUri(item));
|
||||
ldn.addArgument("http://purl.org/vocab/frbr/core#supplement");
|
||||
ldn.addArgument(format("urn:uuid:%s", UUID.randomUUID()));
|
||||
if (actorID != null) {
|
||||
ldn.addArgument("Person");
|
||||
} else {
|
||||
ldn.addArgument("Service");
|
||||
}
|
||||
// Param 14: UI URL, LDN message origin
|
||||
ldn.addArgument(getUiUrl());
|
||||
// Param 15: inReplyTo ID, used in endorsement resubmission notifications
|
||||
if (resubmissionId != null) {
|
||||
ldn.addArgument(String.format("\"inReplyTo\": \"%s\",", resubmissionId));
|
||||
}
|
||||
|
||||
ldnMessage.setMessage(ldn.generateLDNMessage());
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
package org.dspace.app.ldn;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
@@ -16,10 +16,10 @@ import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
/**
|
||||
* Class representing ldnMessages stored in the DSpace system and, when locally resolvable,
|
||||
@@ -100,13 +100,11 @@ public class LDNMessageEntity implements ReloadableEntity<String> {
|
||||
@Column(name = "queue_attempts")
|
||||
private Integer queueAttempts = 0;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "queue_last_start_time")
|
||||
private Date queueLastStartTime = null;
|
||||
private Instant queueLastStartTime = null;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name = "queue_timeout")
|
||||
private Date queueTimeout = null;
|
||||
private Instant queueTimeout = null;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "origin", referencedColumnName = "id")
|
||||
@@ -259,19 +257,19 @@ public class LDNMessageEntity implements ReloadableEntity<String> {
|
||||
this.queueAttempts = queueAttempts;
|
||||
}
|
||||
|
||||
public Date getQueueLastStartTime() {
|
||||
public Instant getQueueLastStartTime() {
|
||||
return queueLastStartTime;
|
||||
}
|
||||
|
||||
public void setQueueLastStartTime(Date queueLastStartTime) {
|
||||
public void setQueueLastStartTime(Instant queueLastStartTime) {
|
||||
this.queueLastStartTime = queueLastStartTime;
|
||||
}
|
||||
|
||||
public Date getQueueTimeout() {
|
||||
public Instant getQueueTimeout() {
|
||||
return queueTimeout;
|
||||
}
|
||||
|
||||
public void setQueueTimeout(Date queueTimeout) {
|
||||
public void setQueueTimeout(Instant queueTimeout) {
|
||||
this.queueTimeout = queueTimeout;
|
||||
}
|
||||
|
||||
@@ -289,7 +287,11 @@ public class LDNMessageEntity implements ReloadableEntity<String> {
|
||||
}
|
||||
|
||||
public static String getNotificationType(LDNMessageEntity ldnMessage) {
|
||||
if (ldnMessage.getInReplyTo() != null || ldnMessage.getOrigin() != null) {
|
||||
// Resubmission outgoing notifications have the inReplyTo, therefore it cannot be used to determine
|
||||
// whether a notification is incoming
|
||||
ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
if (ldnMessage.getOrigin() != null && !ldnMessage.getOrigin().getLdnUrl()
|
||||
.contains(configurationService.getProperty("dspace.ui.url"))) {
|
||||
return TYPE_INCOMING;
|
||||
}
|
||||
return TYPE_OUTGOING;
|
||||
|
@@ -54,6 +54,9 @@ public class NotifyServiceEntity implements ReloadableEntity<Integer> {
|
||||
@Column(name = "enabled")
|
||||
private boolean enabled = false;
|
||||
|
||||
@Column(name = "uses_actor_email_id")
|
||||
private boolean usesActorEmailId = false;
|
||||
|
||||
@Column(name = "score")
|
||||
private BigDecimal score;
|
||||
|
||||
@@ -129,6 +132,14 @@ public class NotifyServiceEntity implements ReloadableEntity<Integer> {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isUsesActorEmailId() {
|
||||
return usesActorEmailId;
|
||||
}
|
||||
|
||||
public void setUsesActorEmailId(boolean usesActorEmailId) {
|
||||
this.usesActorEmailId = usesActorEmailId;
|
||||
}
|
||||
|
||||
public BigDecimal getScore() {
|
||||
return score;
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.app.ldn.action;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@@ -73,8 +73,7 @@ public class LDNCorrectionAction implements LDNAction {
|
||||
qaEvent = new QAEvent(QAEvent.COAR_NOTIFY_SOURCE,
|
||||
handleService.findHandle(context, item), item.getID().toString(), itemName,
|
||||
this.getQaEventTopic(), doubleScoreValue,
|
||||
mapper.writeValueAsString(message),
|
||||
new Date());
|
||||
mapper.writeValueAsString(message), Instant.now());
|
||||
qaEventService.store(context, qaEvent);
|
||||
result = LDNActionStatus.CONTINUE;
|
||||
}
|
||||
|
@@ -9,9 +9,8 @@ package org.dspace.app.ldn.action;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -34,8 +33,6 @@ public class LDNEmailAction implements LDNAction {
|
||||
|
||||
private static final Logger log = LogManager.getLogger(LDNEmailAction.class);
|
||||
|
||||
private final static String DATE_PATTERN = "dd-MM-yyyy HH:mm:ss";
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@@ -80,7 +77,7 @@ public class LDNEmailAction implements LDNAction {
|
||||
email.addRecipient(recipient);
|
||||
}
|
||||
|
||||
String date = new SimpleDateFormat(DATE_PATTERN).format(Calendar.getInstance().getTime());
|
||||
String date = Instant.now().toString();
|
||||
|
||||
email.addArgument(notification.getActor().getName());
|
||||
email.addArgument(item.getName());
|
||||
@@ -139,7 +136,13 @@ public class LDNEmailAction implements LDNAction {
|
||||
List<String> recipients = new LinkedList<String>();
|
||||
|
||||
if (actionSendFilter.startsWith("SUBMITTER")) {
|
||||
recipients.add(item.getSubmitter().getEmail());
|
||||
if (item.getSubmitter() != null) {
|
||||
recipients.add(item.getSubmitter().getEmail());
|
||||
} else {
|
||||
// Fallback configured option
|
||||
recipients.add(configurationService.getProperty("ldn.notification.email.submitter.fallback"));
|
||||
}
|
||||
|
||||
} else if (actionSendFilter.startsWith("GROUP:")) {
|
||||
String groupName = actionSendFilter.replace("GROUP:", "");
|
||||
String property = format("email.%s.list", groupName);
|
||||
|
@@ -9,7 +9,7 @@ package org.dspace.app.ldn.action;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -75,8 +75,7 @@ public class LDNRelationCorrectionAction implements LDNAction {
|
||||
qaEvent = new QAEvent(QAEvent.COAR_NOTIFY_SOURCE,
|
||||
handleService.findHandle(context, item), item.getID().toString(), itemName,
|
||||
this.getQaEventTopic(), doubleScoreValue,
|
||||
mapper.writeValueAsString(message),
|
||||
new Date());
|
||||
mapper.writeValueAsString(message), Instant.now());
|
||||
qaEventService.store(context, qaEvent);
|
||||
result = LDNActionStatus.CONTINUE;
|
||||
}
|
||||
|
@@ -18,9 +18,9 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.client.DSpaceHttpClientFactory;
|
||||
import org.dspace.app.ldn.model.Notification;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
@@ -34,21 +34,13 @@ public class SendLDNMessageAction implements LDNAction {
|
||||
|
||||
private static final Logger log = LogManager.getLogger(SendLDNMessageAction.class);
|
||||
|
||||
private CloseableHttpClient client = null;
|
||||
private CloseableHttpClient client;
|
||||
|
||||
public SendLDNMessageAction() {
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
client = builder
|
||||
.disableAutomaticRetries()
|
||||
.setMaxConnTotal(5)
|
||||
.build();
|
||||
}
|
||||
|
||||
public SendLDNMessageAction(CloseableHttpClient client) {
|
||||
this();
|
||||
if (client != null) {
|
||||
this.client = client;
|
||||
}
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,9 +58,10 @@ public class SendLDNMessageAction implements LDNAction {
|
||||
// NOTE: Github believes there is a "Potential server-side request forgery due to a user-provided value"
|
||||
// This is a false positive because the LDN Service URL is configured by the user from DSpace.
|
||||
// See the frontend configuration at [dspace.ui.url]/admin/ldn/services
|
||||
try (
|
||||
CloseableHttpResponse response = client.execute(httpPost);
|
||||
) {
|
||||
if (client == null) {
|
||||
client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5);
|
||||
}
|
||||
try (CloseableHttpResponse response = client.execute(httpPost)) {
|
||||
if (isSuccessful(response.getStatusLine().getStatusCode())) {
|
||||
result = LDNActionStatus.CONTINUE;
|
||||
} else if (isRedirect(response.getStatusLine().getStatusCode())) {
|
||||
@@ -77,6 +70,7 @@ public class SendLDNMessageAction implements LDNAction {
|
||||
} catch (Exception e) {
|
||||
log.error(e);
|
||||
}
|
||||
client.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -91,9 +85,9 @@ public class SendLDNMessageAction implements LDNAction {
|
||||
statusCode == HttpStatus.SC_TEMPORARY_REDIRECT;
|
||||
}
|
||||
|
||||
private LDNActionStatus handleRedirect(CloseableHttpResponse oldresponse,
|
||||
private LDNActionStatus handleRedirect(CloseableHttpResponse oldResponse,
|
||||
HttpPost request) throws HttpException {
|
||||
Header[] urls = oldresponse.getHeaders(HttpHeaders.LOCATION);
|
||||
Header[] urls = oldResponse.getHeaders(HttpHeaders.LOCATION);
|
||||
String url = urls.length > 0 && urls[0] != null ? urls[0].getValue() : null;
|
||||
if (url == null) {
|
||||
throw new HttpException("Error following redirect, unable to reach"
|
||||
@@ -102,17 +96,14 @@ public class SendLDNMessageAction implements LDNAction {
|
||||
LDNActionStatus result = LDNActionStatus.ABORT;
|
||||
try {
|
||||
request.setURI(new URI(url));
|
||||
try (
|
||||
CloseableHttpResponse response = client.execute(request);
|
||||
) {
|
||||
try (CloseableHttpResponse response = client.execute(request)) {
|
||||
if (isSuccessful(response.getStatusLine().getStatusCode())) {
|
||||
return LDNActionStatus.CONTINUE;
|
||||
result = LDNActionStatus.CONTINUE;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error following redirect:", e);
|
||||
}
|
||||
|
||||
return LDNActionStatus.ABORT;
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -8,8 +8,8 @@
|
||||
package org.dspace.app.ldn.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -47,7 +47,7 @@ public class LDNMessageDaoImpl extends AbstractHibernateDAO<LDNMessageEntity> im
|
||||
andPredicates
|
||||
.add(criteriaBuilder.equal(root.get(LDNMessageEntity_.queueStatus), LDNMessageEntity.QUEUE_STATUS_QUEUED));
|
||||
andPredicates.add(criteriaBuilder.lessThan(root.get(LDNMessageEntity_.queueAttempts), max_attempts));
|
||||
andPredicates.add(criteriaBuilder.lessThan(root.get(LDNMessageEntity_.queueTimeout), new Date()));
|
||||
andPredicates.add(criteriaBuilder.lessThan(root.get(LDNMessageEntity_.queueTimeout), Instant.now()));
|
||||
criteriaQuery.where(criteriaBuilder.and(andPredicates.toArray(new Predicate[] {})));
|
||||
List<Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.desc(root.get(LDNMessageEntity_.queueAttempts)));
|
||||
@@ -94,7 +94,7 @@ public class LDNMessageDaoImpl extends AbstractHibernateDAO<LDNMessageEntity> im
|
||||
andPredicates.add(
|
||||
criteriaBuilder.equal(root.get(LDNMessageEntity_.queueStatus), LDNMessageEntity.QUEUE_STATUS_PROCESSING));
|
||||
andPredicates.add(criteriaBuilder.lessThanOrEqualTo(root.get(LDNMessageEntity_.queueAttempts), max_attempts));
|
||||
andPredicates.add(criteriaBuilder.lessThan(root.get(LDNMessageEntity_.queueTimeout), new Date()));
|
||||
andPredicates.add(criteriaBuilder.lessThan(root.get(LDNMessageEntity_.queueTimeout), Instant.now()));
|
||||
criteriaQuery.where(criteriaBuilder.and(andPredicates.toArray(new Predicate[] {})));
|
||||
List<Order> orderList = new LinkedList<>();
|
||||
orderList.add(criteriaBuilder.desc(root.get(LDNMessageEntity_.queueAttempts)));
|
||||
@@ -149,8 +149,11 @@ public class LDNMessageDaoImpl extends AbstractHibernateDAO<LDNMessageEntity> im
|
||||
Predicate activityPredicate = null;
|
||||
andPredicates.add(
|
||||
criteriaBuilder.equal(root.get(LDNMessageEntity_.queueStatus), LDNMessageEntity.QUEUE_STATUS_PROCESSED));
|
||||
// Added OR with object or context - inbound notifications make use of the context item to provide information
|
||||
// about the repository item the notification refers to
|
||||
andPredicates.add(
|
||||
criteriaBuilder.equal(root.get(LDNMessageEntity_.object), item));
|
||||
criteriaBuilder.or(criteriaBuilder.equal(root.get(LDNMessageEntity_.object), item),
|
||||
criteriaBuilder.equal(root.get(LDNMessageEntity_.context), item)));
|
||||
if (activities != null && activities.length > 0) {
|
||||
activityPredicate = root.get(LDNMessageEntity_.activityStreamType).in(activities);
|
||||
andPredicates.add(activityPredicate);
|
||||
|
@@ -8,11 +8,12 @@
|
||||
package org.dspace.app.ldn.model;
|
||||
/**
|
||||
* REQUESTED means acknowledgements not received yet
|
||||
* ACCEPTED means acknowledgements of "Accept" type received
|
||||
* REJECTED means ack of "TentativeReject" type received
|
||||
* ACCEPTED means acknowledgements of "Accept" or "TentativeAccept" type received
|
||||
* REJECTED means ack of "Reject" type received
|
||||
* TENTATIVE_REJECT means ack of "TentativeReject" type received
|
||||
*
|
||||
* @author Francesco Bacchelli (francesco.bacchelli at 4science.com)
|
||||
*/
|
||||
public enum NotifyRequestStatusEnum {
|
||||
REJECTED, ACCEPTED, REQUESTED
|
||||
REJECTED, ACCEPTED, REQUESTED, TENTATIVE_REJECT
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpResponseException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.ldn.LDNMessageEntity;
|
||||
import org.dspace.app.ldn.action.LDNAction;
|
||||
import org.dspace.app.ldn.action.LDNActionStatus;
|
||||
import org.dspace.app.ldn.model.Notification;
|
||||
@@ -59,6 +60,8 @@ public class LDNMetadataProcessor implements LDNProcessor {
|
||||
"Announce",
|
||||
"TentativeReject",
|
||||
"Accept",
|
||||
"TentativeAccept",
|
||||
"Reject",
|
||||
"coar-notify:ReviewAction",
|
||||
"coar-notify:IngestAction",
|
||||
"coar-notify:EndorsementAction");
|
||||
@@ -168,7 +171,22 @@ public class LDNMetadataProcessor implements LDNProcessor {
|
||||
String url = null;
|
||||
|
||||
if (CONTEXT_ID_ITEM_TYPES.containsAll(notification.getType())) {
|
||||
url = notification.getContext().getId();
|
||||
if (notification.getContext() != null) {
|
||||
url = notification.getContext().getId();
|
||||
} else if (notification.getInReplyTo() != null) {
|
||||
// Find context information (the item this notification relates to) via the inReplyTo notification ID
|
||||
LDNMessageEntity inReplyToldnMessageEntity =
|
||||
ldnMessageService.find(context, notification.getInReplyTo());
|
||||
if (inReplyToldnMessageEntity != null) {
|
||||
String dspaceUrl = configurationService.getProperty("dspace.ui.url")
|
||||
+ "/handle/";
|
||||
url = dspaceUrl + inReplyToldnMessageEntity.getObject().getHandle();
|
||||
// Set context based on the inReplyTo and update in DB
|
||||
LDNMessageEntity ldnMessageEntity = ldnMessageService.find(context, notification.getId());
|
||||
ldnMessageEntity.setContext(inReplyToldnMessageEntity.getObject());
|
||||
ldnMessageService.update(context, ldnMessageEntity);
|
||||
}
|
||||
}
|
||||
} else if (OBJECT_ID_ITEM_TYPES.containsAll(notification.getType())) {
|
||||
url = notification.getObject().getId();
|
||||
} else if (OBJECT_SUBJECT_ITEM_TYPES.containsAll(notification.getType())) {
|
||||
|
@@ -130,6 +130,17 @@ public interface LDNMessageService {
|
||||
*/
|
||||
public NotifyRequestStatus findRequestsByItem(Context context, Item item) throws SQLException;
|
||||
|
||||
/**
|
||||
* find the UUID of a previous tentativeReject notification associated with a new resubmission (Endorsement or
|
||||
* Review patterns only)
|
||||
*
|
||||
* @param context the context
|
||||
* @param item the previousVersion item associated with a potential resubmission
|
||||
* @return the UUID of a previous tentativeReject notification associated with a potential resubmission if found
|
||||
*/
|
||||
public String findEndorsementOrReviewResubmissionIdByItem(Context context, Item item, NotifyServiceEntity service)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* delete the provided ldn message
|
||||
*
|
||||
|
@@ -10,10 +10,11 @@ package org.dspace.app.ldn.service.impl;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -22,7 +23,6 @@ import java.util.UUID;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.ldn.LDNMessageEntity;
|
||||
@@ -145,6 +145,12 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
||||
ldnMessage.setActivityStreamType(notificationTypeArrayList.get(0));
|
||||
if (notificationTypeArrayList.size() > 1) {
|
||||
ldnMessage.setCoarNotifyType(notificationTypeArrayList.get(1));
|
||||
} else {
|
||||
// The Notification's Type array does not include the CoarNotifyType information, e.g. ack notifications
|
||||
// Attempt to find it via the inReplyTo if present
|
||||
if (ldnMessage.getInReplyTo() != null) {
|
||||
ldnMessage.setCoarNotifyType(ldnMessage.getInReplyTo().getCoarNotifyType());
|
||||
}
|
||||
}
|
||||
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_QUEUED);
|
||||
ldnMessage.setSourceIp(sourceIp);
|
||||
@@ -157,7 +163,7 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
||||
ldnMessage.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_UNTRUSTED_IP);
|
||||
}
|
||||
}
|
||||
ldnMessage.setQueueTimeout(new Date());
|
||||
ldnMessage.setQueueTimeout(Instant.now());
|
||||
|
||||
update(context, ldnMessage);
|
||||
return ldnMessage;
|
||||
@@ -282,9 +288,9 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
||||
msg.setQueueAttempts(msg.getQueueAttempts() + 1);
|
||||
update(context, msg);
|
||||
} else {
|
||||
msg.setQueueLastStartTime(new Date());
|
||||
msg.setQueueLastStartTime(Instant.now());
|
||||
msg.setQueueStatus(LDNMessageEntity.QUEUE_STATUS_PROCESSING);
|
||||
msg.setQueueTimeout(DateUtils.addMinutes(new Date(), timeoutInMinutes));
|
||||
msg.setQueueTimeout(Instant.now().plus(timeoutInMinutes, ChronoUnit.MINUTES));
|
||||
update(context, msg);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Notification notification = mapper.readValue(msg.getMessage(), Notification.class);
|
||||
@@ -368,18 +374,23 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
||||
offer.setServiceUrl(nse == null ? "" : nse.getUrl());
|
||||
offer.setOfferType(LDNUtils.getNotifyType(msg.getCoarNotifyType()));
|
||||
List<LDNMessageEntity> acks = ldnMessageDao.findAllRelatedMessagesByItem(
|
||||
context, msg, item, "Accept", "TentativeReject", "TentativeAccept", "Announce");
|
||||
context, msg, item, "Accept", "Reject", "TentativeReject", "TentativeAccept",
|
||||
"Announce");
|
||||
if (acks == null || acks.isEmpty()) {
|
||||
offer.setStatus(NotifyRequestStatusEnum.REQUESTED);
|
||||
} else if (acks.stream()
|
||||
.filter(c -> (c.getActivityStreamType().equalsIgnoreCase("TentativeReject")))
|
||||
.findAny().isPresent()) {
|
||||
offer.setStatus(NotifyRequestStatusEnum.TENTATIVE_REJECT);
|
||||
} else if (acks.stream()
|
||||
.filter(c -> (c.getActivityStreamType().equalsIgnoreCase("Reject")))
|
||||
.findAny().isPresent()) {
|
||||
offer.setStatus(NotifyRequestStatusEnum.REJECTED);
|
||||
} else if (acks.stream()
|
||||
.filter(c -> (c.getActivityStreamType().equalsIgnoreCase("TentativeAccept") ||
|
||||
c.getActivityStreamType().equalsIgnoreCase("Accept")))
|
||||
.findAny().isPresent()) {
|
||||
offer.setStatus(NotifyRequestStatusEnum.ACCEPTED);
|
||||
} else if (acks.stream()
|
||||
.filter(c -> c.getActivityStreamType().equalsIgnoreCase("TentativeReject"))
|
||||
.findAny().isPresent()) {
|
||||
offer.setStatus(NotifyRequestStatusEnum.REJECTED);
|
||||
}
|
||||
if (acks.stream().filter(
|
||||
c -> c.getActivityStreamType().equalsIgnoreCase("Announce"))
|
||||
@@ -391,6 +402,32 @@ public class LDNMessageServiceImpl implements LDNMessageService {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findEndorsementOrReviewResubmissionIdByItem(Context context, Item item, NotifyServiceEntity service)
|
||||
throws SQLException {
|
||||
List<LDNMessageEntity> msgs = ldnMessageDao.findAllMessagesByItem(
|
||||
context, item, "TentativeReject");
|
||||
|
||||
if (msgs != null && !msgs.isEmpty()) {
|
||||
for (LDNMessageEntity msg : msgs) {
|
||||
// Review and Endorsement are the only patterns supporting resubmissions at present
|
||||
if (msg.getCoarNotifyType().contains("EndorsementAction")
|
||||
|| msg.getCoarNotifyType().contains("ReviewAction")) {
|
||||
// Only provide the resubmissionReplyTo UUID if the pattern supports resubmission
|
||||
// Add an extra check to ensure that this is a resubmission: current notification service
|
||||
// matches the service associated with a previous tentativeReject response. This is to avoid a
|
||||
// case where a previous version of the item received a tentativeReject from one service
|
||||
// and the author decides to submit the version to a different service, instead of a resubmission
|
||||
if (msg.getOrigin() != null && msg.getOrigin().getID().equals(service.getID())) {
|
||||
// Return the first ID found that will be used in the inReplyTo for a resubmission notification
|
||||
return msg.getID();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void delete(Context context, LDNMessageEntity ldnMessage) throws SQLException {
|
||||
ldnMessageDao.delete(context, ldnMessage);
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@ import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -128,7 +127,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
|
||||
Iterator<Item> itemIterator =
|
||||
itemService.findByLastModifiedSince(
|
||||
context,
|
||||
Date.from(fromDate.atStartOfDay(ZoneId.systemDefault()).toInstant())
|
||||
fromDate.atStartOfDay(ZoneId.systemDefault()).toInstant()
|
||||
);
|
||||
while (itemIterator.hasNext() && processed < max2Process) {
|
||||
applyFiltersItem(context, itemIterator.next());
|
||||
|
@@ -38,6 +38,8 @@ import org.xml.sax.SAXException;
|
||||
public class TikaTextExtractionFilter
|
||||
extends MediaFilter {
|
||||
private final static Logger log = LogManager.getLogger();
|
||||
private static final int DEFAULT_MAX_CHARS = 100_000;
|
||||
private static final int DEFAULT_MAX_ARRAY = 1_000_000;
|
||||
|
||||
@Override
|
||||
public String getFilteredName(String oldFilename) {
|
||||
@@ -71,15 +73,16 @@ public class TikaTextExtractionFilter
|
||||
}
|
||||
|
||||
// Not using temporary file. We'll use Tika's default in-memory parsing.
|
||||
// Get maximum characters to extract. Default is 100,000 chars, which is also Tika's default setting.
|
||||
String extractedText;
|
||||
int maxChars = configurationService.getIntProperty("textextractor.max-chars", 100_000);
|
||||
// Get maximum characters to extract. Default is 100,000 chars, which is also Tika's default setting.
|
||||
int maxChars = configurationService.getIntProperty("textextractor.max-chars", DEFAULT_MAX_CHARS);
|
||||
// Get maximum size of structure that Tika will try to buffer.
|
||||
int maxArray = configurationService.getIntProperty("textextractor.max-array", DEFAULT_MAX_ARRAY);
|
||||
IOUtils.setByteArrayMaxOverride(maxArray);
|
||||
try {
|
||||
// Use Tika to extract text from input. Tika will automatically detect the file type.
|
||||
Tika tika = new Tika();
|
||||
tika.setMaxStringLength(maxChars); // Tell Tika the maximum number of characters to extract
|
||||
IOUtils.setByteArrayMaxOverride(
|
||||
configurationService.getIntProperty("textextractor.max-array", 100_000_000));
|
||||
extractedText = tika.parseToString(source);
|
||||
} catch (IOException e) {
|
||||
System.err.format("Unable to extract text from bitstream in Item %s%n", currentItem.getID().toString());
|
||||
@@ -141,7 +144,7 @@ public class TikaTextExtractionFilter
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
try {
|
||||
writer.append(new String(ch), start, length);
|
||||
writer.append(new String(ch, start, length));
|
||||
} catch (IOException e) {
|
||||
String errorMsg = String.format("Could not append to temporary file at %s " +
|
||||
"when performing text extraction",
|
||||
@@ -159,7 +162,7 @@ public class TikaTextExtractionFilter
|
||||
@Override
|
||||
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
||||
try {
|
||||
writer.append(new String(ch), start, length);
|
||||
writer.append(new String(ch, start, length));
|
||||
} catch (IOException e) {
|
||||
String errorMsg = String.format("Could not append to temporary file at %s " +
|
||||
"when performing text extraction",
|
||||
@@ -170,6 +173,10 @@ public class TikaTextExtractionFilter
|
||||
}
|
||||
});
|
||||
|
||||
ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
int maxArray = configurationService.getIntProperty("textextractor.max-array", DEFAULT_MAX_ARRAY);
|
||||
IOUtils.setByteArrayMaxOverride(maxArray);
|
||||
|
||||
AutoDetectParser parser = new AutoDetectParser();
|
||||
Metadata metadata = new Metadata();
|
||||
// parse our source InputStream using the above custom handler
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.requestitem;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
@@ -19,8 +19,6 @@ import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
@@ -63,20 +61,23 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
||||
private boolean allfiles;
|
||||
|
||||
@Column(name = "decision_date")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date decision_date = null;
|
||||
private Instant decision_date = null;
|
||||
|
||||
@Column(name = "expires")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date expires = null;
|
||||
private Instant expires = null;
|
||||
|
||||
@Column(name = "request_date")
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
private Date request_date = null;
|
||||
private Instant request_date = null;
|
||||
|
||||
@Column(name = "accept_request")
|
||||
private boolean accept_request;
|
||||
|
||||
@Column(name = "access_token", unique = true, length = 48)
|
||||
private String access_token = null;
|
||||
|
||||
@Column(name = "access_expiry")
|
||||
private Instant access_expiry = null;
|
||||
|
||||
/**
|
||||
* Protected constructor, create object using:
|
||||
* {@link org.dspace.app.requestitem.service.RequestItemService#createRequest(
|
||||
@@ -90,7 +91,7 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
||||
return requestitem_id;
|
||||
}
|
||||
|
||||
void setAllfiles(boolean allfiles) {
|
||||
public void setAllfiles(boolean allfiles) {
|
||||
this.allfiles = allfiles;
|
||||
}
|
||||
|
||||
@@ -139,7 +140,8 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a unique request identifier which can be emailed.
|
||||
* @return a unique request identifier which can be emailed to the *approver* of the request.
|
||||
* This is not the same as the access token, which is used by the requester to access the item after approval.
|
||||
*/
|
||||
public String getToken() {
|
||||
return token;
|
||||
@@ -161,11 +163,11 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
||||
return bitstream;
|
||||
}
|
||||
|
||||
public Date getDecision_date() {
|
||||
public Instant getDecision_date() {
|
||||
return decision_date;
|
||||
}
|
||||
|
||||
public void setDecision_date(Date decision_date) {
|
||||
public void setDecision_date(Instant decision_date) {
|
||||
this.decision_date = decision_date;
|
||||
}
|
||||
|
||||
@@ -177,19 +179,53 @@ public class RequestItem implements ReloadableEntity<Integer> {
|
||||
this.accept_request = accept_request;
|
||||
}
|
||||
|
||||
public Date getExpires() {
|
||||
public Instant getExpires() {
|
||||
return expires;
|
||||
}
|
||||
|
||||
void setExpires(Date expires) {
|
||||
void setExpires(Instant expires) {
|
||||
this.expires = expires;
|
||||
}
|
||||
|
||||
public Date getRequest_date() {
|
||||
public Instant getRequest_date() {
|
||||
return request_date;
|
||||
}
|
||||
|
||||
void setRequest_date(Date request_date) {
|
||||
void setRequest_date(Instant request_date) {
|
||||
this.request_date = request_date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A unique token to be used by the requester when granted access to the resource, which
|
||||
* can be emailed upon approval
|
||||
*/
|
||||
public String getAccess_token() {
|
||||
return access_token;
|
||||
}
|
||||
|
||||
public void setAccess_token(String access_token) {
|
||||
this.access_token = access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The date and time when the access token expires.
|
||||
*/
|
||||
public Instant getAccess_expiry() {
|
||||
return access_expiry;
|
||||
}
|
||||
public void setAccess_expiry(Instant access_expiry) {
|
||||
this.access_expiry = access_expiry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize personal information and the approval token, to be used when returning a RequestItem
|
||||
* to Angular, especially for users clicking on the secure link
|
||||
*/
|
||||
public void sanitizePersonalData() {
|
||||
setReqEmail("sanitized");
|
||||
setReqName("sanitized");
|
||||
setReqMessage("sanitized");
|
||||
// Even though [approval] token is not a name, it can be used to access the original object
|
||||
setToken("sanitized");
|
||||
}
|
||||
}
|
||||
|
@@ -10,6 +10,8 @@ package org.dspace.app.requestitem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.annotation.ManagedBean;
|
||||
@@ -28,6 +30,7 @@ import org.dspace.core.Context;
|
||||
import org.dspace.core.Email;
|
||||
import org.dspace.core.I18nUtil;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.handle.service.HandleService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
@@ -174,9 +177,23 @@ public class RequestItemEmailNotifier {
|
||||
grantorAddress = grantor.getEmail();
|
||||
}
|
||||
|
||||
// Set date format for access expiry date
|
||||
String accessExpiryFormat = configurationService.getProperty("request.item.grant.link.dateformat",
|
||||
"yyyy-MM-dd");
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(accessExpiryFormat)
|
||||
.withZone(ZoneId.of("UTC"));
|
||||
|
||||
Email email;
|
||||
// If this item has a secure access token, send the template with that link instead of attaching files
|
||||
if (ri.isAccept_request() && ri.getAccess_token() != null) {
|
||||
email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
|
||||
"request_item.granted_token"));
|
||||
} else {
|
||||
email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
|
||||
ri.isAccept_request() ? "request_item.granted" : "request_item.rejected"));
|
||||
}
|
||||
|
||||
// Build an email back to the requester.
|
||||
Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
|
||||
ri.isAccept_request() ? "request_item.granted" : "request_item.rejected"));
|
||||
email.addArgument(ri.getReqName()); // {0} requestor's name
|
||||
email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle())); // {1} URL of the requested Item
|
||||
email.addArgument(ri.getItem().getName()); // {2} title of the requested Item
|
||||
@@ -188,34 +205,47 @@ public class RequestItemEmailNotifier {
|
||||
// Attach bitstreams.
|
||||
try {
|
||||
if (ri.isAccept_request()) {
|
||||
if (ri.isAllfiles()) {
|
||||
Item item = ri.getItem();
|
||||
List<Bundle> bundles = item.getBundles("ORIGINAL");
|
||||
for (Bundle bundle : bundles) {
|
||||
List<Bitstream> bitstreams = bundle.getBitstreams();
|
||||
for (Bitstream bitstream : bitstreams) {
|
||||
if (!bitstream.getFormat(context).isInternal() &&
|
||||
requestItemService.isRestricted(context,
|
||||
bitstream)) {
|
||||
// #8636 Anyone receiving the email can respond to the
|
||||
// request without authenticating into DSpace
|
||||
context.turnOffAuthorisationSystem();
|
||||
email.addAttachment(
|
||||
bitstreamService.retrieve(context, bitstream),
|
||||
bitstream.getName(),
|
||||
bitstream.getFormat(context).getMIMEType());
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
}
|
||||
if (ri.getAccess_token() != null) {
|
||||
// {6} secure access link
|
||||
email.addArgument(configurationService.getProperty("dspace.ui.url")
|
||||
+ "/items/" + ri.getItem().getID()
|
||||
+ "?accessToken=" + ri.getAccess_token());
|
||||
// {7} access end date, but only add formatted date string if it is set and not "forever"
|
||||
if (ri.getAccess_expiry() != null && !ri.getAccess_expiry().equals(Utils.getMaxTimestamp())) {
|
||||
email.addArgument(dateTimeFormatter.format(ri.getAccess_expiry()));
|
||||
} else {
|
||||
email.addArgument(null);
|
||||
}
|
||||
} else {
|
||||
Bitstream bitstream = ri.getBitstream();
|
||||
// #8636 Anyone receiving the email can respond to the request without authenticating into DSpace
|
||||
context.turnOffAuthorisationSystem();
|
||||
email.addAttachment(bitstreamService.retrieve(context, bitstream),
|
||||
bitstream.getName(),
|
||||
bitstream.getFormat(context).getMIMEType());
|
||||
context.restoreAuthSystemState();
|
||||
if (ri.isAllfiles()) {
|
||||
Item item = ri.getItem();
|
||||
List<Bundle> bundles = item.getBundles("ORIGINAL");
|
||||
for (Bundle bundle : bundles) {
|
||||
List<Bitstream> bitstreams = bundle.getBitstreams();
|
||||
for (Bitstream bitstream : bitstreams) {
|
||||
if (!bitstream.getFormat(context).isInternal() &&
|
||||
requestItemService.isRestricted(context,
|
||||
bitstream)) {
|
||||
// #8636 Anyone receiving the email can respond to the
|
||||
// request without authenticating into DSpace
|
||||
context.turnOffAuthorisationSystem();
|
||||
email.addAttachment(
|
||||
bitstreamService.retrieve(context, bitstream),
|
||||
bitstream.getName(),
|
||||
bitstream.getFormat(context).getMIMEType());
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Bitstream bitstream = ri.getBitstream();
|
||||
//#8636 Anyone receiving the email can respond to the request without authenticating into DSpace
|
||||
context.turnOffAuthorisationSystem();
|
||||
email.addAttachment(bitstreamService.retrieve(context, bitstream),
|
||||
bitstream.getName(),
|
||||
bitstream.getFormat(context).getMIMEType());
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
}
|
||||
email.send();
|
||||
} else {
|
||||
|
@@ -7,25 +7,40 @@
|
||||
*/
|
||||
package org.dspace.app.requestitem;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.text.ParseException;
|
||||
import java.time.DateTimeException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.requestitem.dao.RequestItemDAO;
|
||||
import org.dspace.app.requestitem.service.RequestItemService;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.ResourcePolicy;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.authorize.service.ResourcePolicyService;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogHelper;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.util.DateMathParser;
|
||||
import org.dspace.util.MultiFormatDateParser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
@@ -35,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
* This class should never be accessed directly.
|
||||
*
|
||||
* @author kevinvandevelde at atmire.com
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public class RequestItemServiceImpl implements RequestItemService {
|
||||
|
||||
@@ -49,16 +65,43 @@ public class RequestItemServiceImpl implements RequestItemService {
|
||||
@Autowired(required = true)
|
||||
protected ResourcePolicyService resourcePolicyService;
|
||||
|
||||
@Autowired
|
||||
protected ConfigurationService configurationService;
|
||||
|
||||
/**
|
||||
* Always set UTC for dateMathParser for consistent database date handling
|
||||
*/
|
||||
static DateMathParser dateMathParser = new DateMathParser(TimeZone.getTimeZone("UTC"));
|
||||
|
||||
private static final int DEFAULT_MINIMUM_FILE_SIZE = 20;
|
||||
|
||||
protected RequestItemServiceImpl() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new request-a-copy item request.
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param bitstream The requested bitstream
|
||||
* @param item The requested item
|
||||
* @param allFiles true indicates that all bitstreams of this item are requested
|
||||
* @param reqEmail email
|
||||
* Requester email
|
||||
* @param reqName Requester name
|
||||
* @param reqMessage Request message text
|
||||
* @return token to be used to approver for grant/deny
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public String createRequest(Context context, Bitstream bitstream, Item item,
|
||||
boolean allFiles, String reqEmail, String reqName, String reqMessage)
|
||||
throws SQLException {
|
||||
|
||||
// Create an empty request item
|
||||
RequestItem requestItem = requestItemDAO.create(context, new RequestItem());
|
||||
|
||||
// Set values of the request item based on supplied parameters
|
||||
requestItem.setToken(Utils.generateHexKey());
|
||||
requestItem.setBitstream(bitstream);
|
||||
requestItem.setItem(item);
|
||||
@@ -66,12 +109,58 @@ public class RequestItemServiceImpl implements RequestItemService {
|
||||
requestItem.setReqEmail(reqEmail);
|
||||
requestItem.setReqName(reqName);
|
||||
requestItem.setReqMessage(reqMessage);
|
||||
requestItem.setRequest_date(new Date());
|
||||
requestItem.setRequest_date(Instant.now());
|
||||
|
||||
// If the 'link' feature is enabled and the filesize threshold is met, pre-generate access token now
|
||||
// so it can be previewed by approver and so Angular and REST services can use the existence of this token
|
||||
// as an indication of which delivery method to use.
|
||||
// Access period will be created upon actual approval.
|
||||
if (configurationService.getBooleanProperty("request.item.grant.link", false)) {
|
||||
// The 'send link' feature is enabled, is the file(s) requested over the size threshold (megabytes as int)?
|
||||
// Default is 20MB minimum. For inspection purposes we convert to bytes.
|
||||
long minimumSize = configurationService.getLongProperty(
|
||||
"request.item.grant.link.filesize", DEFAULT_MINIMUM_FILE_SIZE) * 1024 * 1024;
|
||||
// If we have a single bitstream, we will initialise the "minimum threshold reached" correctly
|
||||
boolean minimumSizeThresholdReached = (null != bitstream && bitstream.getSizeBytes() >= minimumSize);
|
||||
// If all files (and presumably no min reached since bitstream should be null), we look for ANY >= min size
|
||||
if (!minimumSizeThresholdReached && allFiles) {
|
||||
// Iterate bitstream and inspect file sizes. At each loop iteration we will break out if the min
|
||||
// was already reached.
|
||||
String[] bundleNames = configurationService.getArrayProperty("request.item.grant.link.bundles",
|
||||
new String[]{"ORIGINAL"});
|
||||
for (String bundleName : bundleNames) {
|
||||
if (!minimumSizeThresholdReached) {
|
||||
for (Bundle bundle : item.getBundles(bundleName)) {
|
||||
if (null != bundle && !minimumSizeThresholdReached) {
|
||||
for (Bitstream bitstreamToCheck : bundle.getBitstreams()) {
|
||||
if (bitstreamToCheck.getSizeBytes() >= minimumSize) {
|
||||
minimumSizeThresholdReached = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, only generate and set an access token if the minimum file size threshold was reached.
|
||||
// Otherwise, an email attachment will still be used.
|
||||
// From now on, the existence of an access token in the RequestItem indicates that a web link should be
|
||||
// sent instead of attaching file(s) as an attachment.
|
||||
if (minimumSizeThresholdReached) {
|
||||
requestItem.setAccess_token(Utils.generateHexKey());
|
||||
}
|
||||
}
|
||||
|
||||
// Save the request item
|
||||
requestItemDAO.save(context, requestItem);
|
||||
|
||||
log.debug("Created RequestItem with ID {} and token {}",
|
||||
requestItem::getID, requestItem::getToken);
|
||||
log.debug("Created RequestItem with ID {}, approval token {}, access token {}, access expiry {}",
|
||||
requestItem::getID, requestItem::getToken, requestItem::getAccess_token, requestItem::getAccess_expiry);
|
||||
|
||||
// Return the approver token
|
||||
return requestItem.getToken();
|
||||
}
|
||||
|
||||
@@ -128,4 +217,186 @@ public class RequestItemServiceImpl implements RequestItemService {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a request item by its access token. This is the token that a requester would use
|
||||
* to authenticate themselves as a granted requester.
|
||||
* It is up to the RequestItemRepository to check validity of the item, access granted, data sanitization, etc.
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
* @param accessToken the token identifying the request to be temporarily accessed
|
||||
* @return request item data
|
||||
*/
|
||||
@Override
|
||||
public RequestItem findByAccessToken(Context context, String accessToken) {
|
||||
try {
|
||||
return requestItemDAO.findByAccessToken(context, accessToken);
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the access expiry date for the request item.
|
||||
* @param requestItem the request item to update
|
||||
* @param accessExpiry the expiry date to set
|
||||
*/
|
||||
@Override
|
||||
public void setAccessExpiry(RequestItem requestItem, Instant accessExpiry) {
|
||||
requestItem.setAccess_expiry(accessExpiry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a string either as a formatted date, or in the "math" format expected by
|
||||
* the DateMathParser, e.g. +7DAYS or +10MONTHS, and set the access expiry date accordingly.
|
||||
* There are no special checks here to check that the date is in the future, or after the
|
||||
* 'decision date', as there may be legitimate reasons to set past dates.
|
||||
* If past dates are not allowed by some interface, then the caller should check this.
|
||||
*
|
||||
* @param requestItem the request item to update
|
||||
* @param dateOrDelta the delta as a string in format expected by the DateMathParser
|
||||
*/
|
||||
@Override
|
||||
public void setAccessExpiry(RequestItem requestItem, String dateOrDelta) {
|
||||
try {
|
||||
setAccessExpiry(requestItem, parseDateOrDelta(dateOrDelta, requestItem.getDecision_date()));
|
||||
} catch (ParseException e) {
|
||||
log.error("Error parsing access expiry or duration: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taking into account 'accepted' flag, bitstream id or allfiles flag, decision date and access period,
|
||||
* either return cleanly or throw an AuthorizeException
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param requestItem the request item containing request and approval data
|
||||
* @param bitstream the bitstream to which access is requested
|
||||
* @param accessToken the access token supplied by the user (e.g. to REST controller)
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@Override
|
||||
public void authorizeAccessByAccessToken(Context context, RequestItem requestItem, Bitstream bitstream,
|
||||
String accessToken) throws AuthorizeException {
|
||||
if (requestItem == null || bitstream == null || context == null || accessToken == null) {
|
||||
throw new AuthorizeException("Null resources provided, not authorized");
|
||||
}
|
||||
// 1. Request is accepted
|
||||
if (requestItem.isAccept_request()
|
||||
// 2. Request access token is not null and matches supplied string
|
||||
&& (requestItem.getAccess_token() != null && requestItem.getAccess_token().equals(accessToken))
|
||||
// 3. Request is 'allfiles' or for this bitstream ID
|
||||
&& (requestItem.isAllfiles() || bitstream.equals(requestItem.getBitstream()))
|
||||
// 4. access expiry timestamp is null (forever), or is *after* the current time
|
||||
&& (requestItem.getAccess_expiry() == null || requestItem.getAccess_expiry().isAfter(Instant.now()))
|
||||
) {
|
||||
log.info("Authorizing access to bitstream {} by access token", bitstream.getID());
|
||||
return;
|
||||
}
|
||||
// Default, throw authorize exception
|
||||
throw new AuthorizeException("Unauthorized access to bitstream by access token for bitstream ID "
|
||||
+ bitstream.getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* Taking into account 'accepted' flag, bitstream id or allfiles flag, decision date and access period,
|
||||
* either return cleanly or throw an AuthorizeException
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param bitstream the bitstream to which access is requested
|
||||
* @param accessToken the access token supplied by the user (e.g. to REST controller)
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
@Override
|
||||
public void authorizeAccessByAccessToken(Context context, Bitstream bitstream, String accessToken)
|
||||
throws AuthorizeException {
|
||||
if (bitstream == null || context == null || accessToken == null) {
|
||||
throw new AuthorizeException("Null resources provided, not authorized");
|
||||
}
|
||||
// get request item from access token
|
||||
RequestItem requestItem = findByAccessToken(context, accessToken);
|
||||
if (requestItem == null) {
|
||||
throw new AuthorizeException("Null item request provided, not authorized");
|
||||
}
|
||||
// Continue with authorization check
|
||||
authorizeAccessByAccessToken(context, requestItem, bitstream, accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a link back to DSpace, to act on a request.
|
||||
*
|
||||
* @param token identifies the request.
|
||||
* @return URL to the item request API, with the token as request parameter
|
||||
* "token".
|
||||
* @throws URISyntaxException passed through.
|
||||
* @throws MalformedURLException passed through.
|
||||
*/
|
||||
@Override
|
||||
public String getLinkTokenEmail(String token)
|
||||
throws URISyntaxException, MalformedURLException {
|
||||
final String base = configurationService.getProperty("dspace.ui.url");
|
||||
URIBuilder uriBuilder = new URIBuilder(base);
|
||||
String currentPath = uriBuilder.getPath();
|
||||
String newPath = (currentPath == null || currentPath.isEmpty() || currentPath.equals("/"))
|
||||
? "/request-a-copy/" + token
|
||||
: currentPath + "/request-a-copy/" + token;
|
||||
URI uri = uriBuilder.setPath(newPath).build();
|
||||
return uri.toURL().toExternalForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a RequestItem. The following values in the referenced RequestItem
|
||||
* are nullified:
|
||||
* - approver token (aka token)
|
||||
* - requester name
|
||||
* - requester email
|
||||
* - requester message
|
||||
*
|
||||
* These properties contain personal information, or can be used to access personal information
|
||||
* and are not needed except for sending the original request and grant/deny emails
|
||||
*
|
||||
* @param requestItem
|
||||
*/
|
||||
@Override
|
||||
public void sanitizeRequestItem(Context context, RequestItem requestItem) {
|
||||
if (null == requestItem) {
|
||||
log.error("Null request item passed for sanitization, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanitized referenced data (strips requester name, email, message, and the approver token)
|
||||
requestItem.sanitizePersonalData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a date or delta string into an Instant. Kept here as a static method for use in unit tests
|
||||
* and other areas that might not have access to the full spring service
|
||||
*
|
||||
* @param dateOrDelta
|
||||
* @param decisionDate
|
||||
* @return parsed date as instant
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Instant parseDateOrDelta(String dateOrDelta, Instant decisionDate)
|
||||
throws ParseException, DateTimeException {
|
||||
// First, if dateOrDelta is a null string or "FOREVER", we will set the expiry
|
||||
// date to a very distant date in the future.
|
||||
if (dateOrDelta == null || dateOrDelta.equals("FOREVER")) {
|
||||
return Utils.getMaxTimestamp();
|
||||
}
|
||||
// Next, try parsing as a straight date using the multiple format parser
|
||||
ZonedDateTime parsedExpiryDate = MultiFormatDateParser.parse(dateOrDelta);
|
||||
|
||||
if (parsedExpiryDate == null) {
|
||||
// That did not work, so try parsing as a delta
|
||||
// Set the 'now' date to the decision date of the request item
|
||||
dateMathParser.setNow(LocalDateTime.ofInstant(decisionDate, ZoneOffset.UTC));
|
||||
// Parse the delta (e.g. +7DAYS) and set the new access expiry date
|
||||
return dateMathParser.parseMath(dateOrDelta).toInstant(ZoneOffset.UTC);
|
||||
} else {
|
||||
// The expiry date was a valid formatted date string, so set the access expiry date
|
||||
return parsedExpiryDate.toInstant();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ import org.dspace.core.GenericDAO;
|
||||
*/
|
||||
public interface RequestItemDAO extends GenericDAO<RequestItem> {
|
||||
/**
|
||||
* Fetch a request named by its unique token (passed in emails).
|
||||
* Fetch a request named by its unique approval token (passed in emails).
|
||||
*
|
||||
* @param context the current DSpace context.
|
||||
* @param token uniquely identifies the request.
|
||||
@@ -35,5 +35,18 @@ public interface RequestItemDAO extends GenericDAO<RequestItem> {
|
||||
*/
|
||||
public RequestItem findByToken(Context context, String token) throws SQLException;
|
||||
|
||||
/**
|
||||
* Fetch a request named by its unique access token (passed in emails).
|
||||
* Note this is the token used by the requester to access an approved resource, not the token
|
||||
* used by the item submitter or helpdesk to grant the access.
|
||||
*
|
||||
* @param context the current DSpace context.
|
||||
* @param accessToken uniquely identifies the request
|
||||
* @return the found request or {@code null}
|
||||
* @throws SQLException passed through.
|
||||
*/
|
||||
public RequestItem findByAccessToken(Context context, String accessToken) throws SQLException;
|
||||
|
||||
public Iterator<RequestItem> findByItem(Context context, Item item) throws SQLException;
|
||||
|
||||
}
|
||||
|
@@ -42,6 +42,17 @@ public class RequestItemDAOImpl extends AbstractHibernateDAO<RequestItem> implem
|
||||
criteriaQuery.where(criteriaBuilder.equal(requestItemRoot.get(RequestItem_.token), token));
|
||||
return uniqueResult(context, criteriaQuery, false, RequestItem.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestItem findByAccessToken(Context context, String accessToken) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RequestItem.class);
|
||||
Root<RequestItem> requestItemRoot = criteriaQuery.from(RequestItem.class);
|
||||
criteriaQuery.select(requestItemRoot);
|
||||
criteriaQuery.where(criteriaBuilder.equal(requestItemRoot.get(RequestItem_.access_token), accessToken));
|
||||
return uniqueResult(context, criteriaQuery, true, RequestItem.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<RequestItem> findByItem(Context context, Item item) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
|
@@ -8,13 +8,19 @@
|
||||
|
||||
/**
|
||||
* Feature for conveying a request that materials forbidden to the requester
|
||||
* by resource policy be made available by other means. The request will be
|
||||
* e-mailed to a responsible party for consideration and action. Find details
|
||||
* in the user documentation under the rubric "Request a Copy".
|
||||
* by resource policy be made available by other means.
|
||||
*
|
||||
* There are several methods of making the resource(s) available to the requester:
|
||||
* 1. The request will be e-mailed to a responsible party for consideration and action.
|
||||
* Find details in the user documentation under the rubric "Request a Copy".
|
||||
*
|
||||
* <p>Mailing is handled by {@link RequestItemEmailNotifier}. Responsible
|
||||
* parties are represented by {@link RequestItemAuthor}
|
||||
*
|
||||
* 2. A unique 48-char token will be generated and included in a special weblink emailed to the requester.
|
||||
* This link will provide access to the requester as though they had READ policy access while the access period
|
||||
* has not expired, or forever if the access period is null.
|
||||
*
|
||||
* <p>This package includes several "strategy" classes which discover
|
||||
* responsible parties in various ways. See
|
||||
* {@link RequestItemSubmitterStrategy} and the classes which extend it, and
|
||||
|
@@ -7,11 +7,15 @@
|
||||
*/
|
||||
package org.dspace.app.requestitem.service;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Instant;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.app.requestitem.RequestItem;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
@@ -23,6 +27,7 @@ import org.dspace.core.Context;
|
||||
* for the RequestItem object and is autowired by Spring.
|
||||
*
|
||||
* @author kevinvandevelde at atmire.com
|
||||
* @author Kim Shepherd
|
||||
*/
|
||||
public interface RequestItemService {
|
||||
|
||||
@@ -40,7 +45,7 @@ public interface RequestItemService {
|
||||
* @return the token of the request item
|
||||
* @throws SQLException if database error
|
||||
*/
|
||||
public String createRequest(Context context, Bitstream bitstream, Item item,
|
||||
String createRequest(Context context, Bitstream bitstream, Item item,
|
||||
boolean allFiles, String reqEmail, String reqName, String reqMessage)
|
||||
throws SQLException;
|
||||
|
||||
@@ -49,35 +54,46 @@ public interface RequestItemService {
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
* @return all item requests.
|
||||
* @throws java.sql.SQLException passed through.
|
||||
* @throws SQLException passed through.
|
||||
*/
|
||||
public List<RequestItem> findAll(Context context)
|
||||
List<RequestItem> findAll(Context context)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve a request by its token.
|
||||
* Retrieve a request by its approver token.
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
* @param token the token identifying the request.
|
||||
* @param token the token identifying the request to be approved.
|
||||
* @return the matching request, or null if not found.
|
||||
*/
|
||||
public RequestItem findByToken(Context context, String token);
|
||||
RequestItem findByToken(Context context, String token);
|
||||
|
||||
/**
|
||||
* Retrieve a request by its access token, for use by the requester
|
||||
*
|
||||
* @param context current DSpace session.
|
||||
* @param token the token identifying the request to be temporarily accessed
|
||||
* @return the matching request, or null if not found.
|
||||
*/
|
||||
RequestItem findByAccessToken(Context context, String token);
|
||||
/**
|
||||
* Retrieve a request based on the item.
|
||||
* @param context current DSpace session.
|
||||
* @param item the item to find requests for.
|
||||
* @return the matching requests, or null if not found.
|
||||
*/
|
||||
public Iterator<RequestItem> findByItem(Context context, Item item) throws SQLException;
|
||||
Iterator<RequestItem> findByItem(Context context, Item item) throws SQLException;
|
||||
|
||||
/**
|
||||
* Save updates to the record. Only accept_request, and decision_date are set-able.
|
||||
* Save updates to the record. Only accept_request, decision_date, access_period are settable.
|
||||
*
|
||||
* Note: the "is settable" rules mentioned here are enforced in RequestItemRest with annotations meaning that
|
||||
* these JSON properties are considered READ-ONLY by the core DSpaceRestRepository methods
|
||||
*
|
||||
* @param context The relevant DSpace Context.
|
||||
* @param requestItem requested item
|
||||
*/
|
||||
public void update(Context context, RequestItem requestItem);
|
||||
void update(Context context, RequestItem requestItem);
|
||||
|
||||
/**
|
||||
* Remove the record from the database.
|
||||
@@ -85,7 +101,7 @@ public interface RequestItemService {
|
||||
* @param context current DSpace context.
|
||||
* @param request record to be removed.
|
||||
*/
|
||||
public void delete(Context context, RequestItem request);
|
||||
void delete(Context context, RequestItem request);
|
||||
|
||||
/**
|
||||
* Is there at least one valid READ resource policy for this object?
|
||||
@@ -94,6 +110,77 @@ public interface RequestItemService {
|
||||
* @return true if a READ policy applies.
|
||||
* @throws SQLException passed through.
|
||||
*/
|
||||
public boolean isRestricted(Context context, DSpaceObject o)
|
||||
boolean isRestricted(Context context, DSpaceObject o)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Set the access expiry timestamp for a request item. After this date, the
|
||||
* bitstream(s) will no longer be available for download even with a token.
|
||||
* @param requestItem the request item
|
||||
* @param accessExpiry the expiry timestamp
|
||||
*/
|
||||
void setAccessExpiry(RequestItem requestItem, Instant accessExpiry);
|
||||
|
||||
/**
|
||||
* Set the access expiry timestamp for a request item by delta string.
|
||||
* After this date, the bitstream(s) will no longer be available for download
|
||||
* even with a token.
|
||||
* @param requestItem the request item
|
||||
* @param delta the delta to calculate the expiry timestamp, from the decision date
|
||||
*/
|
||||
void setAccessExpiry(RequestItem requestItem, String delta);
|
||||
|
||||
/**
|
||||
* Taking into account 'accepted' flag, bitstream id or allfiles flag, decision date and access period,
|
||||
* either return cleanly or throw an AuthorizeException
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param requestItem the request item containing request and approval data
|
||||
* @param bitstream the bitstream to which access is requested
|
||||
* @param accessToken the access token supplied by the user (e.g. to REST controller)
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
void authorizeAccessByAccessToken(Context context, RequestItem requestItem, Bitstream bitstream,
|
||||
String accessToken)
|
||||
throws AuthorizeException;
|
||||
|
||||
/**
|
||||
* Taking into account 'accepted' flag, bitstream id or allfiles flag, decision date and access period,
|
||||
* either return cleanly or throw an AuthorizeException
|
||||
*
|
||||
* @param context the DSpace context
|
||||
* @param bitstream the bitstream to which access is requested
|
||||
* @param accessToken the access token supplied by the user (e.g. to REST controller)
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
void authorizeAccessByAccessToken(Context context, Bitstream bitstream, String accessToken)
|
||||
throws AuthorizeException;
|
||||
|
||||
/**
|
||||
* Generate a link back to DSpace, to act on a request.
|
||||
*
|
||||
* @param token identifies the request.
|
||||
* @return URL to the item request API, with the token as request parameter
|
||||
* "token".
|
||||
* @throws URISyntaxException passed through.
|
||||
* @throws MalformedURLException passed through.
|
||||
*/
|
||||
String getLinkTokenEmail(String token)
|
||||
throws URISyntaxException, MalformedURLException;
|
||||
|
||||
/**
|
||||
* Sanitize a RequestItem depending on the current session user. If the current user is not
|
||||
* the approver, an administrator or other privileged group, the following values in the return object
|
||||
* are nullified:
|
||||
* - approver token (aka token)
|
||||
* - requester name
|
||||
* - requester email
|
||||
* - requester message
|
||||
*
|
||||
* These properties contain personal information, or can be used to access personal information
|
||||
* and are not needed except for sending the original request and grant/deny emails
|
||||
*
|
||||
* @param requestItem
|
||||
*/
|
||||
void sanitizeRequestItem(Context context, RequestItem requestItem);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.sfx.service.SFXFileReaderService;
|
||||
import org.dspace.app.util.XMLUtils;
|
||||
import org.dspace.content.DCPersonName;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
@@ -79,9 +80,9 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService {
|
||||
log.info("Parsing XML file... " + fileName);
|
||||
DocumentBuilder docBuilder;
|
||||
Document doc = null;
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
docBuilderFactory.setIgnoringElementContentWhitespace(true);
|
||||
try {
|
||||
DocumentBuilderFactory docBuilderFactory = XMLUtils.getDocumentBuilderFactory();
|
||||
docBuilderFactory.setIgnoringElementContentWhitespace(true);
|
||||
docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
log.error("Wrong parser configuration: " + e.getMessage());
|
||||
|
@@ -17,15 +17,15 @@ import jakarta.annotation.PostConstruct;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.app.client.DSpaceHttpClientFactory;
|
||||
import org.dspace.app.sherpa.v2.SHERPAPublisherResponse;
|
||||
import org.dspace.app.sherpa.v2.SHERPAResponse;
|
||||
import org.dspace.app.sherpa.v2.SHERPAUtils;
|
||||
@@ -45,8 +45,6 @@ import org.springframework.cache.annotation.Cacheable;
|
||||
*/
|
||||
public class SHERPAService {
|
||||
|
||||
private CloseableHttpClient client = null;
|
||||
|
||||
private int maxNumberOfTries;
|
||||
private long sleepBetweenTimeouts;
|
||||
private int timeout = 5000;
|
||||
@@ -59,19 +57,6 @@ public class SHERPAService {
|
||||
@Autowired
|
||||
ConfigurationService configurationService;
|
||||
|
||||
/**
|
||||
* Create a new HTTP builder with sensible defaults in constructor
|
||||
*/
|
||||
public SHERPAService() {
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
// httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
|
||||
// not to hammer the SHERPA service too much.
|
||||
client = builder
|
||||
.disableAutomaticRetries()
|
||||
.setMaxConnTotal(5)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete initialization of the Bean.
|
||||
*/
|
||||
@@ -132,46 +117,47 @@ public class SHERPAService {
|
||||
timeout,
|
||||
sleepBetweenTimeouts));
|
||||
|
||||
try {
|
||||
try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
|
||||
Thread.sleep(sleepBetweenTimeouts);
|
||||
|
||||
// Construct a default HTTP method (first result)
|
||||
method = constructHttpGet(type, field, predicate, value, start, limit);
|
||||
|
||||
// Execute the method
|
||||
HttpResponse response = client.execute(method);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
try (CloseableHttpResponse response = client.execute(method)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
|
||||
log.debug(response.getStatusLine().getStatusCode() + ": "
|
||||
+ response.getStatusLine().getReasonPhrase());
|
||||
log.debug(response.getStatusLine().getStatusCode() + ": "
|
||||
+ response.getStatusLine().getReasonPhrase());
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: "
|
||||
+ statusCode);
|
||||
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
log.error("Error from SHERPA HTTP request: " + errorBody);
|
||||
}
|
||||
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
|
||||
// If the response body is valid, pass to SHERPAResponse for parsing as JSON
|
||||
if (null != responseBody) {
|
||||
log.debug("Non-null SHERPA response received for query of " + value);
|
||||
InputStream content = null;
|
||||
try {
|
||||
content = responseBody.getContent();
|
||||
sherpaResponse =
|
||||
new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON);
|
||||
} catch (IOException e) {
|
||||
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (content != null) {
|
||||
content.close();
|
||||
}
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO return not OK status: "
|
||||
+ statusCode);
|
||||
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
log.error("Error from SHERPA HTTP request: " + errorBody);
|
||||
}
|
||||
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
|
||||
// If the response body is valid, pass to SHERPAResponse for parsing as JSON
|
||||
if (null != responseBody) {
|
||||
log.debug("Non-null SHERPA response received for query of " + value);
|
||||
InputStream content = null;
|
||||
try {
|
||||
content = responseBody.getContent();
|
||||
sherpaResponse =
|
||||
new SHERPAPublisherResponse(content, SHERPAPublisherResponse.SHERPAFormat.JSON);
|
||||
} catch (IOException e) {
|
||||
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (content != null) {
|
||||
content.close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.debug("Empty SHERPA response body for query on " + value);
|
||||
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
|
||||
}
|
||||
} else {
|
||||
log.debug("Empty SHERPA response body for query on " + value);
|
||||
sherpaResponse = new SHERPAPublisherResponse("SHERPA/RoMEO returned no response");
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
|
||||
@@ -235,45 +221,46 @@ public class SHERPAService {
|
||||
timeout,
|
||||
sleepBetweenTimeouts));
|
||||
|
||||
try {
|
||||
try (CloseableHttpClient client = DSpaceHttpClientFactory.getInstance().buildWithoutAutomaticRetries(5)) {
|
||||
Thread.sleep(sleepBetweenTimeouts);
|
||||
|
||||
// Construct a default HTTP method (first result)
|
||||
method = constructHttpGet(type, field, predicate, value, start, limit);
|
||||
|
||||
// Execute the method
|
||||
HttpResponse response = client.execute(method);
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
try (CloseableHttpResponse response = client.execute(method)) {
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
|
||||
log.debug(response.getStatusLine().getStatusCode() + ": "
|
||||
+ response.getStatusLine().getReasonPhrase());
|
||||
log.debug(response.getStatusLine().getStatusCode() + ": "
|
||||
+ response.getStatusLine().getReasonPhrase());
|
||||
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
|
||||
+ statusCode);
|
||||
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
log.error("Error from SHERPA HTTP request: " + errorBody);
|
||||
}
|
||||
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
|
||||
// If the response body is valid, pass to SHERPAResponse for parsing as JSON
|
||||
if (null != responseBody) {
|
||||
log.debug("Non-null SHERPA response received for query of " + value);
|
||||
InputStream content = null;
|
||||
try {
|
||||
content = responseBody.getContent();
|
||||
sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON);
|
||||
} catch (IOException e) {
|
||||
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (content != null) {
|
||||
content.close();
|
||||
}
|
||||
if (statusCode != HttpStatus.SC_OK) {
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
|
||||
+ statusCode);
|
||||
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
log.error("Error from SHERPA HTTP request: " + errorBody);
|
||||
}
|
||||
|
||||
HttpEntity responseBody = response.getEntity();
|
||||
|
||||
// If the response body is valid, pass to SHERPAResponse for parsing as JSON
|
||||
if (null != responseBody) {
|
||||
log.debug("Non-null SHERPA response received for query of " + value);
|
||||
InputStream content = null;
|
||||
try {
|
||||
content = responseBody.getContent();
|
||||
sherpaResponse = new SHERPAResponse(content, SHERPAResponse.SHERPAFormat.JSON);
|
||||
} catch (IOException e) {
|
||||
log.error("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (content != null) {
|
||||
content.close();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.debug("Empty SHERPA response body for query on " + value);
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
|
||||
}
|
||||
} else {
|
||||
log.debug("Empty SHERPA response body for query on " + value);
|
||||
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
|
||||
@@ -283,7 +270,7 @@ public class SHERPAService {
|
||||
String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage();
|
||||
log.error(errorMessage, e);
|
||||
sherpaResponse = new SHERPAResponse(errorMessage);
|
||||
} catch (InterruptedException e) {
|
||||
} catch (InterruptedException e) {
|
||||
String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage();
|
||||
log.error(errorMessage, e);
|
||||
sherpaResponse = new SHERPAResponse(errorMessage);
|
||||
|
@@ -12,8 +12,8 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@@ -59,7 +59,7 @@ public class SHERPAResponse implements Serializable {
|
||||
private String uri;
|
||||
|
||||
@JsonIgnore
|
||||
private Date retrievalTime = new Date();
|
||||
private Instant retrievalTime = Instant.now();
|
||||
|
||||
// Format enum - currently only JSON is supported
|
||||
public enum SHERPAFormat {
|
||||
@@ -563,7 +563,7 @@ public class SHERPAResponse implements Serializable {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public Date getRetrievalTime() {
|
||||
public Instant getRetrievalTime() {
|
||||
return retrievalTime;
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
/**
|
||||
@@ -110,7 +110,7 @@ public abstract class AbstractGenerator {
|
||||
* @throws IOException if IO error
|
||||
* if an error occurs writing
|
||||
*/
|
||||
public void addURL(String url, Date lastMod) throws IOException {
|
||||
public void addURL(String url, Instant lastMod) throws IOException {
|
||||
// Kick things off if this is the first call
|
||||
if (currentOutput == null) {
|
||||
startNewFile();
|
||||
@@ -143,7 +143,7 @@ public abstract class AbstractGenerator {
|
||||
|
||||
/**
|
||||
* Complete writing sitemap files and write the index files. This is invoked
|
||||
* when all calls to {@link AbstractGenerator#addURL(String, Date)} have
|
||||
* when all calls to {@link AbstractGenerator#addURL(String, Instant)} have
|
||||
* been completed, and invalidates the generator.
|
||||
*
|
||||
* @return number of sitemap files written.
|
||||
@@ -177,7 +177,7 @@ public abstract class AbstractGenerator {
|
||||
* applicable
|
||||
* @return the mark-up to include
|
||||
*/
|
||||
public abstract String getURLText(String url, Date lastMod);
|
||||
public abstract String getURLText(String url, Instant lastMod);
|
||||
|
||||
/**
|
||||
* Return the boilerplate at the top of a sitemap file.
|
||||
|
@@ -7,10 +7,11 @@
|
||||
*/
|
||||
package org.dspace.app.sitemap;
|
||||
|
||||
import static org.dspace.discovery.SearchUtils.RESOURCE_TYPE_FIELD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
@@ -189,7 +190,8 @@ public class GenerateSitemaps {
|
||||
try {
|
||||
DiscoverQuery discoveryQuery = new DiscoverQuery();
|
||||
discoveryQuery.setMaxResults(PAGE_SIZE);
|
||||
discoveryQuery.setQuery("search.resourcetype:Community");
|
||||
discoveryQuery.setQuery("*:*");
|
||||
discoveryQuery.addFilterQueries(RESOURCE_TYPE_FIELD + ":Community");
|
||||
do {
|
||||
discoveryQuery.setStart(offset);
|
||||
DiscoverResult discoverResult = searchService.search(c, discoveryQuery);
|
||||
@@ -213,7 +215,8 @@ public class GenerateSitemaps {
|
||||
offset = 0;
|
||||
discoveryQuery = new DiscoverQuery();
|
||||
discoveryQuery.setMaxResults(PAGE_SIZE);
|
||||
discoveryQuery.setQuery("search.resourcetype:Collection");
|
||||
discoveryQuery.setQuery("*:*");
|
||||
discoveryQuery.addFilterQueries(RESOURCE_TYPE_FIELD + ":Collection");
|
||||
do {
|
||||
discoveryQuery.setStart(offset);
|
||||
DiscoverResult discoverResult = searchService.search(c, discoveryQuery);
|
||||
@@ -237,7 +240,8 @@ public class GenerateSitemaps {
|
||||
offset = 0;
|
||||
discoveryQuery = new DiscoverQuery();
|
||||
discoveryQuery.setMaxResults(PAGE_SIZE);
|
||||
discoveryQuery.setQuery("search.resourcetype:Item");
|
||||
discoveryQuery.setQuery("*:*");
|
||||
discoveryQuery.addFilterQueries(RESOURCE_TYPE_FIELD + ":Item");
|
||||
discoveryQuery.addSearchField("search.entitytype");
|
||||
do {
|
||||
|
||||
@@ -256,7 +260,6 @@ public class GenerateSitemaps {
|
||||
} else {
|
||||
url = uiURLStem + "items/" + doc.getID();
|
||||
}
|
||||
Date lastMod = doc.getLastModified();
|
||||
c.uncacheEntity(doc.getIndexedObject());
|
||||
|
||||
if (makeHTMLMap) {
|
||||
|
@@ -10,7 +10,7 @@ package org.dspace.app.sitemap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Class for generating HTML "sitemaps" which contain links to various pages in
|
||||
@@ -77,7 +77,7 @@ public class HTMLSitemapGenerator extends AbstractGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURLText(String url, Date lastMod) {
|
||||
public String getURLText(String url, Instant lastMod) {
|
||||
StringBuffer urlText = new StringBuffer();
|
||||
|
||||
urlText.append("<li><a href=\"").append(url).append("\">").append(url)
|
||||
|
@@ -10,9 +10,8 @@ package org.dspace.app.sitemap;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Class for generating <a href="http://sitemaps.org/">Sitemaps</a> to improve
|
||||
@@ -36,8 +35,7 @@ public class SitemapsOrgGenerator extends AbstractGenerator {
|
||||
/**
|
||||
* The correct date format
|
||||
*/
|
||||
protected DateFormat w3dtfFormat = new SimpleDateFormat(
|
||||
"yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
protected DateTimeFormatter w3dtfFormat = DateTimeFormatter.ISO_INSTANT;
|
||||
|
||||
/**
|
||||
* Construct a sitemaps.org protocol sitemap generator, writing files to the
|
||||
@@ -85,7 +83,7 @@ public class SitemapsOrgGenerator extends AbstractGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURLText(String url, Date lastMod) {
|
||||
public String getURLText(String url, Instant lastMod) {
|
||||
StringBuilder urlText = new StringBuilder();
|
||||
|
||||
urlText.append("<url><loc>").append(url).append("</loc>");
|
||||
@@ -111,7 +109,7 @@ public class SitemapsOrgGenerator extends AbstractGenerator {
|
||||
@Override
|
||||
public void writeIndex(PrintStream output, int sitemapCount)
|
||||
throws IOException {
|
||||
String now = w3dtfFormat.format(new Date());
|
||||
String now = w3dtfFormat.format(Instant.now());
|
||||
|
||||
output.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
|
||||
output
|
||||
|
@@ -12,7 +12,8 @@ import static org.dspace.discovery.indexobject.ItemIndexFactoryImpl.STATUS_FIELD
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Calendar;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -98,7 +99,8 @@ public class SolrDatabaseResyncCli extends DSpaceRunnable<SolrDatabaseResyncCliS
|
||||
|
||||
private void performStatusUpdate(Context context) throws SearchServiceException, SolrServerException, IOException {
|
||||
SolrQuery solrQuery = new SolrQuery();
|
||||
solrQuery.setQuery(STATUS_FIELD + ":" + STATUS_FIELD_PREDB);
|
||||
solrQuery.setQuery("*:*");
|
||||
solrQuery.addFilterQuery(STATUS_FIELD + ":" + STATUS_FIELD_PREDB);
|
||||
solrQuery.addFilterQuery(SearchUtils.RESOURCE_TYPE_FIELD + ":" + IndexableItem.TYPE);
|
||||
String dateRangeFilter = SearchUtils.LAST_INDEXED_FIELD + ":[* TO " + maxTime + "]";
|
||||
logDebugAndOut("Date range filter used; " + dateRangeFilter);
|
||||
@@ -166,11 +168,11 @@ public class SolrDatabaseResyncCli extends DSpaceRunnable<SolrDatabaseResyncCliS
|
||||
}
|
||||
|
||||
private String getMaxTime() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
Instant now = Instant.now();
|
||||
if (timeUntilReindex > 0) {
|
||||
cal.add(Calendar.MILLISECOND, -timeUntilReindex);
|
||||
now = now.minus(timeUntilReindex, ChronoUnit.MILLIS);
|
||||
}
|
||||
return SolrUtils.getDateFormatter().format(cal.getTime());
|
||||
return SolrUtils.getDateFormatter().format(now);
|
||||
}
|
||||
|
||||
private int getTimeUntilReindex() {
|
||||
|
@@ -7,11 +7,13 @@
|
||||
*/
|
||||
package org.dspace.app.statistics;
|
||||
|
||||
import static java.time.temporal.TemporalAdjusters.firstDayOfMonth;
|
||||
import static java.time.temporal.TemporalAdjusters.lastDayOfMonth;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
@@ -35,14 +37,14 @@ import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
public class CreateStatReport {
|
||||
|
||||
/**
|
||||
* Current date and time
|
||||
* Current date
|
||||
*/
|
||||
private static Calendar calendar = null;
|
||||
private static LocalDate calendar = null;
|
||||
|
||||
/**
|
||||
* Reporting start date and time
|
||||
* Reporting start date
|
||||
*/
|
||||
private static Calendar reportStartDate = null;
|
||||
private static LocalDate reportStartDate = null;
|
||||
|
||||
/**
|
||||
* Path of log directory
|
||||
@@ -84,22 +86,22 @@ public class CreateStatReport {
|
||||
FileInputStream fis = new java.io.FileInputStream(new File(configFile));
|
||||
Properties config = new Properties();
|
||||
config.load(fis);
|
||||
int startMonth = 0;
|
||||
int startMonth = 1;
|
||||
int startYear = 2005;
|
||||
try {
|
||||
startYear = Integer.parseInt(config.getProperty("start.year", "1").trim());
|
||||
startYear = Integer.parseInt(config.getProperty("start.year", "2005").trim());
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.err.println("start.year is incorrectly set in dstat.cfg. Must be a number (e.g. 2005).");
|
||||
System.exit(0);
|
||||
}
|
||||
try {
|
||||
startMonth = Integer.parseInt(config.getProperty("start.month", "2005").trim());
|
||||
startMonth = Integer.parseInt(config.getProperty("start.month", "1").trim());
|
||||
} catch (NumberFormatException nfe) {
|
||||
System.err.println("start.month is incorrectly set in dstat.cfg. Must be a number between 1 and 12.");
|
||||
System.exit(0);
|
||||
}
|
||||
reportStartDate = new GregorianCalendar(startYear, startMonth - 1, 1);
|
||||
calendar = new GregorianCalendar();
|
||||
reportStartDate = LocalDate.of(startYear, startMonth, 1);
|
||||
calendar = LocalDate.now();
|
||||
|
||||
// create context as super user
|
||||
context = new Context();
|
||||
@@ -168,25 +170,18 @@ public class CreateStatReport {
|
||||
String myConfigFile = null;
|
||||
boolean myLookUp = false;
|
||||
|
||||
Calendar start = new GregorianCalendar(calendar.get(Calendar.YEAR),
|
||||
calendar.get(Calendar.MONTH),
|
||||
calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||
Date myStartDate = start.getTime();
|
||||
|
||||
Calendar end = new GregorianCalendar(calendar.get(Calendar.YEAR),
|
||||
calendar.get(Calendar.MONTH),
|
||||
calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
Date myEndDate = end.getTime();
|
||||
LocalDate start = calendar.with(firstDayOfMonth());
|
||||
LocalDate end = calendar.with(lastDayOfMonth());
|
||||
|
||||
StringBuilder myOutFile = new StringBuilder(outputLogDirectory);
|
||||
myOutFile.append(outputPrefix);
|
||||
myOutFile.append(calendar.get(Calendar.YEAR));
|
||||
myOutFile.append(calendar.getYear());
|
||||
myOutFile.append("-");
|
||||
myOutFile.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myOutFile.append(calendar.getMonth());
|
||||
myOutFile.append(outputSuffix);
|
||||
|
||||
LogAnalyser
|
||||
.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate,
|
||||
.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), start, end,
|
||||
myLookUp);
|
||||
}
|
||||
|
||||
@@ -204,21 +199,19 @@ public class CreateStatReport {
|
||||
String myLogDir = null;
|
||||
String myFileTemplate = null;
|
||||
String myConfigFile = null;
|
||||
Date myStartDate = null;
|
||||
Date myEndDate = null;
|
||||
boolean myLookUp = false;
|
||||
|
||||
StringBuilder myOutFile = new StringBuilder(outputLogDirectory);
|
||||
myOutFile.append(outputPrefix);
|
||||
myOutFile.append(calendar.get(Calendar.YEAR));
|
||||
myOutFile.append(calendar.getYear());
|
||||
myOutFile.append("-");
|
||||
myOutFile.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myOutFile.append(calendar.getMonth());
|
||||
myOutFile.append("-");
|
||||
myOutFile.append(calendar.get(Calendar.DAY_OF_MONTH));
|
||||
myOutFile.append(calendar.getDayOfMonth());
|
||||
myOutFile.append(outputSuffix);
|
||||
|
||||
LogAnalyser
|
||||
.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate, myEndDate,
|
||||
.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), null, null,
|
||||
myLookUp);
|
||||
}
|
||||
|
||||
@@ -239,34 +232,25 @@ public class CreateStatReport {
|
||||
String myConfigFile = null;
|
||||
boolean myLookUp = false;
|
||||
|
||||
Calendar reportEndDate = new GregorianCalendar(calendar.get(Calendar.YEAR),
|
||||
calendar.get(Calendar.MONTH),
|
||||
calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
LocalDate reportEndDate = calendar.with(lastDayOfMonth());
|
||||
|
||||
Calendar currentMonth = (Calendar) reportStartDate.clone();
|
||||
while (currentMonth.before(reportEndDate)) {
|
||||
LocalDate currentMonth = reportStartDate;
|
||||
while (currentMonth.isBefore(reportEndDate)) {
|
||||
|
||||
Calendar start = new GregorianCalendar(currentMonth.get(Calendar.YEAR),
|
||||
currentMonth.get(Calendar.MONTH),
|
||||
currentMonth.getActualMinimum(Calendar.DAY_OF_MONTH));
|
||||
Date myStartDate = start.getTime();
|
||||
|
||||
Calendar end = new GregorianCalendar(currentMonth.get(Calendar.YEAR),
|
||||
currentMonth.get(Calendar.MONTH),
|
||||
currentMonth.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
Date myEndDate = end.getTime();
|
||||
LocalDate start = currentMonth.with(firstDayOfMonth());
|
||||
LocalDate end = currentMonth.with(lastDayOfMonth());
|
||||
|
||||
StringBuilder myOutFile = new StringBuilder(outputLogDirectory);
|
||||
myOutFile.append(outputPrefix);
|
||||
myOutFile.append(currentMonth.get(Calendar.YEAR));
|
||||
myOutFile.append(currentMonth.getYear());
|
||||
myOutFile.append("-");
|
||||
myOutFile.append(currentMonth.get(Calendar.MONTH) + 1);
|
||||
myOutFile.append(currentMonth.getMonth());
|
||||
myOutFile.append(outputSuffix);
|
||||
|
||||
LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), myStartDate,
|
||||
myEndDate, myLookUp);
|
||||
LogAnalyser.processLogs(context, myLogDir, myFileTemplate, myConfigFile, myOutFile.toString(), start,
|
||||
end, myLookUp);
|
||||
|
||||
currentMonth.add(Calendar.MONTH, 1);
|
||||
currentMonth = currentMonth.plus(1, ChronoUnit.MONTHS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,20 +270,20 @@ public class CreateStatReport {
|
||||
|
||||
StringBuilder myInput = new StringBuilder(outputLogDirectory);
|
||||
myInput.append(inputPrefix);
|
||||
myInput.append(calendar.get(Calendar.YEAR));
|
||||
myInput.append(calendar.getYear());
|
||||
myInput.append("-");
|
||||
myInput.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myInput.append(calendar.getMonth());
|
||||
myInput.append("-");
|
||||
myInput.append(calendar.get(Calendar.DAY_OF_MONTH));
|
||||
myInput.append(calendar.getDayOfMonth());
|
||||
myInput.append(outputSuffix);
|
||||
|
||||
StringBuilder myOutput = new StringBuilder(outputReportDirectory);
|
||||
myOutput.append(outputPrefix);
|
||||
myOutput.append(calendar.get(Calendar.YEAR));
|
||||
myOutput.append(calendar.getYear());
|
||||
myOutput.append("-");
|
||||
myOutput.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myOutput.append(calendar.getMonth());
|
||||
myOutput.append("-");
|
||||
myOutput.append(calendar.get(Calendar.DAY_OF_MONTH));
|
||||
myOutput.append(calendar.getDayOfMonth());
|
||||
myOutput.append(".");
|
||||
myOutput.append(myFormat);
|
||||
|
||||
@@ -321,32 +305,30 @@ public class CreateStatReport {
|
||||
String myFormat = "html";
|
||||
String myMap = null;
|
||||
|
||||
Calendar reportEndDate = new GregorianCalendar(calendar.get(Calendar.YEAR),
|
||||
calendar.get(Calendar.MONTH),
|
||||
calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
LocalDate reportEndDate = calendar.with(lastDayOfMonth());
|
||||
|
||||
Calendar currentMonth = (Calendar) reportStartDate.clone();
|
||||
LocalDate currentMonth = reportStartDate;
|
||||
|
||||
while (currentMonth.before(reportEndDate)) {
|
||||
while (currentMonth.isBefore(reportEndDate)) {
|
||||
|
||||
StringBuilder myInput = new StringBuilder(outputLogDirectory);
|
||||
myInput.append(inputPrefix);
|
||||
myInput.append(currentMonth.get(Calendar.YEAR));
|
||||
myInput.append(currentMonth.getYear());
|
||||
myInput.append("-");
|
||||
myInput.append(currentMonth.get(Calendar.MONTH) + 1);
|
||||
myInput.append(currentMonth.getMonth());
|
||||
myInput.append(outputSuffix);
|
||||
|
||||
StringBuilder myOutput = new StringBuilder(outputReportDirectory);
|
||||
myOutput.append(outputPrefix);
|
||||
myOutput.append(currentMonth.get(Calendar.YEAR));
|
||||
myOutput.append(currentMonth.getYear());
|
||||
myOutput.append("-");
|
||||
myOutput.append(currentMonth.get(Calendar.MONTH) + 1);
|
||||
myOutput.append(currentMonth.getMonth());
|
||||
myOutput.append(".");
|
||||
myOutput.append(myFormat);
|
||||
|
||||
ReportGenerator.processReport(context, myFormat, myInput.toString(), myOutput.toString(), myMap);
|
||||
|
||||
currentMonth.add(Calendar.MONTH, 1);
|
||||
currentMonth = currentMonth.plus(1, ChronoUnit.MONTHS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,16 +347,16 @@ public class CreateStatReport {
|
||||
|
||||
StringBuilder myInput = new StringBuilder(outputLogDirectory);
|
||||
myInput.append(inputPrefix);
|
||||
myInput.append(calendar.get(Calendar.YEAR));
|
||||
myInput.append(calendar.getYear());
|
||||
myInput.append("-");
|
||||
myInput.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myInput.append(calendar.getMonth());
|
||||
myInput.append(outputSuffix);
|
||||
|
||||
StringBuilder myOutput = new StringBuilder(outputReportDirectory);
|
||||
myOutput.append(outputPrefix);
|
||||
myOutput.append(calendar.get(Calendar.YEAR));
|
||||
myOutput.append(calendar.getYear());
|
||||
myOutput.append("-");
|
||||
myOutput.append(calendar.get(Calendar.MONTH) + 1);
|
||||
myOutput.append(calendar.getMonth());
|
||||
myOutput.append(".");
|
||||
myOutput.append(myFormat);
|
||||
|
||||
|
@@ -13,8 +13,8 @@ import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.DateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -50,12 +50,12 @@ public class HTMLReport implements Report {
|
||||
/**
|
||||
* start date for report
|
||||
*/
|
||||
private Date start = null;
|
||||
private LocalDate start = null;
|
||||
|
||||
/**
|
||||
* end date for report
|
||||
*/
|
||||
private Date end = null;
|
||||
private LocalDate end = null;
|
||||
|
||||
/**
|
||||
* the output file to which to write aggregation data
|
||||
@@ -190,8 +190,8 @@ public class HTMLReport implements Report {
|
||||
* @param start the start date for the report
|
||||
*/
|
||||
@Override
|
||||
public void setStartDate(Date start) {
|
||||
this.start = (start == null ? null : new Date(start.getTime()));
|
||||
public void setStartDate(LocalDate start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
|
||||
@@ -201,8 +201,8 @@ public class HTMLReport implements Report {
|
||||
* @param end the end date for the report
|
||||
*/
|
||||
@Override
|
||||
public void setEndDate(Date end) {
|
||||
this.end = (end == null ? null : new Date(end.getTime()));
|
||||
public void setEndDate(LocalDate end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -14,18 +14,16 @@ import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -265,7 +263,7 @@ public class LogAnalyser {
|
||||
/**
|
||||
* process timing clock
|
||||
*/
|
||||
private static Calendar startTime = null;
|
||||
private static Instant startTime = null;
|
||||
|
||||
/////////////////////////
|
||||
// command line options
|
||||
@@ -298,22 +296,22 @@ public class LogAnalyser {
|
||||
/**
|
||||
* the starting date of the report
|
||||
*/
|
||||
private static Date startDate = null;
|
||||
private static LocalDate startDate = null;
|
||||
|
||||
/**
|
||||
* the end date of the report
|
||||
*/
|
||||
private static Date endDate = null;
|
||||
private static LocalDate endDate = null;
|
||||
|
||||
/**
|
||||
* the starting date of the report as obtained from the log files
|
||||
*/
|
||||
private static Date logStartDate = null;
|
||||
private static LocalDate logStartDate = null;
|
||||
|
||||
/**
|
||||
* the end date of the report as obtained from the log files
|
||||
*/
|
||||
private static Date logEndDate = null;
|
||||
private static LocalDate logEndDate = null;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
@@ -331,7 +329,7 @@ public class LogAnalyser {
|
||||
public static void main(String[] argv)
|
||||
throws Exception, SQLException {
|
||||
// first, start the processing clock
|
||||
startTime = new GregorianCalendar();
|
||||
startTime = Instant.now();
|
||||
|
||||
// create context as super user
|
||||
Context context = new Context();
|
||||
@@ -342,8 +340,8 @@ public class LogAnalyser {
|
||||
String myFileTemplate = null;
|
||||
String myConfigFile = null;
|
||||
String myOutFile = null;
|
||||
Date myStartDate = null;
|
||||
Date myEndDate = null;
|
||||
LocalDate myStartDate = null;
|
||||
LocalDate myEndDate = null;
|
||||
boolean myLookUp = false;
|
||||
|
||||
// Define command line options.
|
||||
@@ -434,14 +432,14 @@ public class LogAnalyser {
|
||||
*/
|
||||
public static String processLogs(Context context, String myLogDir,
|
||||
String myFileTemplate, String myConfigFile,
|
||||
String myOutFile, Date myStartDate,
|
||||
Date myEndDate, boolean myLookUp)
|
||||
String myOutFile, LocalDate myStartDate,
|
||||
LocalDate myEndDate, boolean myLookUp)
|
||||
throws IOException, SQLException, SearchServiceException {
|
||||
// FIXME: perhaps we should have all parameters and aggregators put
|
||||
// together in a single aggregating object
|
||||
|
||||
// if the timer has not yet been started, then start it
|
||||
startTime = new GregorianCalendar();
|
||||
startTime = Instant.now();
|
||||
|
||||
//instantiate aggregators
|
||||
actionAggregator = new HashMap<>();
|
||||
@@ -658,7 +656,7 @@ public class LogAnalyser {
|
||||
*/
|
||||
public static void setParameters(String myLogDir, String myFileTemplate,
|
||||
String myConfigFile, String myOutFile,
|
||||
Date myStartDate, Date myEndDate,
|
||||
LocalDate myStartDate, LocalDate myEndDate,
|
||||
boolean myLookUp) {
|
||||
|
||||
if (myLogDir != null) {
|
||||
@@ -676,11 +674,11 @@ public class LogAnalyser {
|
||||
}
|
||||
|
||||
if (myStartDate != null) {
|
||||
startDate = new Date(myStartDate.getTime());
|
||||
startDate = myStartDate;
|
||||
}
|
||||
|
||||
if (myEndDate != null) {
|
||||
endDate = new Date(myEndDate.getTime());
|
||||
endDate = myEndDate;
|
||||
}
|
||||
|
||||
if (myOutFile != null) {
|
||||
@@ -722,18 +720,17 @@ public class LogAnalyser {
|
||||
summary.append("service_name=").append(name).append("\n");
|
||||
|
||||
// output the date information if necessary
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy");
|
||||
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd'/'MM'/'yyyy");
|
||||
if (startDate != null) {
|
||||
summary.append("start_date=").append(sdf.format(startDate)).append("\n");
|
||||
summary.append("start_date=").append(formatter.format(startDate)).append("\n");
|
||||
} else if (logStartDate != null) {
|
||||
summary.append("start_date=").append(sdf.format(logStartDate)).append("\n");
|
||||
summary.append("start_date=").append(formatter.format(logStartDate)).append("\n");
|
||||
}
|
||||
|
||||
if (endDate != null) {
|
||||
summary.append("end_date=").append(sdf.format(endDate)).append("\n");
|
||||
summary.append("end_date=").append(formatter.format(endDate)).append("\n");
|
||||
} else if (logEndDate != null) {
|
||||
summary.append("end_date=").append(sdf.format(logEndDate)).append("\n");
|
||||
summary.append("end_date=").append(formatter.format(logEndDate)).append("\n");
|
||||
}
|
||||
|
||||
// write out the archive stats
|
||||
@@ -813,8 +810,7 @@ public class LogAnalyser {
|
||||
}
|
||||
|
||||
// insert the analysis processing time information
|
||||
Calendar endTime = new GregorianCalendar();
|
||||
long timeInMillis = (endTime.getTimeInMillis() - startTime.getTimeInMillis());
|
||||
long timeInMillis = Instant.now().toEpochMilli() - startTime.toEpochMilli();
|
||||
summary.append("analysis_process_time=")
|
||||
.append(Long.toString(timeInMillis / 1000)).append("\n");
|
||||
|
||||
@@ -1072,13 +1068,13 @@ public class LogAnalyser {
|
||||
* @return a date object containing the date, with the time set to
|
||||
* 00:00:00
|
||||
*/
|
||||
public static Date parseDate(String date) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy'-'MM'-'dd");
|
||||
Date parsedDate = null;
|
||||
public static LocalDate parseDate(String date) {
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
|
||||
LocalDate parsedDate = null;
|
||||
|
||||
try {
|
||||
parsedDate = sdf.parse(date);
|
||||
} catch (ParseException e) {
|
||||
parsedDate = LocalDate.parse(date, formatter);
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("The date is not in the correct format");
|
||||
System.exit(0);
|
||||
}
|
||||
@@ -1092,11 +1088,8 @@ public class LogAnalyser {
|
||||
* @param date the date to be converted
|
||||
* @return A string of the form YYYY-MM-DD
|
||||
*/
|
||||
public static String unParseDate(Date date) {
|
||||
// Use SimpleDateFormat
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy'-'MM'-'dd'T'hh:mm:ss'Z'");
|
||||
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return sdf.format(date);
|
||||
public static String unParseDate(LocalDate date) {
|
||||
return DateTimeFormatter.ISO_LOCAL_DATE.format(date);
|
||||
}
|
||||
|
||||
|
||||
@@ -1238,8 +1231,8 @@ public class LogAnalyser {
|
||||
}
|
||||
accessionedQuery.append("]");
|
||||
discoverQuery.addFilterQueries(accessionedQuery.toString());
|
||||
discoverQuery.addFilterQueries("withdrawn: false");
|
||||
discoverQuery.addFilterQueries("archived: true");
|
||||
discoverQuery.addFilterQueries("withdrawn:false");
|
||||
discoverQuery.addFilterQueries("archived:true");
|
||||
|
||||
return (int) SearchUtils.getSearchService().search(context, discoverQuery).getTotalSearchResults();
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.statistics;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* This class represents a single log file line and the operations that can be
|
||||
@@ -22,7 +22,7 @@ public class LogLine {
|
||||
/**
|
||||
* the date of the log file line
|
||||
*/
|
||||
private Date date = null;
|
||||
private LocalDate date = null;
|
||||
|
||||
/**
|
||||
* the level of the log line type
|
||||
@@ -47,7 +47,7 @@ public class LogLine {
|
||||
/**
|
||||
* constructor to create new statistic
|
||||
*/
|
||||
LogLine(Date date, String level, String user, String action, String params) {
|
||||
LogLine(LocalDate date, String level, String user, String action, String params) {
|
||||
this.date = date;
|
||||
this.level = level;
|
||||
this.user = user;
|
||||
@@ -60,8 +60,8 @@ public class LogLine {
|
||||
*
|
||||
* @return the date of this log line
|
||||
*/
|
||||
public Date getDate() {
|
||||
return this.date == null ? null : new Date(this.date.getTime());
|
||||
public LocalDate getDate() {
|
||||
return this.date;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,12 +108,12 @@ public class LogLine {
|
||||
/**
|
||||
* find out if this log file line is before the given date
|
||||
*
|
||||
* @param date the date to be compared to
|
||||
* @param compareDate the date to be compared to
|
||||
* @return true if the line is before the given date, false if not
|
||||
*/
|
||||
public boolean beforeDate(Date date) {
|
||||
if (date != null) {
|
||||
return (date.compareTo(this.date) >= 0);
|
||||
public boolean beforeDate(LocalDate compareDate) {
|
||||
if (compareDate != null) {
|
||||
return this.date.isBefore(compareDate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -122,12 +122,12 @@ public class LogLine {
|
||||
/**
|
||||
* find out if this log file line is after the given date
|
||||
*
|
||||
* @param date the date to be compared to
|
||||
* @param compareDate the date to be compared to
|
||||
* @return true if the line is after the given date, false if not
|
||||
*/
|
||||
public boolean afterDate(Date date) {
|
||||
if (date != null) {
|
||||
return (date.compareTo(this.date) <= 0);
|
||||
public boolean afterDate(LocalDate compareDate) {
|
||||
if (compareDate != null) {
|
||||
return this.date.isAfter(compareDate);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.statistics;
|
||||
|
||||
import java.util.Date;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Sn interface to a generic report generating
|
||||
@@ -120,12 +120,12 @@ public interface Report {
|
||||
*
|
||||
* @param start the start date for the report
|
||||
*/
|
||||
public abstract void setStartDate(Date start);
|
||||
public abstract void setStartDate(LocalDate start);
|
||||
|
||||
/**
|
||||
* set the end date for the report
|
||||
*
|
||||
* @param end the end date for the report
|
||||
*/
|
||||
public abstract void setEndDate(Date end);
|
||||
public abstract void setEndDate(LocalDate end);
|
||||
}
|
||||
|
@@ -13,12 +13,11 @@ import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -132,12 +131,12 @@ public class ReportGenerator {
|
||||
/**
|
||||
* start date of this report
|
||||
*/
|
||||
private static Date startDate = null;
|
||||
private static LocalDate startDate = null;
|
||||
|
||||
/**
|
||||
* end date of this report
|
||||
*/
|
||||
private static Date endDate = null;
|
||||
private static LocalDate endDate = null;
|
||||
|
||||
/**
|
||||
* the time taken to build the aggregation file from the log
|
||||
@@ -175,7 +174,7 @@ public class ReportGenerator {
|
||||
/**
|
||||
* process timing clock
|
||||
*/
|
||||
private static Calendar startTime = null;
|
||||
private static Instant startTime = null;
|
||||
|
||||
/**
|
||||
* a map from log file action to human readable action
|
||||
@@ -326,7 +325,7 @@ public class ReportGenerator {
|
||||
public static void processReport(Context context, Report report,
|
||||
String myInput)
|
||||
throws Exception, SQLException {
|
||||
startTime = new GregorianCalendar();
|
||||
startTime = Instant.now();
|
||||
|
||||
/** instantiate aggregators */
|
||||
actionAggregator = new HashMap<>();
|
||||
@@ -492,8 +491,7 @@ public class ReportGenerator {
|
||||
report.addBlock(levels);
|
||||
|
||||
// get the display processing time information
|
||||
Calendar endTime = new GregorianCalendar();
|
||||
long timeInMillis = (endTime.getTimeInMillis() - startTime.getTimeInMillis());
|
||||
long timeInMillis = Instant.now().toEpochMilli() - startTime.toEpochMilli();
|
||||
int outputProcessTime = (int) (timeInMillis / 1000);
|
||||
|
||||
// prepare the processing information statistics
|
||||
@@ -666,7 +664,7 @@ public class ReportGenerator {
|
||||
|
||||
// first initialise a date format object to do our date processing
|
||||
// if necessary
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("dd'/'MM'/'yyyy");
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd'/'MM'/'yyyy");
|
||||
|
||||
// FIXME: although this works, it is not very elegant
|
||||
// loop through the aggregator file and read in the values
|
||||
@@ -738,9 +736,9 @@ public class ReportGenerator {
|
||||
} else if ("service_name".equals(section)) {
|
||||
name = value;
|
||||
} else if ("start_date".equals(section)) {
|
||||
startDate = sdf.parse(value);
|
||||
startDate = LocalDate.parse(value, formatter);
|
||||
} else if ("end_date".equals(section)) {
|
||||
endDate = sdf.parse(value);
|
||||
endDate = LocalDate.parse(value, formatter);
|
||||
} else if ("analysis_process_time".equals(section)) {
|
||||
processTime = Integer.parseInt(value);
|
||||
} else if ("general_summary".equals(section)) {
|
||||
|
@@ -9,19 +9,20 @@ package org.dspace.app.statistics;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
@@ -35,7 +36,7 @@ public class StatisticsLoader {
|
||||
private static StatsFile generalAnalysis = null;
|
||||
private static StatsFile generalReport = null;
|
||||
|
||||
private static Date lastLoaded = null;
|
||||
private static Instant lastLoaded = null;
|
||||
private static int fileCount = 0;
|
||||
|
||||
private static Pattern analysisMonthlyPattern;
|
||||
@@ -43,8 +44,8 @@ public class StatisticsLoader {
|
||||
private static Pattern reportMonthlyPattern;
|
||||
private static Pattern reportGeneralPattern;
|
||||
|
||||
private static ThreadLocal<DateFormat> monthlySDF;
|
||||
private static ThreadLocal<DateFormat> generalSDF;
|
||||
private static ThreadLocal<DateTimeFormatter> monthlySDF;
|
||||
private static ThreadLocal<DateTimeFormatter> generalSDF;
|
||||
|
||||
// one time initialisation of the regex patterns and formatters we will use
|
||||
static {
|
||||
@@ -53,17 +54,17 @@ public class StatisticsLoader {
|
||||
reportMonthlyPattern = Pattern.compile("report-([0-9][0-9][0-9][0-9]-[0-9]+)\\.html");
|
||||
reportGeneralPattern = Pattern.compile("report-general-([0-9]+-[0-9]+-[0-9]+)\\.html");
|
||||
|
||||
monthlySDF = new ThreadLocal<DateFormat>() {
|
||||
monthlySDF = new ThreadLocal<DateTimeFormatter>() {
|
||||
@Override
|
||||
protected DateFormat initialValue() {
|
||||
return new SimpleDateFormat("yyyy'-'M");
|
||||
protected DateTimeFormatter initialValue() {
|
||||
return DateTimeFormatter.ofPattern("yyyy'-'M");
|
||||
}
|
||||
};
|
||||
|
||||
generalSDF = new ThreadLocal<DateFormat>() {
|
||||
generalSDF = new ThreadLocal<DateTimeFormatter>() {
|
||||
@Override
|
||||
protected DateFormat initialValue() {
|
||||
return new SimpleDateFormat("yyyy'-'M'-'dd");
|
||||
protected DateTimeFormatter initialValue() {
|
||||
return DateTimeFormatter.ofPattern("yyyy'-'M'-'dd");
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -78,7 +79,7 @@ public class StatisticsLoader {
|
||||
*
|
||||
* @return array of dates
|
||||
*/
|
||||
public static Date[] getMonthlyReportDates() {
|
||||
public static LocalDate[] getMonthlyReportDates() {
|
||||
return sortDatesDescending(getDatesFromMap(monthlyReports));
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@ public class StatisticsLoader {
|
||||
*
|
||||
* @return array of dates
|
||||
*/
|
||||
public static Date[] getMonthlyAnalysisDates() {
|
||||
public static LocalDate[] getMonthlyAnalysisDates() {
|
||||
return sortDatesDescending(getDatesFromMap(monthlyAnalysis));
|
||||
}
|
||||
|
||||
@@ -97,15 +98,15 @@ public class StatisticsLoader {
|
||||
* @param monthlyMap map
|
||||
* @return array of dates
|
||||
*/
|
||||
protected static Date[] getDatesFromMap(Map<String, StatsFile> monthlyMap) {
|
||||
protected static LocalDate[] getDatesFromMap(Map<String, StatsFile> monthlyMap) {
|
||||
Set<String> keys = monthlyMap.keySet();
|
||||
Date[] dates = new Date[keys.size()];
|
||||
LocalDate[] dates = new LocalDate[keys.size()];
|
||||
int i = 0;
|
||||
for (String date : keys) {
|
||||
try {
|
||||
dates[i] = monthlySDF.get().parse(date);
|
||||
} catch (ParseException pe) {
|
||||
// ignore
|
||||
dates[i] = YearMonth.parse(date, monthlySDF.get()).atDay(1);
|
||||
} catch (DateTimeParseException pe) {
|
||||
//ignore
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -120,19 +121,19 @@ public class StatisticsLoader {
|
||||
* @param dates array of dates
|
||||
* @return sorted dates.
|
||||
*/
|
||||
protected static Date[] sortDatesDescending(Date[] dates) {
|
||||
Arrays.sort(dates, new Comparator<Date>() {
|
||||
protected static LocalDate[] sortDatesDescending(LocalDate[] dates) {
|
||||
Arrays.sort(dates, new Comparator<LocalDate>() {
|
||||
@Override
|
||||
public int compare(Date d1, Date d2) {
|
||||
public int compare(LocalDate d1, LocalDate d2) {
|
||||
if (d1 == null && d2 == null) {
|
||||
return 0;
|
||||
} else if (d1 == null) {
|
||||
return -1;
|
||||
} else if (d2 == null) {
|
||||
return 1;
|
||||
} else if (d1.before(d2)) {
|
||||
} else if (d1.isBefore(d2)) {
|
||||
return 1;
|
||||
} else if (d2.before(d1)) {
|
||||
} else if (d2.isBefore(d1)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -203,7 +204,7 @@ public class StatisticsLoader {
|
||||
StatisticsLoader.loadFileList(fileList);
|
||||
} else if (lastLoaded == null) {
|
||||
StatisticsLoader.loadFileList(fileList);
|
||||
} else if (DateUtils.addHours(lastLoaded, 1).before(new Date())) {
|
||||
} else if (Instant.now().isAfter(lastLoaded.plus(1, ChronoUnit.HOURS))) {
|
||||
StatisticsLoader.loadFileList(fileList);
|
||||
}
|
||||
}
|
||||
@@ -256,7 +257,7 @@ public class StatisticsLoader {
|
||||
statsFile = makeStatsFile(thisFile, analysisGeneralPattern, generalSDF.get());
|
||||
if (statsFile != null) {
|
||||
// If it is, ensure that we are pointing to the most recent file
|
||||
if (newGeneralAnalysis == null || statsFile.date.after(newGeneralAnalysis.date)) {
|
||||
if (newGeneralAnalysis == null || statsFile.date.isAfter(newGeneralAnalysis.date)) {
|
||||
newGeneralAnalysis = statsFile;
|
||||
}
|
||||
}
|
||||
@@ -268,7 +269,7 @@ public class StatisticsLoader {
|
||||
statsFile = makeStatsFile(thisFile, reportGeneralPattern, generalSDF.get());
|
||||
if (statsFile != null) {
|
||||
// If it is, ensure that we are pointing to the most recent file
|
||||
if (newGeneralReport == null || statsFile.date.after(newGeneralReport.date)) {
|
||||
if (newGeneralReport == null || statsFile.date.isAfter(newGeneralReport.date)) {
|
||||
newGeneralReport = statsFile;
|
||||
}
|
||||
}
|
||||
@@ -281,7 +282,7 @@ public class StatisticsLoader {
|
||||
monthlyReports = newMonthlyReports;
|
||||
generalAnalysis = newGeneralAnalysis;
|
||||
generalReport = newGeneralReport;
|
||||
lastLoaded = new Date();
|
||||
lastLoaded = Instant.now();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,10 +293,10 @@ public class StatisticsLoader {
|
||||
*
|
||||
* @param thisFile file
|
||||
* @param thisPattern pattern
|
||||
* @param sdf date format
|
||||
* @param formatter date formatter
|
||||
* @return StatsFile
|
||||
*/
|
||||
private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, DateFormat sdf) {
|
||||
private static StatsFile makeStatsFile(File thisFile, Pattern thisPattern, DateTimeFormatter formatter) {
|
||||
Matcher matcher = thisPattern.matcher(thisFile.getName());
|
||||
if (matcher.matches()) {
|
||||
StatsFile sf = new StatsFile();
|
||||
@@ -304,8 +305,8 @@ public class StatisticsLoader {
|
||||
sf.dateStr = matcher.group(1).trim();
|
||||
|
||||
try {
|
||||
sf.date = sdf.parse(sf.dateStr);
|
||||
} catch (ParseException e) {
|
||||
sf.date = LocalDate.parse(sf.dateStr, formatter);
|
||||
} catch (DateTimeParseException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
@@ -333,7 +334,7 @@ public class StatisticsLoader {
|
||||
private static class StatsFile {
|
||||
File file;
|
||||
String path;
|
||||
Date date;
|
||||
LocalDate date;
|
||||
String dateStr;
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import java.util.UUID;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.solr.client.solrj.SolrServerException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.external.model.ExternalDataObject;
|
||||
@@ -137,4 +138,16 @@ public abstract class SolrSuggestionProvider implements SuggestionProvider {
|
||||
*/
|
||||
protected abstract boolean isExternalDataObjectPotentiallySuggested(Context context,
|
||||
ExternalDataObject externalDataObject);
|
||||
|
||||
/**
|
||||
* Save a List of ImportRecord into Solr.
|
||||
* ImportRecord will be translate into a SolrDocument by the method translateImportRecordToSolrDocument.
|
||||
*
|
||||
* @param context the DSpace Context
|
||||
* @param item a DSpace Item
|
||||
* @throws SolrServerException
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract void importRecords(Context context, Item item) throws Exception;
|
||||
|
||||
}
|
||||
|
@@ -7,8 +7,10 @@
|
||||
*/
|
||||
package org.dspace.app.suggestion;
|
||||
|
||||
import org.dspace.app.suggestion.scorer.EvidenceScorer;
|
||||
|
||||
/**
|
||||
* This DTO class is returned by an {@link org.dspace.app.suggestion.openaire.EvidenceScorer} to model the concept of
|
||||
* This DTO class is returned by an {@link EvidenceScorer} to model the concept of
|
||||
* an evidence / fact that has been used to evaluate the precision of a suggestion increasing or decreasing the score
|
||||
* of the suggestion.
|
||||
*
|
||||
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
package org.dspace.app.suggestion.loader;
|
||||
|
||||
import static org.dspace.app.suggestion.SuggestionUtils.getAllEntriesByMetadatum;
|
||||
import static org.dspace.app.suggestion.SuggestionUtils.getFirstEntryByMetadatum;
|
||||
@@ -19,6 +19,8 @@ import org.apache.solr.client.solrj.SolrServerException;
|
||||
import org.dspace.app.suggestion.SolrSuggestionProvider;
|
||||
import org.dspace.app.suggestion.Suggestion;
|
||||
import org.dspace.app.suggestion.SuggestionEvidence;
|
||||
import org.dspace.app.suggestion.scorer.AuthorNamesScorer;
|
||||
import org.dspace.app.suggestion.scorer.EvidenceScorer;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.dto.MetadataValueDTO;
|
||||
import org.dspace.core.Context;
|
||||
@@ -28,23 +30,23 @@ import org.dspace.services.ConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Class responsible to load and manage ImportRecords from OpenAIRE
|
||||
* Class responsible to load and manage ImportRecords from external sources
|
||||
*
|
||||
* @author Pasquale Cavallo (pasquale.cavallo at 4science dot it)
|
||||
*
|
||||
*/
|
||||
public class PublicationLoader extends SolrSuggestionProvider {
|
||||
|
||||
private List<String> names;
|
||||
protected List<String> names;
|
||||
|
||||
private ExternalDataProvider primaryProvider;
|
||||
protected ExternalDataProvider primaryProvider;
|
||||
|
||||
private List<ExternalDataProvider> otherProviders;
|
||||
protected List<ExternalDataProvider> otherProviders;
|
||||
|
||||
@Autowired
|
||||
private ConfigurationService configurationService;
|
||||
protected ConfigurationService configurationService;
|
||||
|
||||
private List<EvidenceScorer> pipeline;
|
||||
protected List<EvidenceScorer> pipeline;
|
||||
|
||||
public void setPrimaryProvider(ExternalDataProvider primaryProvider) {
|
||||
this.primaryProvider = primaryProvider;
|
||||
@@ -65,8 +67,8 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
/**
|
||||
* This method filter a list of ImportRecords using a pipeline of AuthorNamesApprover
|
||||
* and return a filtered list of ImportRecords.
|
||||
*
|
||||
* @see org.dspace.app.suggestion.openaire.AuthorNamesScorer
|
||||
*
|
||||
* @see AuthorNamesScorer
|
||||
* @param researcher the researcher Item
|
||||
* @param importRecords List of import record
|
||||
* @return a list of filtered import records
|
||||
@@ -103,8 +105,9 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
* @throws SolrServerException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void importAuthorRecords(Context context, Item researcher)
|
||||
throws SolrServerException, IOException {
|
||||
@Override
|
||||
public void importRecords(Context context, Item researcher)
|
||||
throws Exception {
|
||||
int offset = 0;
|
||||
int limit = 10;
|
||||
int loaded = limit;
|
||||
@@ -132,18 +135,20 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
* @return Suggestion
|
||||
*/
|
||||
private Suggestion translateImportRecordToSuggestion(Item item, ExternalDataObject record) {
|
||||
String openAireId = record.getId();
|
||||
Suggestion suggestion = new Suggestion(getSourceName(), item, openAireId);
|
||||
String recordId = record.getId();
|
||||
Suggestion suggestion = new Suggestion(getSourceName(), item, recordId);
|
||||
suggestion.setDisplay(getFirstEntryByMetadatum(record, "dc", "title", null));
|
||||
suggestion.getMetadata().add(
|
||||
new MetadataValueDTO("dc", "title", null, null, getFirstEntryByMetadatum(record, "dc", "title", null)));
|
||||
new MetadataValueDTO("dc", "title", null, null, getFirstEntryByMetadatum(record, "dc", "title", null)));
|
||||
suggestion.getMetadata().add(new MetadataValueDTO("dc", "date", "issued", null,
|
||||
getFirstEntryByMetadatum(record, "dc", "date", "issued")));
|
||||
getFirstEntryByMetadatum(record, "dc", "date", "issued")));
|
||||
suggestion.getMetadata().add(new MetadataValueDTO("dc", "description", "abstract", null,
|
||||
getFirstEntryByMetadatum(record, "dc", "description", "abstract")));
|
||||
getFirstEntryByMetadatum(record, "dc", "description",
|
||||
"abstract")));
|
||||
suggestion.setExternalSourceUri(configurationService.getProperty("dspace.server.url")
|
||||
+ "/api/integration/externalsources/" + primaryProvider.getSourceIdentifier() + "/entryValues/"
|
||||
+ openAireId);
|
||||
+ "/api/integration/externalsources/" +
|
||||
primaryProvider.getSourceIdentifier() + "/entryValues/"
|
||||
+ recordId);
|
||||
for (String o : getAllEntriesByMetadatum(record, "dc", "source", null)) {
|
||||
suggestion.getMetadata().add(new MetadataValueDTO("dc", "source", null, null, o));
|
||||
}
|
||||
@@ -162,10 +167,10 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load metadata from OpenAIRE using the import service. The service use the value
|
||||
* get from metadata key defined in class level variable names as author to query OpenAIRE.
|
||||
*
|
||||
* @see org.dspace.importer.external.openaire.service.OpenAireImportMetadataSourceServiceImpl
|
||||
* Load metadata from external source using the import service. The service use the value
|
||||
* get from metadata key defined in class level variable names as author to query external source.
|
||||
*
|
||||
* @see org.dspace.importer.external.service.AbstractImportMetadataSourceService
|
||||
* @param searchValues query
|
||||
* @param researcher item to extract metadata from
|
||||
* @param limit for pagination purpose
|
||||
@@ -173,7 +178,7 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
* @return list of ImportRecord
|
||||
*/
|
||||
private List<ExternalDataObject> getImportRecords(List<String> searchValues,
|
||||
Item researcher, int offset, int limit) {
|
||||
Item researcher, int offset, int limit) {
|
||||
List<ExternalDataObject> matchingRecords = new ArrayList<>();
|
||||
for (String searchValue : searchValues) {
|
||||
matchingRecords.addAll(
|
||||
@@ -205,7 +210,7 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
/**
|
||||
* Check if the ImportRecord is already present in the list.
|
||||
* The comparison is made on the value of metadatum with key 'dc.identifier.other'
|
||||
*
|
||||
*
|
||||
* @param dto An importRecord instance
|
||||
* @param importRecords a list of importRecord
|
||||
* @return true if dto is already present in importRecords, false otherwise
|
||||
@@ -230,7 +235,7 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
* @param researcher DSpace item
|
||||
* @return list of metadata values
|
||||
*/
|
||||
private List<String> searchMetadataValues(Item researcher) {
|
||||
public List<String> searchMetadataValues(Item researcher) {
|
||||
List<String> authors = new ArrayList<String>();
|
||||
for (String name : names) {
|
||||
String value = itemService.getMetadata(researcher, name);
|
||||
@@ -247,7 +252,8 @@ public class PublicationLoader extends SolrSuggestionProvider {
|
||||
return true;
|
||||
} else if (otherProviders != null) {
|
||||
return otherProviders.stream()
|
||||
.anyMatch(x -> StringUtils.equals(externalDataObject.getSource(), x.getSourceIdentifier()));
|
||||
.anyMatch(
|
||||
x -> StringUtils.equals(externalDataObject.getSource(), x.getSourceIdentifier()));
|
||||
} else {
|
||||
return false;
|
||||
}
|
@@ -1,115 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.SearchService;
|
||||
import org.dspace.discovery.SearchServiceException;
|
||||
import org.dspace.discovery.SearchUtils;
|
||||
import org.dspace.discovery.utils.DiscoverQueryBuilder;
|
||||
import org.dspace.discovery.utils.parameter.QueryBuilderSearchFilter;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.sort.SortOption;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* Runner responsible to import metadata about authors from OpenAIRE to Solr.
|
||||
* This runner works in two ways:
|
||||
* If -s parameter with a valid UUID is received, then the specific researcher
|
||||
* with this UUID will be used.
|
||||
* Invocation without any parameter results in massive import, processing all
|
||||
* authors registered in DSpace.
|
||||
*
|
||||
* @author Alessandro Martelli (alessandro.martelli at 4science.it)
|
||||
*/
|
||||
public class PublicationLoaderRunnable
|
||||
extends DSpaceRunnable<PublicationLoaderScriptConfiguration<PublicationLoaderRunnable>> {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private PublicationLoader oairePublicationLoader = null;
|
||||
|
||||
protected Context context;
|
||||
|
||||
protected String profile;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public PublicationLoaderScriptConfiguration<PublicationLoaderRunnable> getScriptConfiguration() {
|
||||
PublicationLoaderScriptConfiguration configuration = new DSpace().getServiceManager()
|
||||
.getServiceByName("import-openaire-suggestions", PublicationLoaderScriptConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
|
||||
oairePublicationLoader = new DSpace().getServiceManager().getServiceByName(
|
||||
"OpenairePublicationLoader", PublicationLoader.class);
|
||||
|
||||
profile = commandLine.getOptionValue("s");
|
||||
if (profile == null) {
|
||||
LOGGER.info("No argument for -s, process all profiles");
|
||||
} else {
|
||||
LOGGER.info("Process eperson item with UUID {}", profile);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void internalRun() throws Exception {
|
||||
|
||||
context = new Context();
|
||||
|
||||
Iterator<Item> researchers = getResearchers(profile);
|
||||
while (researchers.hasNext()) {
|
||||
Item researcher = researchers.next();
|
||||
oairePublicationLoader.importAuthorRecords(context, researcher);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Item(s) which map a researcher from Solr. If the uuid is specified,
|
||||
* the researcher with this UUID will be chosen. If the uuid doesn't match any
|
||||
* researcher, the method returns an empty array list. If uuid is null, all
|
||||
* research will be return.
|
||||
*
|
||||
* @param profileUUID uuid of the researcher. If null, all researcher will be
|
||||
* returned.
|
||||
* @return the researcher with specified UUID or all researchers
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Iterator<Item> getResearchers(String profileUUID) {
|
||||
SearchService searchService = new DSpace().getSingletonService(SearchService.class);
|
||||
DiscoverQueryBuilder queryBuilder = SearchUtils.getQueryBuilder();
|
||||
List<QueryBuilderSearchFilter> filters = new ArrayList<>();
|
||||
String query = "*:*";
|
||||
if (profileUUID != null) {
|
||||
query = "search.resourceid:" + profileUUID;
|
||||
}
|
||||
try {
|
||||
DiscoverQuery discoverQuery = queryBuilder.buildQuery(context, null,
|
||||
SearchUtils.getDiscoveryConfigurationByName("person"),
|
||||
query, filters,
|
||||
"Item", 10, Long.getLong("0"), null, SortOption.DESCENDING);
|
||||
return searchService.iteratorSearch(context, null, discoverQuery);
|
||||
} catch (SearchServiceException e) {
|
||||
LOGGER.error("Unable to read researcher on solr", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
public class PublicationLoaderRunnableCli extends PublicationLoaderRunnable {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public PublicationLoaderCliScriptConfiguration getScriptConfiguration() {
|
||||
PublicationLoaderCliScriptConfiguration configuration = new DSpace().getServiceManager()
|
||||
.getServiceByName("import-openaire-suggestions", PublicationLoaderCliScriptConfiguration.class);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
super.setup();
|
||||
|
||||
// in case of CLI we show the help prompt
|
||||
if (commandLine.hasOption('h')) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("Import Researchers Suggestions", getScriptConfiguration().getOptions());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
|
||||
public class PublicationLoaderScriptConfiguration<T extends PublicationLoaderRunnable>
|
||||
extends ScriptConfiguration<T> {
|
||||
|
||||
private Class<T> dspaceRunnableClass;
|
||||
|
||||
@Override
|
||||
public Class<T> getDspaceRunnableClass() {
|
||||
return dspaceRunnableClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the dspaceRunnableClass
|
||||
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this PublicationLoaderScriptConfiguration
|
||||
*/
|
||||
@Override
|
||||
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
|
||||
this.dspaceRunnableClass = dspaceRunnableClass;
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public boolean isAllowedToExecute(Context context) {
|
||||
try {
|
||||
return authorizeService.isAdmin(context);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
if (options == null) {
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("s", "single-researcher", true, "Single researcher UUID");
|
||||
options.getOption("s").setType(String.class);
|
||||
|
||||
super.options = options;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openalex;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.suggestion.loader.PublicationLoader;
|
||||
import org.dspace.content.Item;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of {@link PublicationLoader} that retrieves metadata values
|
||||
* from an OpenAlex external source.
|
||||
*
|
||||
* @author Adamo Fapohunda (adamo.fapohunda at 4science.com)
|
||||
**/
|
||||
public class OpenAlexPublicationLoader extends PublicationLoader {
|
||||
|
||||
/**
|
||||
* Searches for metadata values related to a given researcher item.
|
||||
* It first checks for "dc.identifier" metadata and builds the filter accordingly.
|
||||
* If not found, it collects available metadata values to be used in the search query.
|
||||
*
|
||||
* @param researcher The researcher item from which metadata values are extracted.
|
||||
* @return A list of search query parameters for OpenAlex.
|
||||
*/
|
||||
@Override
|
||||
public List<String> searchMetadataValues(Item researcher) {
|
||||
List<String> names = getNames();
|
||||
|
||||
// First, check for "dc.identifier.openalex" and build the filter if present
|
||||
List<String> authorIds = names.stream()
|
||||
.filter("dc.identifier.openalex"::equals)
|
||||
.map(name -> itemService.getMetadata(researcher, name))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!authorIds.isEmpty()) {
|
||||
return Collections.singletonList(StringUtils.join(authorIds, "|"));
|
||||
}
|
||||
|
||||
// Otherwise, collect all available metadata values
|
||||
return names.stream()
|
||||
.map(name -> itemService.getMetadata(researcher, name))
|
||||
.filter(Objects::nonNull)
|
||||
.map(i -> "search_by_author=" + i)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* 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.suggestion.runnable;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.app.suggestion.SolrSuggestionProvider;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataFieldName;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.discovery.DiscoverQuery;
|
||||
import org.dspace.discovery.DiscoverResultItemIterator;
|
||||
import org.dspace.discovery.indexobject.IndexableItem;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.util.UUIDUtils;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Runner responsible to import metadata about authors from loader to Solr. This
|
||||
* runner works in two ways: If -s parameter with a valid UUID is received, then
|
||||
* the specific researcher with this UUID will be used. Invocation without any
|
||||
* parameter results in massive import, processing all authors registered in
|
||||
* DSpace.
|
||||
*
|
||||
* @author Alessandro Martelli (alessandro.martelli at 4science.it)
|
||||
**/
|
||||
public class PublicationLoaderRunnable
|
||||
extends DSpaceRunnable<ScriptConfiguration<?>> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(PublicationLoaderRunnable.class);
|
||||
protected Context context;
|
||||
protected String profile;
|
||||
protected String loader;
|
||||
protected String filterQuery;
|
||||
private SolrSuggestionProvider publicationLoader = null;
|
||||
private ConfigurationService configurationService;
|
||||
private ItemService itemService;
|
||||
private Integer itemLimit;
|
||||
private List<SolrSuggestionProvider> providers;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the script configuration for this runnable.
|
||||
* The configuration is fetched from the DSpace service manager.
|
||||
*
|
||||
* @return The {@link ScriptConfiguration} instance for the import-loader-suggestions script.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public ScriptConfiguration<?> getScriptConfiguration() {
|
||||
return new DSpace().getServiceManager()
|
||||
.getServiceByName("import-loader-suggestions", ScriptConfiguration.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the script execution environment by setting up necessary services,
|
||||
* retrieving command-line arguments, and setting default values where necessary.
|
||||
*
|
||||
* @throws ParseException If there is an error parsing command-line options.
|
||||
*/
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
providers = new DSpace().getServiceManager().getServicesByType(SolrSuggestionProvider.class);
|
||||
loader = commandLine.getOptionValue("l");
|
||||
profile = commandLine.getOptionValue("s");
|
||||
filterQuery = !commandLine.hasOption("f") ? "" : commandLine.getOptionValue("f");
|
||||
if (profile == null) {
|
||||
LOGGER.info("No argument for -s, process all profile");
|
||||
} else {
|
||||
LOGGER.info("Process eperson item with UUID " + profile);
|
||||
}
|
||||
if (commandLine.hasOption("m")) {
|
||||
this.itemLimit = Integer.valueOf(commandLine.getOptionValue("m"));
|
||||
} else {
|
||||
this.itemLimit = getDefaultLimit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution method for the script.
|
||||
* It validates input parameters, retrieves researcher items, and triggers the publication import process.
|
||||
*
|
||||
* @throws Exception If an error occurs during execution.
|
||||
*/
|
||||
@Override
|
||||
public void internalRun() throws Exception {
|
||||
if (loader == null) {
|
||||
throw new NullPointerException("loader can't be null");
|
||||
}
|
||||
if (profile != null && UUIDUtils.fromString(profile) == null) {
|
||||
throw new IllegalArgumentException("The provided argument -s is not a valid uuid");
|
||||
}
|
||||
|
||||
publicationLoader = getPublicationLoader(loader);
|
||||
|
||||
try {
|
||||
context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
DiscoverResultItemIterator researchers = findResearchers();
|
||||
while (researchers.hasNext()) {
|
||||
Item researcher = researchers.next();
|
||||
researcher = context.reloadEntity(researcher);
|
||||
publicationLoader.importRecords(context, researcher);
|
||||
setLastImportMetadataValue(researcher);
|
||||
context.commit();
|
||||
context.uncacheEntity(researcher);
|
||||
}
|
||||
} finally {
|
||||
context.restoreAuthSystemState();
|
||||
context.complete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the {@link SolrSuggestionProvider} based on the provided loader name.
|
||||
*
|
||||
* @param loader The name of the publication loader.
|
||||
* @return The corresponding {@link SolrSuggestionProvider}.
|
||||
* @throws IllegalArgumentException If no provider matching the loader name is found.
|
||||
*/
|
||||
private SolrSuggestionProvider getPublicationLoader(String loader) {
|
||||
return providers
|
||||
.stream()
|
||||
.filter(provider -> StringUtils.equals(provider.getSourceName(), loader))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalArgumentException("IllegalArgumentException: " +
|
||||
"Provider for: " + loader + " couldn't be found"));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Item(s) which map a researcher from Solr. If the uuid is specified,
|
||||
* the researcher with this UUID will be chosen. If the uuid doesn't match any
|
||||
* researcher, the method returns an empty array list. If uuid is null, all
|
||||
* research will be return.
|
||||
*
|
||||
* @return the researcher with specified UUID or all researchers
|
||||
*/
|
||||
private DiscoverResultItemIterator findResearchers() {
|
||||
DiscoverQuery discoverQuery = new DiscoverQuery();
|
||||
discoverQuery.setDSpaceObjectFilter(IndexableItem.TYPE);
|
||||
if (org.apache.commons.lang3.StringUtils.isNotBlank(profile)) {
|
||||
discoverQuery.setQuery("search.resourceid:" + profile);
|
||||
}
|
||||
discoverQuery.addFilterQueries("search.resourcetype:Item");
|
||||
discoverQuery.addFilterQueries("dspace.entity.type:Person");
|
||||
discoverQuery.setSortField("lastModified", DiscoverQuery.SORT_ORDER.asc);
|
||||
|
||||
if (!filterQuery.isEmpty()) {
|
||||
discoverQuery.addFilterQueries(filterQuery);
|
||||
}
|
||||
|
||||
DiscoverResultItemIterator iterator = new DiscoverResultItemIterator(context, discoverQuery, itemLimit);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates the researcher's item metadata to store the last import timestamp.
|
||||
*
|
||||
* @param item The researcher item whose metadata should be updated.
|
||||
*/
|
||||
private void setLastImportMetadataValue(Item item) {
|
||||
try {
|
||||
item = context.reloadEntity(item);
|
||||
String metadataField = String.format("dspace.%s.lastimport", loader);
|
||||
String currentDate = DCDate.getCurrent().toString();
|
||||
itemService.setMetadataSingleValue(context, item, new MetadataFieldName(metadataField), null, currentDate);
|
||||
itemService.update(context, item);
|
||||
} catch (SQLException | AuthorizeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the default item limit for the publication loader.
|
||||
*
|
||||
* @return The default item limit, as defined in the DSpace configuration.
|
||||
*/
|
||||
private Integer getDefaultLimit() {
|
||||
return configurationService.getIntProperty("suggestion.publication-loader.max", -1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.runnable;
|
||||
|
||||
import org.apache.commons.cli.HelpFormatter;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* CLI implementation of the {@link PublicationLoaderRunnable} script.
|
||||
* This class extends {@link PublicationLoaderRunnable} and provides additional
|
||||
* functionality specific to command-line execution.
|
||||
*
|
||||
* @author Adamo Fapohunda (adamo.fapohunda at 4science.com)
|
||||
*/
|
||||
public class PublicationLoaderRunnableCli extends PublicationLoaderRunnable {
|
||||
|
||||
/**
|
||||
* Retrieves the script configuration associated with this CLI script.
|
||||
* This method fetches the configuration from the DSpace service manager.
|
||||
*
|
||||
* @return The {@link ScriptConfiguration} instance for the import-loader-suggestions script.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public ScriptConfiguration<?> getScriptConfiguration() {
|
||||
return new DSpace().getServiceManager()
|
||||
.getServiceByName("import-loader-suggestions", ScriptConfiguration.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the script execution environment.
|
||||
* This method also checks for the presence of the help option and, if found,
|
||||
* displays usage instructions before terminating the script.
|
||||
*
|
||||
* @throws ParseException If there is an error parsing the command-line options.
|
||||
*/
|
||||
@Override
|
||||
public void setup() throws ParseException {
|
||||
super.setup();
|
||||
|
||||
// in case of CLI we show the help prompt
|
||||
if (commandLine.hasOption('h')) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("Imports suggestions from external providers for publication claim",
|
||||
getScriptConfiguration().getOptions());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
package org.dspace.app.suggestion.scorer;
|
||||
|
||||
import static org.dspace.app.suggestion.SuggestionUtils.getAllEntriesByMetadatum;
|
||||
|
||||
@@ -137,6 +137,8 @@ public class AuthorNamesScorer implements EvidenceScorer {
|
||||
* */
|
||||
private String normalize(String value) {
|
||||
String norm = Normalizer.normalize(value, Normalizer.NFD);
|
||||
// Removes diacritical marks
|
||||
norm = norm.replaceAll("\\p{M}", "");
|
||||
CharsetDetector cd = new CharsetDetector();
|
||||
cd.setText(value.getBytes());
|
||||
CharsetMatch detect = cd.detect();
|
@@ -5,12 +5,10 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
package org.dspace.app.suggestion.scorer;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.app.suggestion.SuggestionEvidence;
|
||||
@@ -202,11 +200,9 @@ public class DateScorer implements EvidenceScorer {
|
||||
private int getYear(String birthDateStr) {
|
||||
int birthDateYear = -1;
|
||||
if (birthDateStr != null) {
|
||||
Date birthDate = MultiFormatDateParser.parse(birthDateStr);
|
||||
LocalDateTime birthDate = MultiFormatDateParser.parse(birthDateStr).toLocalDateTime();
|
||||
if (birthDate != null) {
|
||||
Calendar calendar = new GregorianCalendar();
|
||||
calendar.setTime(birthDate);
|
||||
birthDateYear = calendar.get(Calendar.YEAR);
|
||||
birthDateYear = birthDate.getYear();
|
||||
}
|
||||
}
|
||||
return birthDateYear;
|
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
package org.dspace.app.suggestion.scorer;
|
||||
|
||||
import org.dspace.app.suggestion.SuggestionEvidence;
|
||||
import org.dspace.content.Item;
|
||||
@@ -32,6 +32,6 @@ public interface EvidenceScorer {
|
||||
* @return the generated suggestion evidence or null if the record should be
|
||||
* discarded
|
||||
*/
|
||||
public SuggestionEvidence computeEvidence(Item researcher, ExternalDataObject importRecord);
|
||||
SuggestionEvidence computeEvidence(Item researcher, ExternalDataObject importRecord);
|
||||
|
||||
}
|
@@ -5,18 +5,27 @@
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.suggestion.openaire;
|
||||
package org.dspace.app.suggestion.script;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.app.suggestion.runnable.PublicationLoaderRunnable;
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@link PublicationLoaderScriptConfiguration} for CLI.
|
||||
* Extension of {@link org.dspace.app.suggestion.openaire.PublicationLoaderScriptConfiguration} for CLI.
|
||||
*
|
||||
* @author Alessandro Martelli (alessandro.martelli at 4science.it)
|
||||
*/
|
||||
public class PublicationLoaderCliScriptConfiguration<T extends PublicationLoaderRunnable>
|
||||
extends PublicationLoaderScriptConfiguration<T> {
|
||||
|
||||
/**
|
||||
* Retrieves the command-line options available for this script.
|
||||
* In addition to the options provided by {@link PublicationLoaderScriptConfiguration},
|
||||
* this method adds a "help" option.
|
||||
*
|
||||
* @return The configured {@link Options} object containing all available command-line parameters.
|
||||
*/
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = super.getOptions();
|
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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.suggestion.script;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.dspace.app.suggestion.runnable.PublicationLoaderRunnable;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.DSpaceCommandLineParameter;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Configuration class for the PublicationLoader script.
|
||||
* This class extends {@link ScriptConfiguration} to provide configuration settings
|
||||
* and execution permissions for the {@link PublicationLoaderRunnable} script.
|
||||
*
|
||||
* @param <T> The specific type of {@link PublicationLoaderRunnable} that this configuration supports.
|
||||
* @author Adamo Fapohunda (adamo.fapohunda at 4science.com)
|
||||
*/
|
||||
public class PublicationLoaderScriptConfiguration<T extends PublicationLoaderRunnable>
|
||||
extends ScriptConfiguration<T> {
|
||||
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
private Class<T> dspaceRunnableClass;
|
||||
|
||||
/**
|
||||
* Retrieves the class type of the DSpace runnable script.
|
||||
*
|
||||
* @return the class of type {@link T} representing the script to execute.
|
||||
*/
|
||||
@Override
|
||||
public Class<T> getDspaceRunnableClass() {
|
||||
return dspaceRunnableClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class type of the DSpace runnable script.
|
||||
*
|
||||
* @param dspaceRunnableClass The class of the script to be set.
|
||||
*/
|
||||
@Override
|
||||
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
|
||||
this.dspaceRunnableClass = dspaceRunnableClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current user is authorized to execute the script.
|
||||
* This check is based on whether the user has administrator privileges.
|
||||
*
|
||||
* @param context The DSpace context.
|
||||
* @param commandLineParameters The list of command line parameters provided.
|
||||
* @return true if the user has administrative privileges, false otherwise.
|
||||
* @throws RuntimeException if an SQL exception occurs while checking authorization.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAllowedToExecute(Context context, List<DSpaceCommandLineParameter> commandLineParameters) {
|
||||
try {
|
||||
return authorizeService.isAdmin(context);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the command-line options available for the script.
|
||||
* These options allow customization of the script execution parameters.
|
||||
*
|
||||
* @return an {@link Options} object containing the available script options.
|
||||
*/
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
if (options == null) {
|
||||
Options options = new Options();
|
||||
|
||||
options.addOption("s", "single-researcher", true, "Single researcher UUID");
|
||||
options.getOption("s").setType(String.class);
|
||||
|
||||
options.addOption("l", "loader", true, "Publication loader to be used");
|
||||
options.getOption("l").setType(String.class);
|
||||
options.getOption("l").setRequired(true);
|
||||
|
||||
options.addOption("f", "solrfilter", true, "The additional SOLR filter to better refine results");
|
||||
options.getOption("f").setType(String.class);
|
||||
|
||||
options.addOption("m", "max", true,
|
||||
"The maximum number of researcher profiles to process. If no maximum is provided, then " +
|
||||
"the configured default will be used.");
|
||||
options.getOption("m").setType(Integer.class);
|
||||
|
||||
super.options = options;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -9,8 +9,7 @@
|
||||
package org.dspace.app.util;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
import java.time.Instant;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -35,7 +34,7 @@ abstract public class AbstractDSpaceWebapp
|
||||
|
||||
protected String kind;
|
||||
|
||||
protected Date started;
|
||||
protected Instant started;
|
||||
|
||||
protected String url;
|
||||
|
||||
@@ -55,7 +54,7 @@ abstract public class AbstractDSpaceWebapp
|
||||
public AbstractDSpaceWebapp(String kind) {
|
||||
this.kind = kind;
|
||||
|
||||
started = new Date();
|
||||
started = Instant.now();
|
||||
|
||||
ConfigurationService configurationService
|
||||
= DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
@@ -70,10 +69,9 @@ abstract public class AbstractDSpaceWebapp
|
||||
*/
|
||||
public void register() {
|
||||
// Create the database entry
|
||||
Timestamp now = new Timestamp(started.getTime());
|
||||
try {
|
||||
Context context = new Context();
|
||||
webApp = webAppService.create(context, kind, url, now, isUI() ? 1 : 0);
|
||||
webApp = webAppService.create(context, kind, url, started, isUI() ? 1 : 0);
|
||||
context.complete();
|
||||
} catch (SQLException e) {
|
||||
log.error("Failed to record startup in Webapp table.", e);
|
||||
|
@@ -15,7 +15,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.FactoryConfigurationError;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -118,15 +117,17 @@ public class DCInputsReader {
|
||||
formDefns = new HashMap<String, List<List<Map<String, String>>>>();
|
||||
valuePairs = new HashMap<String, List<String>>();
|
||||
|
||||
String uri = "file:" + new File(fileName).getAbsolutePath();
|
||||
File inputFile = new File(fileName);
|
||||
String inputFileDir = inputFile.toPath().normalize().getParent().toString();
|
||||
|
||||
String uri = "file:" + inputFile.getAbsolutePath();
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
// This document builder will *not* disable external
|
||||
// entities as they can be useful in managing large forms, but
|
||||
// it will restrict them to be within the directory that the
|
||||
// current input form XML file exists (or a sub-directory)
|
||||
DocumentBuilder db = XMLUtils.getTrustedDocumentBuilder(inputFileDir);
|
||||
Document doc = db.parse(uri);
|
||||
doNodes(doc);
|
||||
checkValues();
|
||||
@@ -379,7 +380,7 @@ public class DCInputsReader {
|
||||
}
|
||||
// sanity check number of fields
|
||||
if (fields.size() < 1) {
|
||||
throw new DCInputsReaderException("Form " + formName + "row " + rowIdx + " has no fields");
|
||||
throw new DCInputsReaderException("Form " + formName + ", row " + rowIdx + " has no fields");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,6 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
@@ -64,20 +63,36 @@ public class InitializeEntities {
|
||||
*/
|
||||
public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException {
|
||||
InitializeEntities initializeEntities = new InitializeEntities();
|
||||
// Set up command-line options and parse arguments
|
||||
CommandLineParser parser = new DefaultParser();
|
||||
Options options = createCommandLineOptions();
|
||||
CommandLine line = parser.parse(options,argv);
|
||||
String fileLocation = getFileLocationFromCommandLine(line);
|
||||
// First of all, check if the help option was entered or a required argument is missing
|
||||
checkHelpEntered(options, line);
|
||||
// Get the file location from the command line
|
||||
String fileLocation = getFileLocationFromCommandLine(line);
|
||||
// Run the script
|
||||
initializeEntities.run(fileLocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the help option was entered or a required argument is missing. If so, print help and exit.
|
||||
* @param options the defined command-line options
|
||||
* @param line the parsed command-line arguments
|
||||
*/
|
||||
private static void checkHelpEntered(Options options, CommandLine line) {
|
||||
if (line.hasOption("h")) {
|
||||
if (line.hasOption("h") || !line.hasOption("f")) {
|
||||
HelpFormatter formatter = new HelpFormatter();
|
||||
formatter.printHelp("Initialize Entities", options);
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file path from the command-line argument. Exits with exit code 1 if no file argument was entered.
|
||||
* @param line the parsed command-line arguments
|
||||
* @return the file path
|
||||
*/
|
||||
private static String getFileLocationFromCommandLine(CommandLine line) {
|
||||
String query = line.getOptionValue("f");
|
||||
if (StringUtils.isEmpty(query)) {
|
||||
@@ -88,13 +103,25 @@ public class InitializeEntities {
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the command-line options
|
||||
* @return the command-line options
|
||||
*/
|
||||
protected static Options createCommandLineOptions() {
|
||||
Options options = new Options();
|
||||
options.addOption("f", "file", true, "the location for the file containing the xml data");
|
||||
options.addOption("f", "file", true, "the path to the file containing the " +
|
||||
"relationship definitions (e.g. ${dspace.dir}/config/entities/relationship-types.xml)");
|
||||
options.addOption("h", "help", false, "print this message");
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the script for the given file location
|
||||
* @param fileLocation the file location
|
||||
* @throws SQLException If something goes wrong initializing context or inserting relationship types
|
||||
* @throws AuthorizeException If the script user fails to authorize while inserting relationship types
|
||||
*/
|
||||
private void run(String fileLocation) throws SQLException, AuthorizeException {
|
||||
Context context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
@@ -102,11 +129,18 @@ public class InitializeEntities {
|
||||
context.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the XML file at fileLocation to create relationship types in the database
|
||||
* @param context DSpace context
|
||||
* @param fileLocation the full or relative file path to the relationship types XML
|
||||
* @throws AuthorizeException If the script user fails to authorize while inserting relationship types
|
||||
*/
|
||||
private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException {
|
||||
try {
|
||||
File fXmlFile = new File(fileLocation);
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
// This XML builder will allow external entities, so the relationship types XML should
|
||||
// be considered trusted by administrators
|
||||
DocumentBuilder dBuilder = XMLUtils.getTrustedDocumentBuilder();
|
||||
Document doc = dBuilder.parse(fXmlFile);
|
||||
|
||||
doc.getDocumentElement().normalize();
|
||||
@@ -158,15 +192,15 @@ public class InitializeEntities {
|
||||
|
||||
for (int j = 0; j < leftCardinalityList.getLength(); j++) {
|
||||
Node node = leftCardinalityList.item(j);
|
||||
leftCardinalityMin = getString(leftCardinalityMin,(Element) node, "min");
|
||||
leftCardinalityMax = getString(leftCardinalityMax,(Element) node, "max");
|
||||
leftCardinalityMin = getCardinalityMinString(leftCardinalityMin,(Element) node, "min");
|
||||
leftCardinalityMax = getCardinalityMinString(leftCardinalityMax,(Element) node, "max");
|
||||
|
||||
}
|
||||
|
||||
for (int j = 0; j < rightCardinalityList.getLength(); j++) {
|
||||
Node node = rightCardinalityList.item(j);
|
||||
rightCardinalityMin = getString(rightCardinalityMin,(Element) node, "min");
|
||||
rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max");
|
||||
rightCardinalityMin = getCardinalityMinString(rightCardinalityMin,(Element) node, "min");
|
||||
rightCardinalityMax = getCardinalityMinString(rightCardinalityMax,(Element) node, "max");
|
||||
|
||||
}
|
||||
populateRelationshipType(context, leftType, rightType, leftwardType, rightwardType,
|
||||
@@ -182,13 +216,39 @@ public class InitializeEntities {
|
||||
}
|
||||
}
|
||||
|
||||
private String getString(String leftCardinalityMin,Element node, String minOrMax) {
|
||||
/**
|
||||
* Extract the min or max value for the left or right cardinality from the node text content
|
||||
* @param leftCardinalityMin current left cardinality min
|
||||
* @param node node to extract the min or max value from
|
||||
* @param minOrMax element tag name to parse
|
||||
* @return final left cardinality min
|
||||
*/
|
||||
private String getCardinalityMinString(String leftCardinalityMin, Element node, String minOrMax) {
|
||||
if (node.getElementsByTagName(minOrMax).getLength() > 0) {
|
||||
leftCardinalityMin = node.getElementsByTagName(minOrMax).item(0).getTextContent();
|
||||
}
|
||||
return leftCardinalityMin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the relationship type based on values parsed from the XML relationship types configuration
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param leftType left relationship type (e.g. "Publication").
|
||||
* @param rightType right relationship type (e.g. "Journal").
|
||||
* @param leftwardType leftward relationship type (e.g. "isAuthorOfPublication").
|
||||
* @param rightwardType rightward relationship type (e.g. "isPublicationOfAuthor").
|
||||
* @param leftCardinalityMin left cardinality min
|
||||
* @param leftCardinalityMax left cardinality max
|
||||
* @param rightCardinalityMin right cardinality min
|
||||
* @param rightCardinalityMax right cardinality max
|
||||
* @param copyToLeft copy metadata values to left if right side is deleted
|
||||
* @param copyToRight copy metadata values to right if left side is deleted
|
||||
* @param tilted set a tilted relationship side (left or right) if there are many relationships going one way
|
||||
* to help performance (e.g. authors with 1000s of publications)
|
||||
* @throws SQLException if database error occurs while saving the relationship type
|
||||
* @throws AuthorizeException if authorization error occurs while saving the relationship type
|
||||
*/
|
||||
private void populateRelationshipType(Context context, String leftType, String rightType, String leftwardType,
|
||||
String rightwardType, String leftCardinalityMin, String leftCardinalityMax,
|
||||
String rightCardinalityMin, String rightCardinalityMax,
|
||||
|
@@ -100,6 +100,14 @@ public class OpenSearchServiceImpl implements OpenSearchService {
|
||||
configurationService.getProperty("websvc.opensearch.uicontext");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base search UI URL (websvc.opensearch.max_num_of_items_per_request)
|
||||
*/
|
||||
public int getMaxNumOfItemsPerRequest() {
|
||||
return configurationService.getIntProperty(
|
||||
"websvc.opensearch.max_num_of_items_per_request", 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType(String format) {
|
||||
return "html".equals(format) ? "text/html" :
|
||||
|
@@ -16,7 +16,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.FactoryConfigurationError;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -170,13 +169,10 @@ public class SubmissionConfigReader {
|
||||
String uri = "file:" + new File(fileName).getAbsolutePath();
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setIgnoringComments(true);
|
||||
factory.setIgnoringElementContentWhitespace(true);
|
||||
|
||||
DocumentBuilder db = factory.newDocumentBuilder();
|
||||
// This document builder factory will *not* disable external
|
||||
// entities as they can be useful in managing large forms, but
|
||||
// it will restrict them to the config dir containing submission definitions
|
||||
DocumentBuilder db = XMLUtils.getTrustedDocumentBuilder(configDir);
|
||||
Document doc = db.parse(uri);
|
||||
doNodes(doc);
|
||||
} catch (FactoryConfigurationError fe) {
|
||||
@@ -732,4 +728,4 @@ public class SubmissionConfigReader {
|
||||
}
|
||||
return results;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user