Compare commits

..

1 Commits

Author SHA1 Message Date
Terry Brady
cfc200f2c7 Update README.md 2018-06-22 14:33:35 -07:00
2820 changed files with 84423 additions and 256757 deletions

View File

@@ -1,35 +0,0 @@
# DSpace configuration for Codecov.io coverage reports
# These override the default YAML settings at
# https://docs.codecov.io/docs/codecov-yaml#section-default-yaml
# Can be validated via instructions at:
# https://docs.codecov.io/docs/codecov-yaml#validate-your-repository-yaml
# Tell Codecov not to send a coverage notification until (at least) 2 builds are completed
# Since we run Unit & Integration tests in parallel, this lets Codecov know that coverage
# needs to be merged across those builds
codecov:
notify:
after_n_builds: 2
# Settings related to code coverage analysis
coverage:
status:
# Configuration for project-level checks. This checks how the PR changes overall coverage.
project:
default:
# For each PR, auto compare coverage to previous commit.
# Require that overall (project) coverage does NOT drop more than 0.5%
target: auto
threshold: 0.5%
# Configuration for patch-level checks. This checks the relative coverage of the new PR code ONLY.
patch:
default:
# Enable informational mode, which just provides info to reviewers & always passes
# https://docs.codecov.io/docs/commit-status#section-informational
informational: true
# Turn PR comments "off". This feature adds the code coverage summary as a
# comment on each PR. See https://docs.codecov.io/docs/pull-request-comments
# However, this same info is available from the Codecov checks in the PR's
# "Checks" tab in GitHub. So, the comment is unnecessary.
comment: false

View File

@@ -1,11 +0,0 @@
.git/
.idea/
.settings/
*/target/
dspace/modules/*/target/
Dockerfile.*
dspace/src/main/docker/dspace-postgres-pgcrypto
dspace/src/main/docker/dspace-postgres-pgcrypto-curl
dspace/src/main/docker/solr
dspace/src/main/docker/README.md
dspace/src/main/docker-compose/

6
.gitattributes vendored
View File

@@ -1,12 +1,6 @@
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * text=auto
# Ensure Unix files always keep Unix line endings
*.sh text eol=lf
# Ensure Windows files always keep Windows line endings
*.bat text eol=crlf
# Standard to msysgit # Standard to msysgit
*.doc diff=astextplain *.doc diff=astextplain
*.DOC diff=astextplain *.DOC diff=astextplain

View File

@@ -1,22 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug, needs triage
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is. Include the version(s) of DSpace where you've seen this problem. Link to examples if they are public.
**To Reproduce**
Steps to reproduce the behavior:
1. Do this
2. Then this...
**Expected behavior**
A clear and concise description of what you expected to happen.
**Related work**
Link to any related tickets or PRs here.

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest a new feature for this project
title: ''
labels: new feature, needs triage
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives or workarounds you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,26 +0,0 @@
# This workflow runs whenever a new pull request is created
# TEMPORARILY DISABLED. Unfortunately this doesn't work for PRs created from forked repositories (which is how we tend to create PRs).
# There is no known workaround yet. See https://github.community/t/how-to-use-github-token-for-prs-from-forks/16818
name: Pull Request opened
# Only run for newly opened PRs against the "main" branch
on:
pull_request:
types: [opened]
branches:
- main
jobs:
automation:
runs-on: ubuntu-latest
steps:
# Assign the PR to whomever created it. This is useful for visualizing assignments on project boards
# See https://github.com/marketplace/actions/pull-request-assigner
- name: Assign PR to creator
uses: thomaseizinger/assign-pr-creator-action@v1.0.0
# Note, this authentication token is created automatically
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
# Ignore errors. It is possible the PR was created by someone who cannot be assigned
continue-on-error: true

View File

@@ -1,26 +0,0 @@
## References
_Add references/links to any related issues or PRs. These may include:_
* Fixes #[issue-number]
* Related to [REST Contract](https://github.com/DSpace/Rest7Contract)
## Description
Short summary of changes (1-2 sentences).
## Instructions for Reviewers
Please add a more detailed description of the changes made by your PR. At a minimum, providing a bulleted list of changes in your PR is helpful to reviewers.
List of changes in this PR:
* First, ...
* Second, ...
**Include guidance for how to test or review your PR.** This may include: steps to reproduce a bug, screenshots or description of a new feature, or reasons behind specific changes.
## Checklist
_This checklist provides a reminder of what we are going to look for when reviewing your PR. You need not complete this checklist prior to creating your PR (draft PRs are always welcome). If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!_
- [ ] My PR is small in size (e.g. less than 1,000 lines of code, not including comments & integration tests). Exceptions may be made if previously agreed upon.
- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide).
- [ ] My PR includes Javadoc for _all new (or modified) public methods and classes_. It also includes Javadoc for large or complex private methods.
- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/main/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] If my PR modifies the REST API, I've linked to the REST Contract page (or open PR) related to this change.

View File

@@ -1,83 +0,0 @@
# DSpace Continuous Integration/Build via GitHub Actions
# Concepts borrowed from
# https://docs.github.com/en/free-pro-team@latest/actions/guides/building-and-testing-java-with-maven
name: Build
# Run this Build for all pushes / PRs to current branch
on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-latest
env:
# Give Maven 1GB of memory to work with
# Suppress all Maven "downloading" messages in logs (see https://stackoverflow.com/a/35653426)
# This also slightly speeds builds, as there is less logging
MAVEN_OPTS: "-Xmx1024M -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
strategy:
# Create a matrix of two separate configurations for Unit vs Integration Tests
# This will ensure those tasks are run in parallel
# Also specify version of Java to use (this can allow us to optionally run tests on multiple JDKs in future)
matrix:
include:
# NOTE: Unit Tests include deprecated REST API v6 (as it has unit tests)
# - surefire.rerunFailingTestsCount => try again for flakey tests, and keep track of/report on number of retries
- type: "Unit Tests"
java: 11
mvnflags: "-DskipUnitTests=false -Pdspace-rest -Dsurefire.rerunFailingTestsCount=2"
resultsdir: "**/target/surefire-reports/**"
# NOTE: ITs skip all code validation checks, as they are already done by Unit Test job.
# - enforcer.skip => Skip maven-enforcer-plugin rules
# - checkstyle.skip => Skip all checkstyle checks by maven-checkstyle-plugin
# - license.skip => Skip all license header checks by license-maven-plugin
# - xml.skip => Skip all XML/XSLT validation by xml-maven-plugin
# - failsafe.rerunFailingTestsCount => try again for flakey tests, and keep track of/report on number of retries
- type: "Integration Tests"
java: 11
mvnflags: "-DskipIntegrationTests=false -Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true -Dfailsafe.rerunFailingTestsCount=2"
resultsdir: "**/target/failsafe-reports/**"
# Do NOT exit immediately if one matrix job fails
# This ensures ITs continue running even if Unit Tests fail, or visa versa
fail-fast: false
name: Run ${{ matrix.type }}
# These are the actual CI steps to perform per job
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v2
# https://github.com/actions/setup-java
- name: Install JDK ${{ matrix.java }}
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
# https://github.com/actions/cache
- name: Cache Maven dependencies
uses: actions/cache@v2
with:
# Cache entire ~/.m2/repository
path: ~/.m2/repository
# Cache key is hash of all pom.xml files. Therefore any changes to POMs will invalidate cache
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
# Run parallel Maven builds based on the above 'strategy.matrix'
- name: Run Maven ${{ matrix.type }}
env:
TEST_FLAGS: ${{ matrix.mvnflags }}
run: mvn install -B -V -P-assembly -Pcoverage-report $TEST_FLAGS
# If previous step failed, save results of tests to downloadable artifact for this job
# (This artifact is downloadable at the bottom of any job's summary page)
- name: Upload Results of ${{ matrix.type }} to Artifact
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.type }} results
path: ${{ matrix.resultsdir }}
# https://github.com/codecov/codecov-action
- name: Upload coverage to Codecov.io
uses: codecov/codecov-action@v2

View File

@@ -1,156 +0,0 @@
# DSpace Docker image build for hub.docker.com
name: Docker images
# Run this Build for all pushes to 'main' or maintenance branches, or tagged releases.
# Also run for PRs to ensure PR doesn't break Docker build process
on:
push:
branches:
- main
- 'dspace-**'
tags:
- 'dspace-**'
pull_request:
jobs:
docker:
# Ensure this job never runs on forked repos. It's only executed for 'dspace/dspace'
if: github.repository == 'dspace/dspace'
runs-on: ubuntu-latest
env:
# Define tags to use for Docker images based on Git tags/branches (for docker/metadata-action)
# For a new commit on default branch (main), use the literal tag 'dspace-7_x' on Docker image.
# For a new commit on other branches, use the branch name as the tag for Docker image.
# For a new tag, copy that tag name as the tag for Docker image.
IMAGE_TAGS: |
type=raw,value=dspace-7_x,enable=${{ endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=branch,enable=${{ !endsWith(github.ref, github.event.repository.default_branch) }}
type=ref,event=tag
# Define default tag "flavor" for docker/metadata-action per
# https://github.com/docker/metadata-action#flavor-input
# We turn off 'latest' tag by default.
TAGS_FLAVOR: |
latest=false
steps:
# https://github.com/actions/checkout
- name: Checkout codebase
uses: actions/checkout@v2
# https://github.com/docker/setup-buildx-action
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
# https://github.com/docker/login-action
- name: Login to DockerHub
# Only login if not a PR, as PRs only trigger a Docker build and not a push
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
####################################################
# Build/Push the 'dspace/dspace-dependencies' image
####################################################
# https://github.com/docker/metadata-action
# Get Metadata for docker_build_deps step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-dependencies' image
id: meta_build_deps
uses: docker/metadata-action@v3
with:
images: dspace/dspace-dependencies
tags: ${{ env.IMAGE_TAGS }}
flavor: ${{ env.TAGS_FLAVOR }}
# https://github.com/docker/build-push-action
- name: Build and push 'dspace-dependencies' image
id: docker_build_deps
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.dependencies
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build_deps.outputs.tags }}
labels: ${{ steps.meta_build_deps.outputs.labels }}
#######################################
# Build/Push the 'dspace/dspace' image
#######################################
# Get Metadata for docker_build step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace' image
id: meta_build
uses: docker/metadata-action@v3
with:
images: dspace/dspace
tags: ${{ env.IMAGE_TAGS }}
flavor: ${{ env.TAGS_FLAVOR }}
- name: Build and push 'dspace' image
id: docker_build
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build.outputs.tags }}
labels: ${{ steps.meta_build.outputs.labels }}
#####################################################
# Build/Push the 'dspace/dspace' image ('-test' tag)
#####################################################
# Get Metadata for docker_build_test step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-test' image
id: meta_build_test
uses: docker/metadata-action@v3
with:
images: dspace/dspace
tags: ${{ env.IMAGE_TAGS }}
# As this is a test/development image, its tags are all suffixed with "-test". Otherwise, it uses the same
# tagging logic as the primary 'dspace/dspace' image above.
flavor: ${{ env.TAGS_FLAVOR }}
suffix=-test
- name: Build and push 'dspace-test' image
id: docker_build_test
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.test
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build_test.outputs.tags }}
labels: ${{ steps.meta_build_test.outputs.labels }}
###########################################
# Build/Push the 'dspace/dspace-cli' image
###########################################
# Get Metadata for docker_build_test step below
- name: Sync metadata (tags, labels) from GitHub to Docker for 'dspace-cli' image
id: meta_build_cli
uses: docker/metadata-action@v3
with:
images: dspace/dspace-cli
tags: ${{ env.IMAGE_TAGS }}
flavor: ${{ env.TAGS_FLAVOR }}
- name: Build and push 'dspace-cli' image
id: docker_build_cli
uses: docker/build-push-action@v2
with:
context: .
file: ./Dockerfile.cli
# For pull requests, we run the Docker build (to ensure no PR changes break the build),
# but we ONLY do an image push to DockerHub if it's NOT a PR
push: ${{ github.event_name != 'pull_request' }}
# Use tags / labels provided by 'docker/metadata-action' above
tags: ${{ steps.meta_build_cli.outputs.tags }}
labels: ${{ steps.meta_build_cli.outputs.labels }}

View File

@@ -1,29 +0,0 @@
# This workflow runs whenever a new issue is created
name: Issue opened
on:
issues:
types: [opened]
jobs:
automation:
runs-on: ubuntu-latest
steps:
# Add the new issue to a project board, if it needs triage
# See https://github.com/marketplace/actions/create-project-card-action
- name: Add issue to project board
# Only add to project board if issue is flagged as "needs triage" or has no labels
# NOTE: By default we flag new issues as "needs triage" in our issue template
if: (contains(github.event.issue.labels.*.name, 'needs triage') || join(github.event.issue.labels.*.name) == '')
uses: technote-space/create-project-card-action@v1
# Note, the authentication token below is an ORG level Secret.
# It must be created/recreated manually via a personal access token with "public_repo" and "admin:org" permissions
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token#permissions-for-the-github_token
# This is necessary because the "DSpace Backlog" project is an org level project (i.e. not repo specific)
with:
GITHUB_TOKEN: ${{ secrets.ORG_PROJECT_TOKEN }}
PROJECT: DSpace Backlog
COLUMN: Triage
CHECK_ORG_PROJECT: true
# Ignore errors.
continue-on-error: true

View File

@@ -1,25 +0,0 @@
# This workflow checks open PRs for merge conflicts and labels them when conflicts are found
name: Check for merge conflicts
# Run whenever the "main" branch is updated
# NOTE: This means merge conflicts are only checked for when a PR is merged to main.
on:
push:
branches:
- main
jobs:
triage:
runs-on: ubuntu-latest
steps:
# See: https://github.com/mschilde/auto-label-merge-conflicts/
- name: Auto-label PRs with merge conflicts
uses: mschilde/auto-label-merge-conflicts@v2.0
# Add "merge conflict" label if a merge conflict is detected. Remove it when resolved.
# Note, the authentication token is created automatically
# See: https://docs.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
with:
CONFLICT_LABEL_NAME: 'merge conflict'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Ignore errors
continue-on-error: true

6
.gitignore vendored
View File

@@ -19,7 +19,7 @@ tags
overlays/ overlays/
## Ignore project files created by NetBeans ## Ignore project files created by NetBeans
nbproject/ nbproject/private/
build/ build/
nbbuild/ nbbuild/
dist/ dist/
@@ -42,7 +42,3 @@ nb-configuration.xml
##Ignore JRebel project configuration ##Ignore JRebel project configuration
rebel.xml rebel.xml
## Ignore jenv configuration
.java-version

View File

@@ -1,9 +0,0 @@
# LGTM Settings (https://lgtm.com/)
# For reference, see https://lgtm.com/help/lgtm/lgtm.yml-configuration-file
# or template at https://lgtm.com/static/downloads/lgtm.template.yml
extraction:
java:
index:
# Specify the Java version required to build the project
java_version: 11

44
.travis.yml Normal file
View File

@@ -0,0 +1,44 @@
language: java
sudo: false
env:
# Give Maven 1GB of memory to work with
- MAVEN_OPTS=-Xmx1024M
jdk:
# DS-3384 Oracle JDK 8 has DocLint enabled by default.
# Let's use this to catch any newly introduced DocLint issues.
- oraclejdk8
## Should we run into any problems with oraclejdk8 on Travis, we may try the following workaround.
## https://docs.travis-ci.com/user/languages/java#Testing-Against-Multiple-JDKs
## https://github.com/travis-ci/travis-ci/issues/3259#issuecomment-130860338
#addons:
# apt:
# packages:
# - oracle-java8-installer
# Install prerequisites for building Mirage2 more rapidly
before_install:
# Remove outdated settings.xml from Travis builds. Workaround for https://github.com/travis-ci/travis-ci/issues/4629
- rm ~/.m2/settings.xml
# Skip install stage, as we'll do it below
install: "echo 'Skipping install stage, dependencies will be downloaded during build and test stages.'"
# Two stage Build and Test
# 1. Install & Unit Test APIs
# 2. Assemble DSpace
script:
# 1. [Install & Unit Test] Check source code licenses and run source code Unit Tests
# license:check => Validate all source code license headers
# -Dmaven.test.skip=false => Enable DSpace Unit Tests
# -DskipITs=false => Enable DSpace Integration Tests
# -P !assembly => Skip normal assembly (as it can be memory intensive)
# -B => Maven batch/non-interactive mode (recommended for CI)
# -V => Display Maven version info before build
# -Dsurefire.rerunFailingTestsCount=2 => try again for flakey tests, and keep track of/report on number of retries
- "mvn clean install license:check -Dmaven.test.skip=false -DskipITs=false -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"
# 2. [Assemble DSpace] Ensure overlay & assembly process works (from [src]/dspace/)
# -P !assembly => SKIP the actual building of [src]/dspace/dspace-installer (as it can be memory intensive)
- "cd dspace && mvn package -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"

View File

@@ -1,67 +0,0 @@
# This image will be published as dspace/dspace
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
#
# - note: default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x
# This Dockerfile uses JDK11 by default, but has also been tested with JDK17.
# To build with JDK17, use "--build-arg JDK_VERSION=17"
ARG JDK_VERSION=11
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-7_x as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-installer directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install \
&& chown -Rv dspace: /app
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Build DSpace (note: this build doesn't include the optional, deprecated "dspace-rest" webapp)
# Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
RUN mvn package && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM openjdk:${JDK_VERSION}-slim as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.12
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
# Need wget to install ant
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
# Download and install 'ant'
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
# Run necessary 'ant' deploy scripts
RUN ant init_installation update_configs update_code update_webapps
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:9-jdk${JDK_VERSION}
# NOTE: DSPACE_INSTALL must align with the "dspace.dir" default configuration.
ENV DSPACE_INSTALL=/dspace
# Copy the /dspace directory from 'ant_build' containger to /dspace in this container
COPY --from=ant_build /dspace $DSPACE_INSTALL
# Expose Tomcat port and AJP port
EXPOSE 8080 8009
# Give java extra memory (2GB)
ENV JAVA_OPTS=-Xmx2000m
# Link the DSpace 'server' webapp into Tomcat's webapps directory.
# This ensures that when we start Tomcat, it runs from /server path (e.g. http://localhost:8080/server/)
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server
# If you wish to run "server" webapp off the ROOT path, then comment out the above RUN, and uncomment the below RUN.
# You also MUST update the 'dspace.server.url' configuration to match.
# Please note that server webapp should only run on one path at a time.
#RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT

View File

@@ -1,54 +0,0 @@
# This image will be published as dspace/dspace-cli
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
#
# - note: default tag for branch: dspace/dspace-cli: dspace/dspace-cli:dspace-7_x
# This Dockerfile uses JDK11 by default, but has also been tested with JDK17.
# To build with JDK17, use "--build-arg JDK_VERSION=17"
ARG JDK_VERSION=11
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-7_x as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-installer directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install \
&& chown -Rv dspace: /app
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Build DSpace. Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
RUN mvn package && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM openjdk:${JDK_VERSION}-slim as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.12
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
# Need wget to install ant
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
# Download and install 'ant'
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
# Run necessary 'ant' deploy scripts
RUN ant init_installation update_configs update_code
# Step 3 - Run jdk
FROM openjdk:${JDK_VERSION}
# NOTE: DSPACE_INSTALL must align with the "dspace.dir" default configuration.
ENV DSPACE_INSTALL=/dspace
# Copy the /dspace directory from 'ant_build' container to /dspace in this container
COPY --from=ant_build /dspace $DSPACE_INSTALL
# Give java extra memory (1GB)
ENV JAVA_OPTS=-Xmx1000m

View File

@@ -1,36 +0,0 @@
# This image will be published as dspace/dspace-dependencies
# The purpose of this image is to make the build for dspace/dspace run faster
#
# This Dockerfile uses JDK11 by default, but has also been tested with JDK17.
# To build with JDK17, use "--build-arg JDK_VERSION=17"
ARG JDK_VERSION=11
# Step 1 - Run Maven Build
FROM maven:3-openjdk-${JDK_VERSION}-slim as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# Create the 'dspace' user account & home directory
RUN useradd dspace \
&& mkdir -p /home/dspace \
&& chown -Rv dspace: /home/dspace
RUN chown -Rv dspace: /app
# Need git to support buildnumber-maven-plugin, which lets us know what version of DSpace is being run.
RUN apt-get update \
&& apt-get install -y --no-install-recommends git \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
# Switch to dspace user & run below commands as that user
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Trigger the installation of all maven dependencies (hide download progress messages)
RUN mvn --no-transfer-progress package
# Clear the contents of the /app directory (including all maven builds), so no artifacts remain.
# This ensures when dspace:dspace is built, it will use the Maven local cache (~/.m2) for dependencies
USER root
RUN rm -rf /app/*

View File

@@ -1,80 +0,0 @@
# This image will be published as dspace/dspace
# See https://github.com/DSpace/DSpace/tree/main/dspace/src/main/docker for usage details
#
# - note: default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-test
#
# This image is meant for TESTING/DEVELOPMENT ONLY as it deploys the old v6 REST API under HTTP (not HTTPS)
# This Dockerfile uses JDK11 by default, but has also been tested with JDK17.
# To build with JDK17, use "--build-arg JDK_VERSION=17"
ARG JDK_VERSION=11
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-7_x as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-installer directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install \
&& chown -Rv dspace: /app
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Build DSpace (INCLUDING the optional, deprecated "dspace-rest" webapp)
# Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
RUN mvn package -Pdspace-rest && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM openjdk:${JDK_VERSION}-slim as ant_build
ARG TARGET_DIR=dspace-installer
# COPY the /install directory from 'build' container to /dspace-src in this container
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.12
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
# Need wget to install ant
RUN apt-get update \
&& apt-get install -y --no-install-recommends wget \
&& apt-get purge -y --auto-remove \
&& rm -rf /var/lib/apt/lists/*
# Download and install 'ant'
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
# Run necessary 'ant' deploy scripts
RUN ant init_installation update_configs update_code update_webapps
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
FROM tomcat:9-jdk${JDK_VERSION}
ENV DSPACE_INSTALL=/dspace
ENV TOMCAT_INSTALL=/usr/local/tomcat
# Copy the /dspace directory from 'ant_build' containger to /dspace in this container
COPY --from=ant_build /dspace $DSPACE_INSTALL
# Enable the AJP connector in Tomcat's server.xml
# NOTE: secretRequired="false" should only be used when AJP is NOT accessible from an external network. But, secretRequired="true" isn't supported by mod_proxy_ajp until Apache 2.5
RUN sed -i '/Service name="Catalina".*/a \\n <Connector protocol="AJP/1.3" port="8009" address="0.0.0.0" redirectPort="8443" URIEncoding="UTF-8" secretRequired="false" />' $TOMCAT_INSTALL/conf/server.xml
# Expose Tomcat port and AJP port
EXPOSE 8080 8009
# Give java extra memory (2GB)
ENV JAVA_OPTS=-Xmx2000m
# Link the DSpace 'server' webapp into Tomcat's webapps directory.
# This ensures that when we start Tomcat, it runs from /server path (e.g. http://localhost:8080/server/)
# Also link the v6.x (deprecated) REST API off the "/rest" path
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
# If you wish to run "server" webapp off the ROOT path, then comment out the above RUN, and uncomment the below RUN.
# You also MUST update the 'dspace.server.url' configuration to match.
# Please note that server webapp should only run on one path at a time.
#RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT && \
# ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
# Overwrite the v6.x (deprecated) REST API's web.xml, so that we can run it on HTTP (defaults to requiring HTTPS)
# WARNING: THIS IS OBVIOUSLY INSECURE. NEVER DO THIS IN PRODUCTION.
COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml

21
LICENSE
View File

@@ -1,6 +1,7 @@
BSD 3-Clause License DSpace source code license:
Copyright (c) 2002-2021, LYRASIS. All rights reserved.
Copyright (c) 2002-2016, DuraSpace. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are modification, are permitted provided that the following conditions are
@@ -13,12 +14,13 @@ notice, this list of conditions and the following disclaimer.
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holder nor the names of its - Neither the name DuraSpace nor the name of the DSpace Foundation
contributors may be used to endorse or promote products derived from nor the names of its contributors may be used to endorse or promote
this software without specific prior written permission. products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
@@ -29,3 +31,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. DAMAGE.
DSpace uses third-party libraries which may be distributed under
different licenses to the above. Information about these licenses
is detailed in the LICENSES_THIRD_PARTY file at the root of the source
tree. You must agree to the terms of these licenses, in addition to
the above DSpace source code license, in order to use this software.

View File

@@ -15,566 +15,371 @@ PLEASE NOTE: Some dependencies may be listed under multiple licenses if they
are dual-licensed. This is especially true of anything listed as are dual-licensed. This is especially true of anything listed as
"GNU General Public Library" below, as DSpace actually does NOT allow for any "GNU General Public Library" below, as DSpace actually does NOT allow for any
dependencies that are solely released under GPL terms. For more info see: dependencies that are solely released under GPL terms. For more info see:
https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
--------------------------------------------------- ---------------------------------------------------
Apache Software License, Version 2.0: Apache Software License, Version 2.0:
* Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net) * Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net)
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.12.116 - https://aws.amazon.com/sdkforjava) * Code Generation Library (cglib:cglib:2.2.2 - http://cglib.sourceforge.net/)
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.12.116 - https://aws.amazon.com/sdkforjava) * AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.10.50 - https://aws.amazon.com/sdkforjava)
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.12.116 - https://aws.amazon.com/sdkforjava) * AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.10.50 - https://aws.amazon.com/sdkforjava)
* JMES Path Query library (com.amazonaws:jmespath-java:1.12.116 - https://aws.amazon.com/sdkforjava) * AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.10.50 - https://aws.amazon.com/sdkforjava)
* jcommander (com.beust:jcommander:1.78 - https://jcommander.org) * HPPC Collections (com.carrotsearch:hppc:0.5.2 - http://labs.carrotsearch.com/hppc.html/hppc)
* HPPC Collections (com.carrotsearch:hppc:0.8.1 - http://labs.carrotsearch.com/hppc.html/hppc) * metadata-extractor (com.drewnoakes:metadata-extractor:2.6.2 - http://code.google.com/p/metadata-extractor/)
* parso (com.epam:parso:2.0.11 - https://github.com/epam/parso) * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.5.4 - http://github.com/FasterXML/jackson)
* ClassMate (com.fasterxml:classmate:1.3.0 - http://github.com/cowtowncoder/java-classmate) * Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.7.0 - http://github.com/FasterXML/jackson)
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.12.3 - http://github.com/FasterXML/jackson) * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.5.4 - https://github.com/FasterXML/jackson)
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.12.3 - https://github.com/FasterXML/jackson-core) * Jackson-core (com.fasterxml.jackson.core:jackson-core:2.7.0 - https://github.com/FasterXML/jackson-core)
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.12.3 - http://github.com/FasterXML/jackson) * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.5.4 - http://github.com/FasterXML/jackson)
* Jackson dataformat: CBOR (com.fasterxml.jackson.dataformat:jackson-dataformat-cbor:2.12.3 - http://github.com/FasterXML/jackson-dataformats-binary) * jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.7.0 - http://github.com/FasterXML/jackson)
* Jackson dataformat: Smile (com.fasterxml.jackson.dataformat:jackson-dataformat-smile:2.11.2 - http://github.com/FasterXML/jackson-dataformats-binary) * Jackson-JAXRS-base (com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-base)
* Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.1 - https://github.com/FasterXML/jackson-dataformats-text) * Jackson-JAXRS-JSON (com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-json-provider)
* Jackson datatype: jdk8 (com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.10.3 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jdk8) * Jackson-module-JAXB-annotations (com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.5.4 - http://wiki.fasterxml.com/JacksonJAXBAnnotations)
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.10.3 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) * Google APIs Client Library for Java (com.google.api-client:google-api-client:1.21.0 - https://github.com/google/google-api-java-client/google-api-client)
* Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.11.1 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310) * Google Analytics API v3-rev123-1.21.0 (com.google.apis:google-api-services-analytics:v3-rev123-1.21.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
* Jackson-module-parameter-names (com.fasterxml.jackson.module:jackson-module-parameter-names:2.10.3 - https://github.com/FasterXML/jackson-modules-java8/jackson-module-parameter-names)
* Java UUID Generator (com.fasterxml.uuid:java-uuid-generator:4.0.1 - https://github.com/cowtowncoder/java-uuid-generator)
* Woodstox (com.fasterxml.woodstox:woodstox-core:5.0.3 - https://github.com/FasterXML/woodstox)
* zjsonpatch (com.flipkart.zjsonpatch:zjsonpatch:0.4.6 - https://github.com/flipkart-incubator/zjsonpatch/)
* Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.8.4 - https://github.com/ben-manes/caffeine)
* btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
* jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
* jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
* 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)
* Open JSON (com.github.openjson:openjson:1.0.12 - https://github.com/openjson/openjson)
* JCIP Annotations under Apache License (com.github.stephenc.jcip:jcip-annotations:1.0-1 - http://stephenc.github.com/jcip-annotations)
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.23.0 - https://github.com/google/google-api-java-client/google-api-client)
* Google Analytics API v3-rev145-1.23.0 (com.google.apis:google-api-services-analytics:v3-rev145-1.23.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.1 - http://findbugs.sourceforge.net/) * FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.1 - http://findbugs.sourceforge.net/)
* Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson) * Gson (com.google.code.gson:gson:2.6.1 - https://github.com/google/gson/gson)
* error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations) * Guava: Google Core Libraries for Java (com.google.guava:guava:14.0.1 - http://code.google.com/p/guava-libraries/guava)
* 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:19.0 - https://github.com/google/guava/guava)
* Guava: Google Core Libraries for Java (com.google.guava:guava:30.0-jre - https://github.com/google/guava/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 (JDK5 Backport) (com.google.guava:guava-jdk5:17.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
* Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture) * Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.21.0 - https://github.com/google/google-http-java-client/google-http-client)
* 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) * Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.21.0 - https://github.com/google/google-http-java-client/google-http-client-jackson2)
* 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 OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.21.0 - https://github.com/google/google-oauth-java-client/google-oauth-client)
* J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/) * ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.2 - http://code.google.com/p/concurrentlinkedhashmap)
* Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.32.1 - https://github.com/googleapis/google-oauth-java-client/google-oauth-client) * ISO Parser (com.googlecode.mp4parser:isoparser:1.0-RC-1 - http://code.google.com/p/mp4parser/)
* ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2 - http://code.google.com/p/concurrentlinkedhashmap)
* JSON.simple (com.googlecode.json-simple:json-simple:1.1.1 - http://code.google.com/p/json-simple/)
* libphonenumber (com.googlecode.libphonenumber:libphonenumber:8.11.1 - https://github.com/google/libphonenumber/)
* Jackcess (com.healthmarketscience.jackcess:jackcess:3.0.1 - https://jackcess.sourceforge.io)
* Jackcess Encrypt (com.healthmarketscience.jackcess:jackcess-encrypt:3.0.0 - http://jackcessencrypt.sf.net)
* project ':json-path' (com.jayway.jsonpath:json-path:2.4.0 - https://github.com/jayway/JsonPath)
* project ':json-path-assert' (com.jayway.jsonpath:json-path-assert:2.4.0 - https://github.com/jayway/JsonPath)
* Disruptor Framework (com.lmax:disruptor:3.4.2 - http://lmax-exchange.github.com/disruptor)
* builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons) * builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons)
* MaxMind DB Reader (com.maxmind.db:maxmind-db:1.2.2 - http://dev.maxmind.com/) * Jtwig Core (com.lyncode:jtwig-core:2.0.1 - http://www.lyncode.com/jtwig-core)
* MaxMind GeoIP2 API (com.maxmind.geoip2:geoip2:2.11.0 - http://dev.maxmind.com/geoip/geoip2/web-services) * Jtwig Core Functions (com.lyncode:jtwig-functions:2.0.1 - http://www.lyncode.com/jtwig-functions)
* Nimbus JOSE+JWT (com.nimbusds:nimbus-jose-jwt:7.9 - https://bitbucket.org/connect2id/nimbus-jose-jwt) * Jtwig Spring (com.lyncode:jtwig-spring:2.0.1 - http://www.lyncode.com/jtwig-spring)
* opencsv (com.opencsv:opencsv:5.2 - http://opencsv.sf.net) * Test Support (com.lyncode:test-support:1.0.3 - http://nexus.sonatype.org/oss-repository-hosting.html/test-support)
* java-libpst (com.pff:java-libpst:0.9.3 - https://github.com/rjohnsondev/java-libpst) * Spatial4J (com.spatial4j:spatial4j:0.4.1 - https://github.com/spatial4j/spatial4j)
* rome (com.rometools:rome:1.12.2 - http://rometools.com/rome) * Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.2 - http://commons.apache.org/proper/commons-beanutils/)
* rome-utils (com.rometools:rome-utils:1.12.2 - http://rometools.com/rome-utils) * Apache Commons CLI (commons-cli:commons-cli:1.3.1 - http://commons.apache.org/proper/commons-cli/)
* fastinfoset (com.sun.xml.fastinfoset:FastInfoset:1.2.15 - http://fi.java.net)
* T-Digest (com.tdunning:t-digest:3.1 - https://github.com/tdunning/t-digest)
* JSON library from Android SDK (com.vaadin.external.google:android-json:0.0.20131108.vaadin1 - http://developer.android.com/sdk)
* HikariCP (com.zaxxer:HikariCP-java7:2.4.13 - https://github.com/brettwooldridge/HikariCP)
* SparseBitSet (com.zaxxer:SparseBitSet:1.2 - https://github.com/brettwooldridge/SparseBitSet)
* Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.4 - https://commons.apache.org/proper/commons-beanutils/)
* Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
* Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/) * Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/)
* Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/) * Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/)
* Apache Commons Configuration (commons-configuration:commons-configuration:1.10 - http://commons.apache.org/configuration/)
* Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/) * Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/)
* Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.3.3 - http://commons.apache.org/proper/commons-fileupload/) * Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.3.1 - http://commons.apache.org/proper/commons-fileupload/)
* Apache Commons IO (commons-io:commons-io:2.7 - https://commons.apache.org/proper/commons-io/) * HttpClient (commons-httpclient:commons-httpclient:3.1 - http://jakarta.apache.org/httpcomponents/httpclient-3.x/)
* Commons IO (commons-io:commons-io:2.4 - http://commons.apache.org/io/)
* commons-jexl (commons-jexl:commons-jexl:1.0 - no url defined)
* Commons JXPath (commons-jxpath:commons-jxpath:1.3 - http://commons.apache.org/jxpath/)
* Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/) * Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/)
* Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/) * Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
* Apache Commons Validator (commons-validator:commons-validator:1.5.0 - http://commons.apache.org/proper/commons-validator/) * Apache Commons Validator (commons-validator:commons-validator:1.5.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)
* Boilerpipe -- Boilerplate Removal and Fulltext Extraction from HTML pages (de.l3s.boilerpipe:boilerpipe:1.1.0 - http://code.google.com/p/boilerpipe/) * Boilerpipe -- Boilerplate Removal and Fulltext Extraction from HTML pages (de.l3s.boilerpipe:boilerpipe:1.1.0 - http://code.google.com/p/boilerpipe/)
* SentimentAnalysisParser (edu.usc.ir:sentiment-analysis-parser:0.1 - https://github.com/USCDataScience/SentimentAnalysisParser) * The Netty Project (io.netty:netty:3.7.0.Final - http://netty.io/)
* OpenAIRE Funders Model (eu.openaire:funders-model:2.0.0 - https://api.openaire.eu) * jakarta-regexp (jakarta-regexp:jakarta-regexp:1.4 - no url defined)
* Metrics Core (io.dropwizard.metrics:metrics-core:4.1.5 - 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)
* Netty (io.netty:netty:3.10.6.Final - http://netty.io/)
* Netty/Buffer (io.netty:netty-buffer:4.1.50.Final - https://netty.io/netty-buffer/)
* Netty/Buffer (io.netty:netty-buffer:4.1.68.Final - https://netty.io/netty-buffer/)
* Netty/Codec (io.netty:netty-codec:4.1.50.Final - https://netty.io/netty-codec/)
* Netty/Codec (io.netty:netty-codec:4.1.68.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.50.Final - https://netty.io/netty-common/)
* Netty/Common (io.netty:netty-common:4.1.68.Final - https://netty.io/netty-common/)
* Netty/Handler (io.netty:netty-handler:4.1.50.Final - https://netty.io/netty-handler/)
* Netty/Handler (io.netty:netty-handler:4.1.68.Final - https://netty.io/netty-handler/)
* Netty/Handler/Proxy (io.netty:netty-handler-proxy:4.1.53.Final - https://netty.io/netty-handler-proxy/)
* Netty/Resolver (io.netty:netty-resolver:4.1.50.Final - https://netty.io/netty-resolver/)
* Netty/Transport (io.netty:netty-transport:4.1.50.Final - https://netty.io/netty-transport/)
* Netty/Transport (io.netty:netty-transport:4.1.68.Final - https://netty.io/netty-transport/)
* Netty/Transport/Native/Epoll (io.netty:netty-transport-native-epoll:4.1.50.Final - https://netty.io/netty-transport-native-epoll/)
* Netty/Transport/Native/Unix/Common (io.netty:netty-transport-native-unix-common:4.1.50.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)
* Google S2 geometry library (io.sgr:s2-geometry-library-java:1.0.0 - https://github.com/sgr-io/s2-geometry-library-java)
* 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-core (io.swagger.core.v3:swagger-core:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-core)
* swagger-models (io.swagger.core.v3:swagger-models:2.1.5 - https://github.com/swagger-api/swagger-core/modules/swagger-models)
* 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)
* Jakarta Bean Validation API (jakarta.validation:jakarta.validation-api:2.0.2 - https://beanvalidation.org)
* JSR107 API and SPI (javax.cache:cache-api:1.1.0 - https://github.com/jsr107/jsr107spec)
* javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/) * javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
* Bean Validation API (javax.validation:validation-api:2.0.1.Final - http://beanvalidation.org) * Bean Validation API (javax.validation:validation-api:1.1.0.Final - http://beanvalidation.org)
* jdbm (jdbm:jdbm:1.0 - no url defined) * jdbm (jdbm:jdbm:1.0 - no url defined)
* Joda time (joda-time:joda-time:2.2 - http://joda-time.sourceforge.net)
* Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/) * Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/)
* Byte Buddy (without dependencies) (net.bytebuddy:byte-buddy:1.11.13 - https://bytebuddy.net/byte-buddy) * Apache Log4j (log4j:log4j:1.2.17 - http://logging.apache.org/log4j/1.2/)
* 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)
* Java Native Access (net.java.dev.jna:jna:5.5.0 - https://github.com/java-native-access/jna)
* json-unit-core (net.javacrumbs.json-unit:json-unit-core:2.19.0 - https://github.com/lukas-krecan/JsonUnit/json-unit-core)
* "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/) * "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/)
* ASM based accessors helper used by json-smart (net.minidev:accessors-smart:1.2 - http://www.minidev.net/) * Ehcache Core (net.sf.ehcache:ehcache-core:2.4.3 - http://ehcache.org)
* JSON Small and Fast Parser (net.minidev:json-smart:2.3 - http://www.minidev.net/) * opencsv (net.sf.opencsv:opencsv:2.3 - http://opencsv.sf.net)
* ehcache (net.sf.ehcache:ehcache:2.10.6 - http://ehcache.org) * Abdera Client (org.apache.abdera:abdera-client:1.1.3 - http://abdera.apache.org/abdera-client)
* Ehcache Core (net.sf.ehcache:ehcache-core:2.6.11 - http://ehcache.org)
* Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core) * Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core)
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org) * I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org)
* Apache Ant Core (org.apache.ant:ant:1.10.11 - https://ant.apache.org/) * Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser)
* Apache Ant Launcher (org.apache.ant:ant-launcher:1.10.11 - https://ant.apache.org/) * org.apache.tools.ant (org.apache.ant:ant:1.7.0 - http://ant.apache.org/ant/)
* Apache Commons BCEL (org.apache.bcel:bcel:6.4.0 - https://commons.apache.org/proper/commons-bcel) * ant-launcher (org.apache.ant:ant-launcher:1.7.0 - http://ant.apache.org/ant-launcher/)
* Calcite Core (org.apache.calcite:calcite-core:1.18.0 - https://calcite.apache.org/calcite-core) * Avalon Framework API (org.apache.avalon.framework:avalon-framework-api:4.3.1 - http://www.apache.org/excalibur/avalon-framework/avalon-framework-api/)
* Calcite Linq4j (org.apache.calcite:calcite-linq4j:1.18.0 - https://calcite.apache.org/calcite-linq4j) * Avalon Framework Implementation (org.apache.avalon.framework:avalon-framework-impl:4.3.1 - http://www.apache.org/excalibur/avalon-framework/avalon-framework-impl/)
* Apache Calcite Avatica (org.apache.calcite.avatica:avatica-core:1.13.0 - https://calcite.apache.org/avatica/avatica-core) * Cocoon Configuration API (org.apache.cocoon:cocoon-configuration-api:1.0.2 - http://cocoon.apache.org/subprojects/configuration/1.0/configuration-api/1.0/)
* Apache Commons Collections (org.apache.commons:commons-collections4:4.1 - http://commons.apache.org/proper/commons-collections/) * Cocoon Core (org.apache.cocoon:cocoon-core:2.2.0 - http://cocoon.apache.org/2.2/core-modules/core/2.2/)
* Apache Commons Compress (org.apache.commons:commons-compress:1.20 - https://commons.apache.org/proper/commons-compress/) * Cocoon Expression Language API (org.apache.cocoon:cocoon-expression-language-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/expression-language-api/1.0/)
* Apache Commons Configuration (org.apache.commons:commons-configuration2:2.7 - https://commons.apache.org/proper/commons-configuration/) * Cocoon Expression Language Implementation. (org.apache.cocoon:cocoon-expression-language-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/expression-language-impl/1.0/)
* Apache Commons CSV (org.apache.commons:commons-csv:1.8 - https://commons.apache.org/proper/commons-csv/) * Cocoon Flowscript Block Implementation (org.apache.cocoon:cocoon-flowscript-impl:1.0.0 - http://cocoon.apache.org/2.2/blocks/flowscript/1.0/)
* Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.8.0 - https://commons.apache.org/dbcp/) * Cocoon Linkrewriter Block Implementation (org.apache.cocoon:cocoon-linkrewriter-impl:1.0.0 - http://cocoon.apache.org/2.2/blocks/linkrewriter/1.0/)
* Apache Commons Exec (org.apache.commons:commons-exec:1.3 - http://commons.apache.org/proper/commons-exec/) * Cocoon Pipeline API (org.apache.cocoon:cocoon-pipeline-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-api/1.0/)
* Apache Commons Lang (org.apache.commons:commons-lang3:3.7 - http://commons.apache.org/proper/commons-lang/) * Cocoon Pipeline Components (org.apache.cocoon:cocoon-pipeline-components:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-components/1.0/)
* Apache Commons Math (org.apache.commons:commons-math3:3.6.1 - http://commons.apache.org/proper/commons-math/) * Cocoon Pipeline Implementation (org.apache.cocoon:cocoon-pipeline-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-impl/1.0/)
* Apache Commons Pool (org.apache.commons:commons-pool2:2.9.0 - https://commons.apache.org/proper/commons-pool/) * Cocoon Servlet Service Components (org.apache.cocoon:cocoon-servlet-service-components:1.0.0 - http://cocoon.apache.org/subprojects/servlet-service/1.0/servlet-service-components/1.0/)
* Apache Commons Text (org.apache.commons:commons-text:1.8 - https://commons.apache.org/proper/commons-text) * Cocoon Sitemap API (org.apache.cocoon:cocoon-sitemap-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-api/1.0/)
* Apache Commons Text (org.apache.commons:commons-text:1.9 - https://commons.apache.org/proper/commons-text) * Cocoon Sitemap Components (org.apache.cocoon:cocoon-sitemap-components:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-components/1.0/)
* Curator Client (org.apache.curator:curator-client:2.13.0 - http://curator.apache.org/curator-client) * Cocoon Sitemap Implementation (org.apache.cocoon:cocoon-sitemap-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-impl/1.0/)
* Curator Framework (org.apache.curator:curator-framework:2.13.0 - http://curator.apache.org/curator-framework) * Cocoon Spring Configurator (org.apache.cocoon:cocoon-spring-configurator:1.0.2 - http://cocoon.apache.org/cocoon-spring-configurator)
* Curator Recipes (org.apache.curator:curator-recipes:2.13.0 - http://curator.apache.org/curator-recipes) * Cocoon Store Implementation (org.apache.cocoon:cocoon-store-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/store-impl/1.0/)
* Apache CXF Core (org.apache.cxf:cxf-core:3.3.6 - https://cxf.apache.org) * Cocoon Template Framework Block Implementation (org.apache.cocoon:cocoon-template-impl:1.1.0 - http://cocoon.apache.org/2.2/blocks/template/1.0/)
* Apache CXF Runtime JAX-RS Frontend (org.apache.cxf:cxf-rt-frontend-jaxrs:3.3.6 - https://cxf.apache.org) * Cocoon Thread API (org.apache.cocoon:cocoon-thread-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/thread-api/1.0/)
* Apache CXF JAX-RS Client (org.apache.cxf:cxf-rt-rs-client:3.3.6 - https://cxf.apache.org) * Cocoon Thread Implementation (org.apache.cocoon:cocoon-thread-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/thread-impl/1.0/)
* Apache CXF Runtime Security functionality (org.apache.cxf:cxf-rt-security:3.3.6 - https://cxf.apache.org) * Cocoon Util (org.apache.cocoon:cocoon-util:1.0.0 - http://cocoon.apache.org/2.2/core-modules/util/1.0/)
* Apache CXF Runtime HTTP Transport (org.apache.cxf:cxf-rt-transports-http:3.3.6 - https://cxf.apache.org) * Cocoon XML API (org.apache.cocoon:cocoon-xml-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-api/1.0/)
* JTA 1.1 (org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1 - http://geronimo.apache.org/specs/geronimo-jta_1.1_spec) * Cocoon XML Implementation (org.apache.cocoon:cocoon-xml-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-impl/1.0/)
* Web Services Metadata 2.0 (org.apache.geronimo.specs:geronimo-ws-metadata_2.0_spec:1.1.3 - http://geronimo.apache.org/maven/specs/geronimo-ws-metadata_2.0_spec/1.1.3) * Cocoon XML Resolver (org.apache.cocoon:cocoon-xml-resolver:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-resolver/1.0/)
* Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:3.2.0 - no url defined) * Cocoon XML Utilities (org.apache.cocoon:cocoon-xml-util:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-util/1.0/)
* Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:3.2.0 - no url defined) * Apache Commons Compress (org.apache.commons:commons-compress:1.7 - http://commons.apache.org/proper/commons-compress/)
* Apache Hadoop Common (org.apache.hadoop:hadoop-common:3.2.0 - no url defined) * Apache Commons CSV (org.apache.commons:commons-csv:1.0 - http://commons.apache.org/proper/commons-csv/)
* Apache Hadoop HDFS Client (org.apache.hadoop:hadoop-hdfs-client:3.2.0 - no url defined) * Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.1.1 - http://commons.apache.org/dbcp/)
* htrace-core4 (org.apache.htrace:htrace-core4:4.1.0-incubating - http://incubator.apache.org/projects/htrace.html) * Apache Commons Lang (org.apache.commons:commons-lang3:3.3.2 - http://commons.apache.org/proper/commons-lang/)
* Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.13 - http://hc.apache.org/httpcomponents-client) * Apache Commons Pool (org.apache.commons:commons-pool2:2.4.2 - http://commons.apache.org/proper/commons-pool/)
* Excalibur Pool API (org.apache.excalibur.components:excalibur-pool-api:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-pool-modules/excalibur-pool-api/)
* Excalibur Sourceresolve (org.apache.excalibur.components:excalibur-sourceresolve:2.2.3 - http://www.apache.org/excalibur/excalibur-sourceresolve/)
* Excalibur Store (org.apache.excalibur.components:excalibur-store:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-store/)
* Excalibur XML Utilities (org.apache.excalibur.components:excalibur-xmlutil:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-xmlutil/)
* Excalibur Instrument API (org.apache.excalibur.containerkit:excalibur-instrument-api:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-instrument-modules/excalibur-instrument-api/)
* Excalibur Logger (org.apache.excalibur.containerkit:excalibur-logger:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-logger/)
* Activation 1.1 (org.apache.geronimo.specs:geronimo-activation_1.1_spec:1.1 - http://geronimo.apache.org/maven/specs/geronimo-activation_1.1_spec/1.1)
* JavaMail 1.4 (org.apache.geronimo.specs:geronimo-javamail_1.4_spec:1.7.1 - http://geronimo.apache.org/maven/specs/geronimo-javamail_1.4_spec/1.7.1)
* Streaming API for XML (STAX API 1.0) (org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:1.0.1 - http://geronimo.apache.org/specs/geronimo-stax-api_1.0_spec)
* Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:2.2.0 - no url defined)
* Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:2.2.0 - no url defined)
* Apache Hadoop Common (org.apache.hadoop:hadoop-common:2.2.0 - no url defined)
* Apache Hadoop HDFS (org.apache.hadoop:hadoop-hdfs:2.2.0 - no url defined)
* Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.1 - http://hc.apache.org/httpcomponents-client)
* Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client) * Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client)
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.4 - http://hc.apache.org/httpcomponents-core-ga) * Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.4 - http://hc.apache.org/httpcomponents-core-ga)
* Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.5.12 - http://hc.apache.org/httpcomponents-client) * Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.3.1 - http://hc.apache.org/httpcomponents-client)
* Apache James :: Mime4j :: Core (org.apache.james:apache-mime4j-core:0.8.3 - http://james.apache.org/mime4j/apache-mime4j-core) * Apache JAMES Mime4j (Core) (org.apache.james:apache-mime4j-core:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-core)
* Apache James :: Mime4j :: DOM (org.apache.james:apache-mime4j-dom:0.8.3 - http://james.apache.org/mime4j/apache-mime4j-dom) * Apache JAMES Mime4j (DOM) (org.apache.james:apache-mime4j-dom:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-dom)
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/) * Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/)
* Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/) * Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/)
* Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/) * Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/)
* Apache Jena - IRI (org.apache.jena:jena-iri:1.1.2 - http://jena.apache.org/jena-iri/) * Apache Jena - IRI (org.apache.jena:jena-iri:1.1.2 - http://jena.apache.org/jena-iri/)
* Apache Jena - TDB (Native Triple Store) (org.apache.jena:jena-tdb:1.1.2 - http://jena.apache.org/jena-tdb/) * Apache Jena - TDB (Native Triple Store) (org.apache.jena:jena-tdb:1.1.2 - http://jena.apache.org/jena-tdb/)
* Kerby-kerb core (org.apache.kerby:kerb-core:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-core) * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
* Kerby-kerb Util (org.apache.kerby:kerb-util:1.0.1 - http://directory.apache.org/kerby/kerby-kerb/kerb-util) * Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
* Kerby ASN1 Project (org.apache.kerby:kerby-asn1:1.0.1 - http://directory.apache.org/kerby/kerby-common/kerby-asn1) * Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
* Kerby PKIX Project (org.apache.kerby:kerby-pkix:1.0.1 - http://directory.apache.org/kerby/kerby-pkix) * Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
* Apache Log4j 1.x Compatibility API (org.apache.logging.log4j:log4j-1.2-api:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-1.2-api/) * Lucene Morfologik Polish Lemmatizer (org.apache.lucene:lucene-analyzers-morfologik:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-morfologik)
* Apache Log4j API (org.apache.logging.log4j:log4j-api:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-api/) * Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
* Apache Log4j Core (org.apache.logging.log4j:log4j-core:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-core/) * Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
* Apache Log4j JUL Adapter (org.apache.logging.log4j:log4j-jul:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-jul/) * Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
* Apache Log4j SLF4J Binding (org.apache.logging.log4j:log4j-slf4j-impl:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-slf4j-impl/) * Lucene codecs (org.apache.lucene:lucene-codecs:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-codecs)
* Apache Log4j Web (org.apache.logging.log4j:log4j-web:2.17.1 - https://logging.apache.org/log4j/2.x/log4j-web/) * Lucene Core (org.apache.lucene:lucene-core:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-core)
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-common) * Lucene Core (org.apache.lucene:lucene-core:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-core)
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-icu) * Lucene Expressions (org.apache.lucene:lucene-expressions:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-expressions)
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji) * Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-grouping)
* Lucene Nori Korean Morphological Analyzer (org.apache.lucene:lucene-analyzers-nori:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-nori) * Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-grouping)
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic) * Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn) * Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-analyzers-stempel) * Lucene Join (org.apache.lucene:lucene-join:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-join)
* Lucene Memory (org.apache.lucene:lucene-backward-codecs:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-backward-codecs) * Lucene Join (org.apache.lucene:lucene-join:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-join)
* Lucene Classification (org.apache.lucene:lucene-classification:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-classification) * Lucene Memory (org.apache.lucene:lucene-memory:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-memory)
* Lucene codecs (org.apache.lucene:lucene-codecs:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-codecs) * Lucene Memory (org.apache.lucene:lucene-memory:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-memory)
* Lucene Core (org.apache.lucene:lucene-core:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-core) * Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-misc)
* Lucene Expressions (org.apache.lucene:lucene-expressions:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-expressions) * Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-misc)
* Lucene Grouping (org.apache.lucene:lucene-grouping:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-grouping) * Lucene Queries (org.apache.lucene:lucene-queries:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queries)
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-highlighter) * Lucene Queries (org.apache.lucene:lucene-queries:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queries)
* Lucene Join (org.apache.lucene:lucene-join:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-join) * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
* Lucene Memory (org.apache.lucene:lucene-memory:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-memory) * Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-misc) * Lucene Sandbox (org.apache.lucene:lucene-sandbox:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-sandbox)
* Lucene Queries (org.apache.lucene:lucene-queries:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-queries) * Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-spatial)
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-queryparser) * Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-spatial)
* Lucene Sandbox (org.apache.lucene:lucene-sandbox:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-sandbox) * Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-suggest)
* Lucene Spatial Extras (org.apache.lucene:lucene-spatial-extras:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-spatial-extras) * Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-suggest)
* Lucene Spatial 3D (org.apache.lucene:lucene-spatial3d:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-spatial3d) * Apache FontBox (org.apache.pdfbox:fontbox:2.0.2 - http://pdfbox.apache.org/)
* Lucene Suggest (org.apache.lucene:lucene-suggest:8.8.1 - https://lucene.apache.org/lucene-parent/lucene-suggest) * Apache JempBox (org.apache.pdfbox:jempbox:1.8.4 - http://www.apache.org/pdfbox-parent/jempbox/)
* Apache OpenNLP Tools (org.apache.opennlp:opennlp-tools:1.9.2 - https://www.apache.org/opennlp/opennlp-tools/) * Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.2 - http://www.apache.org/pdfbox-parent/pdfbox/)
* Apache FontBox (org.apache.pdfbox:fontbox:2.0.24 - http://pdfbox.apache.org/) * Apache POI (org.apache.poi:poi:3.13 - http://poi.apache.org/)
* PDFBox JBIG2 ImageIO plugin (org.apache.pdfbox:jbig2-imageio:3.0.3 - https://www.apache.org/jbig2-imageio/) * Apache POI (org.apache.poi:poi-ooxml:3.13 - http://poi.apache.org/)
* Apache JempBox (org.apache.pdfbox:jempbox:1.8.16 - http://www.apache.org/pdfbox-parent/jempbox/) * Apache POI (org.apache.poi:poi-ooxml-schemas:3.10.1 - http://poi.apache.org/)
* Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.24 - https://www.apache.org/pdfbox-parent/pdfbox/) * Apache POI (org.apache.poi:poi-ooxml-schemas:3.13 - http://poi.apache.org/)
* Apache PDFBox tools (org.apache.pdfbox:pdfbox-tools:2.0.19 - https://www.apache.org/pdfbox-parent/pdfbox-tools/) * Apache POI (org.apache.poi:poi-scratchpad:3.13 - http://poi.apache.org/)
* Apache Preflight (org.apache.pdfbox:preflight:2.0.19 - https://www.apache.org/pdfbox-parent/preflight/) * Apache Solr Search Server (org.apache.solr:solr:4.10.4 - http://lucene.apache.org/solr-parent/solr)
* Apache XmpBox (org.apache.pdfbox:xmpbox:2.0.19 - https://www.apache.org/pdfbox-parent/xmpbox/) * Apache Solr Analysis Extras (org.apache.solr:solr-analysis-extras:4.10.4 - http://lucene.apache.org/solr-parent/solr-analysis-extras)
* Apache POI (org.apache.poi:poi:3.17 - http://poi.apache.org/) * Apache Solr Content Extraction Library (org.apache.solr:solr-cell:4.10.4 - http://lucene.apache.org/solr-parent/solr-cell)
* Apache POI (org.apache.poi:poi-ooxml:3.17 - http://poi.apache.org/) * Apache Solr Core (org.apache.solr:solr-core:4.10.4 - http://lucene.apache.org/solr-parent/solr-core)
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.17 - http://poi.apache.org/) * Apache Solr Solrj (org.apache.solr:solr-solrj:4.10.4 - http://lucene.apache.org/solr-parent/solr-solrj)
* Apache POI (org.apache.poi:poi-scratchpad:3.17 - http://poi.apache.org/)
* Apache SIS features (org.apache.sis.core:sis-feature:1.0 - http://sis.apache.org/core/sis-feature)
* Apache SIS metadata (org.apache.sis.core:sis-metadata:1.0 - http://sis.apache.org/core/sis-metadata)
* Apache SIS referencing (org.apache.sis.core:sis-referencing:1.0 - http://sis.apache.org/core/sis-referencing)
* Apache SIS utilities (org.apache.sis.core:sis-utility:1.0 - http://sis.apache.org/core/sis-utility)
* Apache SIS netCDF storage (org.apache.sis.storage:sis-netcdf:1.0 - http://sis.apache.org/storage/sis-netcdf)
* Apache SIS common storage (org.apache.sis.storage:sis-storage:1.0 - http://sis.apache.org/storage/sis-storage)
* Apache Solr Content Extraction Library (org.apache.solr:solr-cell:8.8.1 - https://lucene.apache.org/solr-parent/solr-cell)
* Apache Solr Core (org.apache.solr:solr-core:8.8.1 - https://lucene.apache.org/solr-parent/solr-core)
* Apache Solr Solrj (org.apache.solr:solr-solrj:8.8.1 - https://lucene.apache.org/solr-parent/solr-solrj)
* Apache Standard Taglib Implementation (org.apache.taglibs:taglibs-standard-impl:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-impl)
* Apache Standard Taglib Specification API (org.apache.taglibs:taglibs-standard-spec:1.2.5 - http://tomcat.apache.org/taglibs/standard-1.2.5/taglibs-standard-spec)
* Apache Thrift (org.apache.thrift:libthrift:0.9.2 - http://thrift.apache.org) * Apache Thrift (org.apache.thrift:libthrift:0.9.2 - http://thrift.apache.org)
* Apache Tika core (org.apache.tika:tika-core:1.24.1 - http://tika.apache.org/) * Apache Tika core (org.apache.tika:tika-core:1.5 - http://tika.apache.org/)
* Apache Tika Java-7 Components (org.apache.tika:tika-java7:1.24.1 - http://tika.apache.org/) * Apache Tika parsers (org.apache.tika:tika-parsers:1.5 - http://tika.apache.org/)
* Apache Tika parsers (org.apache.tika:tika-parsers:1.24.1 - http://tika.apache.org/) * Apache Tika XMP (org.apache.tika:tika-xmp:1.5 - http://tika.apache.org/)
* Apache Tika XMP (org.apache.tika:tika-xmp:1.24.1 - http://tika.apache.org/) * Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/)
* tomcat-embed-core (org.apache.tomcat.embed:tomcat-embed-core:9.0.33 - https://tomcat.apache.org/) * Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/)
* tomcat-embed-el (org.apache.tomcat.embed:tomcat-embed-el:9.0.33 - https://tomcat.apache.org/) * XmlBeans (org.apache.xmlbeans:xmlbeans:2.6.0 - http://xmlbeans.apache.org)
* tomcat-embed-websocket (org.apache.tomcat.embed:tomcat-embed-websocket:9.0.33 - https://tomcat.apache.org/) * zookeeper (org.apache.zookeeper:zookeeper:3.4.6 - no url defined)
* Apache Velocity - Engine (org.apache.velocity:velocity-engine-core:2.2 - http://velocity.apache.org/engine/devel/velocity-engine-core/) * Evo Inflector (org.atteo:evo-inflector:1.2.1 - http://atteo.org/static/evo-inflector)
* Apache Velocity - JSR 223 Scripting (org.apache.velocity:velocity-engine-scripting:2.2 - http://velocity.apache.org/engine/devel/velocity-engine-scripting/)
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.22 - http://ws.apache.org/axiom/)
* LLOM (org.apache.ws.commons.axiom:axiom-impl:1.2.22 - http://ws.apache.org/axiom/implementations/axiom-impl/)
* Abdera Model (FOM) Implementation (org.apache.ws.commons.axiom:fom-impl:1.2.22 - http://ws.apache.org/axiom/implementations/fom-impl/)
* XmlSchema Core (org.apache.ws.xmlschema:xmlschema-core:2.2.5 - https://ws.apache.org/commons/xmlschema20/xmlschema-core/)
* XmlBeans (org.apache.xmlbeans:xmlbeans:3.1.0 - https://xmlbeans.apache.org/)
* zookeeper (org.apache.zookeeper:zookeeper:3.4.14 - no url defined)
* Apache ZooKeeper - Jute (org.apache.zookeeper:zookeeper-jute:3.6.2 - http://zookeeper.apache.org/zookeeper-jute)
* AssertJ fluent assertions (org.assertj:assertj-core:3.13.2 - http://assertj.org/assertj-core)
* Evo Inflector (org.atteo:evo-inflector:1.2.2 - http://atteo.org/static/evo-inflector)
* jose4j (org.bitbucket.b_c:jose4j:0.6.5 - https://bitbucket.org/b_c/jose4j/)
* TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/) * TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/)
* Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.4.1 - http://woodstox.codehaus.org) * Jackson (org.codehaus.jackson:jackson-core-asl:1.9.13 - http://jackson.codehaus.org)
* jems (org.dmfs:jems:1.18 - https://github.com/dmfs/jems) * Data Mapper for Jackson (org.codehaus.jackson:jackson-mapper-asl:1.9.13 - http://jackson.codehaus.org)
* rfc3986-uri (org.dmfs:rfc3986-uri:0.8.1 - https://github.com/dmfs/uri-toolkit) * Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.1.4 - http://woodstox.codehaus.org)
* Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty) * Woodstox (org.codehaus.woodstox:wstx-asl:3.2.0 - http://woodstox.codehaus.org)
* Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/) * Woodstox (org.codehaus.woodstox:wstx-asl:3.2.7 - http://woodstox.codehaus.org)
* Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client) * flyway-core (org.flywaydb:flyway-core:4.0.3 - https://flywaydb.org/flyway-core)
* Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client) * Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.1 - https://github.com/Gagravarr/VorbisJava)
* Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server) * Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.1 - https://github.com/Gagravarr/VorbisJava)
* Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server) * Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-client)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-continuation)
* Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-deploy)
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-http)
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-io)
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.34.v20201102 - 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.34.v20201102 - https://eclipse.org/jetty/jetty-rewrite)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-security)
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-server)
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-servlet)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-servlets)
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-util)
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-webapp)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-xml)
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-client)
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-common)
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-hpack)
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
* Ehcache (org.ehcache:ehcache:3.4.0 - http://ehcache.org)
* flyway-core (org.flywaydb:flyway-core:6.5.7 - https://flywaydb.org/flyway-core)
* Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.8 - https://github.com/Gagravarr/VorbisJava)
* Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.8 - https://github.com/Gagravarr/VorbisJava)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Hibernate Validator Engine (org.hibernate.validator:hibernate-validator:6.0.18.Final - http://hibernate.org/validator/hibernate-validator)
* Hibernate Validator Portable Extension (org.hibernate.validator:hibernate-validator-cdi:6.0.18.Final - http://hibernate.org/validator/hibernate-validator-cdi)
* Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/)
* Java Annotation Indexer (org.jboss:jandex:2.1.1.Final - http://www.jboss.org/jandex)
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.3.2.Final - http://www.jboss.org)
* JDOM (org.jdom:jdom:1.1.3 - http://www.jdom.org)
* JDOM (org.jdom:jdom2:2.0.6 - 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)
* 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)
* MortBay :: Apache EL :: API and Implementation (org.mortbay.jasper:apache-el:8.5.35.1 - https://github.com/jetty-project/jasper-jsp/apache-el)
* MortBay :: Apache Jasper :: JSP Implementation (org.mortbay.jasper:apache-jsp:8.5.35.1 - https://github.com/jetty-project/jasper-jsp/apache-jsp)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty) * 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 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) * 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) * Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api)
* Objenesis (org.objenesis:objenesis:3.2 - http://objenesis.org/objenesis) * Noggit (org.noggit:noggit:0.5 - http://noggit.org)
* parboiled-core (org.parboiled:parboiled-core:1.3.1 - http://parboiled.org) * Objenesis (org.objenesis:objenesis:2.1 - http://objenesis.org)
* parboiled-java (org.parboiled:parboiled-java:1.3.1 - http://parboiled.org) * parboiled-core (org.parboiled:parboiled-core:1.1.6 - http://parboiled.org)
* quartz (org.quartz-scheduler:quartz:2.3.2 - http://www.quartz-scheduler.org/quartz) * parboiled-java (org.parboiled:parboiled-java:1.1.6 - http://parboiled.org)
* org.restlet (org.restlet.jee:org.restlet:2.1.1 - no url defined)
* org.restlet.ext.servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - no url defined)
* rome-modules (org.rometools:rome-modules:1.0 - http://www.rometools.org) * rome-modules (org.rometools:rome-modules:1.0 - http://www.rometools.org)
* RRD4J (org.rrd4j:rrd4j:3.5 - https://github.com/rrd4j/rrd4j/) * Spring AOP (org.springframework:spring-aop:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* JSONassert (org.skyscreamer:jsonassert:1.5.0 - https://github.com/skyscreamer/JSONassert) * Spring AOP (org.springframework:spring-aop:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring AOP (org.springframework:spring-aop:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Beans (org.springframework:spring-beans:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Beans (org.springframework:spring-beans:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Beans (org.springframework:spring-beans:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Context (org.springframework:spring-context:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Context (org.springframework:spring-context:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Context Support (org.springframework:spring-context-support:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Context (org.springframework:spring-context:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Core (org.springframework:spring-core:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Context Support (org.springframework:spring-context-support:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Expression Language (SpEL) (org.springframework:spring-expression:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Core (org.springframework:spring-core:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Commons Logging Bridge (org.springframework:spring-jcl:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Core (org.springframework:spring-core:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring JDBC (org.springframework:spring-jdbc:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Object/Relational Mapping (org.springframework:spring-orm:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring TestContext Framework (org.springframework:spring-test:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring JDBC (org.springframework:spring-jdbc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Transaction (org.springframework:spring-tx:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring JDBC (org.springframework:spring-jdbc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Web (org.springframework:spring-web:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Web MVC (org.springframework:spring-webmvc:5.2.5.RELEASE - https://github.com/spring-projects/spring-framework) * Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot (org.springframework.boot:spring-boot:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot) * Spring TestContext Framework (org.springframework:spring-test:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot AutoConfigure (org.springframework.boot:spring-boot-autoconfigure:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-autoconfigure) * Spring Transaction (org.springframework:spring-tx:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* 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 Transaction (org.springframework:spring-tx:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot Starter (org.springframework.boot:spring-boot-starter:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter) * Spring Web (org.springframework:spring-web:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot AOP Starter (org.springframework.boot:spring-boot-starter-aop:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-aop) * Spring Web (org.springframework:spring-web:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot Cache Starter (org.springframework.boot:spring-boot-starter-cache:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-cache) * Spring Web MVC (org.springframework:spring-webmvc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot Data REST Starter (org.springframework.boot:spring-boot-starter-data-rest:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-data-rest) * Spring Web MVC (org.springframework:spring-webmvc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
* Spring Boot Json Starter (org.springframework.boot:spring-boot-starter-json:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-json) * spring-security-config (org.springframework.security:spring-security-config:3.2.9.RELEASE - http://spring.io/spring-security)
* Spring Boot Log4j 2 Starter (org.springframework.boot:spring-boot-starter-log4j2:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-log4j2) * spring-security-core (org.springframework.security:spring-security-core:3.2.9.RELEASE - http://spring.io/spring-security)
* Spring Boot Security Starter (org.springframework.boot:spring-boot-starter-security:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-security) * spring-security-web (org.springframework.security:spring-security-web:3.2.9.RELEASE - http://spring.io/spring-security)
* Spring Boot Test Starter (org.springframework.boot:spring-boot-starter-test:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-test) * SWORD Java API, GUI and CLI (org.swordapp:sword-common:1.1 - http://nexus.sonatype.org/oss-repository-hosting.html/sword-common)
* Spring Boot Tomcat Starter (org.springframework.boot:spring-boot-starter-tomcat:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-tomcat)
* Spring Boot Validation Starter (org.springframework.boot:spring-boot-starter-validation:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-validation)
* Spring Boot Web Starter (org.springframework.boot:spring-boot-starter-web:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-starters/spring-boot-starter-web)
* Spring Boot Test (org.springframework.boot:spring-boot-test:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-test)
* Spring Boot Test Auto-Configure (org.springframework.boot:spring-boot-test-autoconfigure:2.2.6.RELEASE - https://projects.spring.io/spring-boot/#/spring-boot-parent/spring-boot-test-autoconfigure)
* Spring Data Core (org.springframework.data:spring-data-commons:2.2.6.RELEASE - https://www.spring.io/spring-data/spring-data-commons)
* Spring Data REST - Core (org.springframework.data:spring-data-rest-core:3.2.6.RELEASE - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-core)
* Spring Data REST - HAL Browser (org.springframework.data:spring-data-rest-hal-browser:3.2.6.RELEASE - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-hal-browser)
* Spring Data REST - WebMVC (org.springframework.data:spring-data-rest-webmvc:3.2.6.RELEASE - https://www.spring.io/spring-data/spring-data-rest-parent/spring-data-rest-webmvc)
* Spring HATEOAS (org.springframework.hateoas:spring-hateoas:1.0.4.RELEASE - https://github.com/spring-projects/spring-hateoas)
* Spring Plugin - Core (org.springframework.plugin:spring-plugin-core:2.0.0.RELEASE - https://github.com/spring-projects/spring-plugin/spring-plugin-core)
* spring-security-config (org.springframework.security:spring-security-config:5.2.2.RELEASE - http://spring.io/spring-security)
* spring-security-core (org.springframework.security:spring-security-core:5.2.2.RELEASE - http://spring.io/spring-security)
* spring-security-test (org.springframework.security:spring-security-test:5.2.2.RELEASE - http://spring.io/spring-security)
* spring-security-web (org.springframework.security:spring-security-web:5.2.2.RELEASE - http://spring.io/spring-security)
* SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/) * SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/)
* ISO Parser (org.tallison:isoparser:1.9.41.2 - https://github.com/tballison/mp4parser)
* org.tallison:metadata-extractor (org.tallison:metadata-extractor:2.13.0 - https://drewnoakes.com/code/exif/)
* XMPCore Shaded (org.tallison.xmp:xmpcore-shaded:6.1.10 - https://github.com/tballison)
* snappy-java (org.xerial.snappy:snappy-java:1.1.7.6 - https://github.com/xerial/snappy-java)
* xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/) * xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/)
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.6.4 - https://www.xmlunit.org/) * oro (oro:oro:2.0.8 - no url defined)
* org.xmlunit:xmlunit-core (org.xmlunit:xmlunit-core:2.8.0 - https://www.xmlunit.org/) * JUnitParams (pl.pragmatists:JUnitParams:1.0.2 - http://junitparams.googlecode.com)
* org.xmlunit:xmlunit-placeholders (org.xmlunit:xmlunit-placeholders:2.8.0 - https://www.xmlunit.org/xmlunit-placeholders/) * Rome A9 OpenSearch (rome:opensearch:0.1 - http://wiki.java.net/bin/view/Javawsxml/OpenSearch)
* SnakeYAML (org.yaml:snakeyaml:1.25 - http://www.snakeyaml.org)
* SnakeYAML (org.yaml:snakeyaml:1.26 - http://www.snakeyaml.org)
* ROME, RSS and atOM utilitiEs for Java (rome:rome:1.0 - https://rome.dev.java.net/) * ROME, RSS and atOM utilitiEs for Java (rome:rome:1.0 - https://rome.dev.java.net/)
* software.amazon.ion:ion-java (software.amazon.ion:ion-java:1.0.2 - https://github.com/amznlabs/ion-java/) * oai4j (se.kb:oai4j:0.6b1 - http://oai4j-client.sourceforge.net/)
* xalan (xalan:xalan:2.7.0 - no url defined) * StAX API (stax:stax-api:1.0.1 - http://stax.codehaus.org/)
* Xerces2-j (xerces:xercesImpl:2.12.0 - https://xerces.apache.org/xerces2-j/) * standard (taglibs:standard:1.1.2 - no url defined)
* Xalan Java Serializer (xalan:serializer:2.7.2 - http://xml.apache.org/xalan-j/)
* Xalan Java (xalan:xalan:2.7.2 - http://xml.apache.org/xalan-j/)
* Xerces2-j (xerces:xercesImpl:2.11.0 - https://xerces.apache.org/xerces2-j/)
* xmlParserAPIs (xerces:xmlParserAPIs:2.6.2 - no url defined)
* XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/) * XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/)
* XML Commons Resolver Component (xml-resolver:xml-resolver:1.2 - http://xml.apache.org/commons/components/resolver/)
BSD License: BSD License:
* AntLR Parser Generator (antlr:antlr:2.7.7 - http://www.antlr.org/) * AntLR Parser Generator (antlr:antlr:2.7.7 - http://www.antlr.org/)
* ASM Core (asm:asm:3.3.1 - http://asm.objectweb.org/asm/)
* XMP Library for Java (com.adobe.xmp:xmpcore:5.1.2 - http://www.adobe.com/devnet/xmp.html)
* coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security) * coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security)
* Java Advanced Imaging Image I/O Tools API core (standalone) (com.github.jai-imageio:jai-imageio-core:1.4.0 - https://github.com/jai-imageio/jai-imageio-core)
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/) * JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
* curvesapi (com.github.virtuald:curvesapi:1.06 - https://github.com/virtuald/curvesapi) * Protocol Buffer Java API (com.google.protobuf:protobuf-java:2.5.0 - http://code.google.com/p/protobuf)
* Protocol Buffers [Core] (com.google.protobuf:protobuf-java:3.11.0 - https://developers.google.com/protocol-buffers/protobuf-java/) * Jena IRI (com.hp.hpl.jena:iri:0.8 - http://jena.sf.net/iri)
* JZlib (com.jcraft:jzlib:1.1.3 - http://www.jcraft.com/jzlib/) * Jena (com.hp.hpl.jena:jena:2.6.4 - http://www.openjena.org/)
* yui compressor (com.yahoo.platform.yui:yuicompressor:2.3.6 - http://developer.yahoo.com/yui/compressor/)
* dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org) * dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org)
* Units of Measurement API (javax.measure:unit-api:1.0 - http://unitsofmeasurement.github.io/) * dom4j (dom4j:dom4j:1.6.1 - http://dom4j.org)
* Biblio Transformation Engine :: Core (gr.ekt.bte:bte-core:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-core)
* Biblio Transformation Engine :: Input/Output (gr.ekt.bte:bte-io:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-io)
* jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/) * jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/)
* JLine (jline:jline:0.9.94 - http://jline.sourceforge.net) * JLine (jline:jline:0.9.94 - http://jline.sourceforge.net)
* ANTLR 4 Runtime (org.antlr:antlr4-runtime:4.5.1-1 - http://www.antlr.org/antlr4-runtime) * ANTLR 3 Runtime (org.antlr:antlr-runtime:3.5 - http://www.antlr.org)
* commons-compiler (org.codehaus.janino:commons-compiler:3.0.9 - http://janino-compiler.github.io/commons-compiler/) * Morfologik FSA (org.carrot2:morfologik-fsa:1.7.1 - http://morfologik.blogspot.com/morfologik-fsa/)
* janino (org.codehaus.janino:janino:3.0.9 - http://janino-compiler.github.io/janino/) * Morfologik Stemming Dictionary for Polish (org.carrot2:morfologik-polish:1.7.1 - http://morfologik.blogspot.com/morfologik-polish/)
* Stax2 API (org.codehaus.woodstox:stax2-api:3.1.4 - http://wiki.fasterxml.com/WoodstoxStax2) * Morfologik Stemming APIs (org.carrot2:morfologik-stemming:1.7.1 - http://morfologik.blogspot.com/morfologik-stemming/)
* dom4j (org.dom4j:dom4j:2.1.1 - http://dom4j.github.io/) * Stax2 API (org.codehaus.woodstox:stax2-api:3.1.1 - http://woodstox.codehaus.org/StAX2)
* Hamcrest Date (org.exparity:hamcrest-date:2.0.7 - https://github.com/exparity/hamcrest-date) * DSpace Kernel :: API and Implementation (org.dspace:dspace-api:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-api)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * DSpace I18N :: Language Packs (org.dspace:dspace-api-lang:6.0.3 - https://github.com/dspace/dspace-api-lang)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * DSpace JSP-UI (org.dspace:dspace-jspui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-jspui)
* Hamcrest (org.hamcrest:hamcrest:2.1 - http://hamcrest.org/JavaHamcrest/) * DSpace OAI-PMH (org.dspace:dspace-oai:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-oai)
* DSpace RDF (org.dspace:dspace-rdf:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-rdf)
* DSpace REST :: API and Implementation (org.dspace:dspace-rest:6.0-rc4-SNAPSHOT - http://demo.dspace.org)
* DSpace Services Framework :: API and Implementation (org.dspace:dspace-services:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-services)
* Apache Solr Webapp (org.dspace:dspace-solr:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-solr)
* DSpace SWORD (org.dspace:dspace-sword:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-sword)
* DSpace SWORD v2 (org.dspace:dspace-swordv2:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-swordv2)
* DSpace XML-UI (Manakin) (org.dspace:dspace-xmlui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-xmlui)
* DSpace XML-UI (Manakin) I18N :: Language Packs (org.dspace:dspace-xmlui-lang:6.0.3 - https://github.com/dspace/dspace-xmlui-lang)
* handle (org.dspace:handle:6.2 - no url defined)
* jargon (org.dspace:jargon:1.4.25 - no url defined)
* mets (org.dspace:mets:1.5.2 - no url defined)
* oclc-harvester2 (org.dspace:oclc-harvester2:0.1.12 - no url defined)
* XOAI : OAI-PMH Java Toolkit (org.dspace:xoai:3.2.10 - http://nexus.sonatype.org/oss-repository-hosting.html/xoai)
* Repackaged Cocoon Servlet Service Implementation (org.dspace.dependencies.cocoon:dspace-cocoon-servlet-service-impl:1.0.3 - http://projects.dspace.org/dspace-pom/dspace-cocoon-servlet-service-impl)
* DSpace Kernel :: Additions and Local Customizations (org.dspace.modules:additions:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/modules/additions)
* Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all) * Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
* Hamcrest Core (org.hamcrest:hamcrest-core:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-core) * Hamcrest Core (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
* Hamcrest library (org.hamcrest:hamcrest-library:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-library)
* JBibTeX (org.jbibtex:jbibtex:1.0.10 - http://www.jbibtex.org) * JBibTeX (org.jbibtex:jbibtex:1.0.10 - http://www.jbibtex.org)
* asm (org.ow2.asm:asm:8.0.1 - http://asm.ow2.io/) * ASM Core (org.ow2.asm:asm:4.1 - http://asm.objectweb.org/asm/)
* asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/) * ASM Analysis (org.ow2.asm:asm-analysis:4.1 - http://asm.objectweb.org/asm-analysis/)
* asm-commons (org.ow2.asm:asm-commons:8.0.1 - http://asm.ow2.io/) * ASM Commons (org.ow2.asm:asm-commons:4.1 - http://asm.objectweb.org/asm-commons/)
* asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/) * ASM Tree (org.ow2.asm:asm-tree:4.1 - http://asm.objectweb.org/asm-tree/)
* asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/) * ASM Util (org.ow2.asm:asm-util:4.1 - http://asm.objectweb.org/asm-util/)
* PostgreSQL JDBC Driver (org.postgresql:postgresql:42.2.25 - https://jdbc.postgresql.org) * XMLUnit for Java (xmlunit:xmlunit:1.1 - http://xmlunit.sourceforge.net/)
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections)
* JMatIO (org.tallison:jmatio:1.5 - https://github.com/tballison/jmatio)
* XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/) * XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/)
Common Development and Distribution License (CDDL): Common Development and Distribution License (CDDL):
* JavaBeans Activation Framework (com.sun.activation:javax.activation:1.2.0 - http://java.net/all/javax.activation/) * JAXB Reference Implementation (com.sun.xml.bind:jaxb-impl:2.2.5 - http://jaxb.java.net/)
* istack common utility code runtime (com.sun.istack:istack-commons-runtime:3.0.7 - http://java.net/istack-commons/istack-commons-runtime/) * JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
* JavaMail API (com.sun.mail:javax.mail:1.6.2 - http://javaee.github.io/javamail/javax.mail) * JavaBeans(TM) Activation Framework (javax.activation:activation:1.1.1 - http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
* JavaMail API (no providers) (com.sun.mail:mailapi:1.6.2 - http://javaee.github.io/javamail/mailapi) * javax.annotation API (javax.annotation:javax.annotation-api:1.2 - http://jcp.org/en/jsr/detail?id=250)
* Old JAXB Core (com.sun.xml.bind:jaxb-core:2.3.0.1 - http://jaxb.java.net/jaxb-bundles/jaxb-core) * JavaMail API (compat) (javax.mail:mail:1.4.7 - http://kenai.com/projects/javamail/mail)
* Old JAXB Runtime (com.sun.xml.bind:jaxb-impl:2.3.1 - http://jaxb.java.net/jaxb-bundles/jaxb-impl)
* saaj-impl (com.sun.xml.messaging.saaj:saaj-impl:1.4.0-b03 - http://java.net/saaj-impl/)
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca)
* jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api)
* JavaBeans Activation Framework (JAF) (javax.activation:activation:1.1 - http://java.sun.com/products/javabeans/jaf/index.jsp)
* JavaBeans Activation Framework API jar (javax.activation:javax.activation-api:1.2.0 - http://java.net/all/javax.activation-api/)
* javax.annotation API (javax.annotation:javax.annotation-api:1.3.2 - http://jcp.org/en/jsr/detail?id=250)
* Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net) * Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
* javax.transaction API (javax.transaction:javax.transaction-api:1.3 - http://jta-spec.java.net) * jsp-api (javax.servlet:jsp-api:2.0 - no url defined)
* jaxb-api (javax.xml.bind:jaxb-api:2.3.1 - https://github.com/javaee/jaxb-spec/jaxb-api) * jstl (javax.servlet:jstl:1.2 - no url defined)
* JAX-WS API (javax.xml.ws:jaxws-api:2.3.1 - https://github.com/javaee/jax-ws-spec) * servlet-api (javax.servlet:servlet-api:2.5 - no url defined)
* JHighlight (org.codelibs:jhighlight:1.0.3 - https://github.com/codelibs/jhighlight) * javax.ws.rs-api (javax.ws.rs:javax.ws.rs-api:2.0.1 - http://jax-rs-spec.java.net)
* HK2 API module (org.glassfish.hk2:hk2-api:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api) * Class Model for Hk2 (org.glassfish.hk2:class-model:2.4.0-b31 - https://hk2.java.net/class-model)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator) * HK2 config types (org.glassfish.hk2:config-types:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/config-types)
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-utils) * HK2 module of HK2 itself (org.glassfish.hk2:hk2:2.4.0-b31 - https://hk2.java.net/hk2)
* OSGi resource locator (org.glassfish.hk2:osgi-resource-locator:1.0.3 - https://projects.eclipse.org/projects/ee4j/osgi-resource-locator) * HK2 API module (org.glassfish.hk2:hk2-api:2.4.0-b31 - https://hk2.java.net/hk2-api)
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged) * HK2 configuration module (org.glassfish.hk2:hk2-config:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/hk2-config)
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject) * HK2 core module (org.glassfish.hk2:hk2-core:2.4.0-b31 - https://hk2.java.net/hk2-core)
* JAXB Runtime (org.glassfish.jaxb:jaxb-runtime:2.3.1 - http://jaxb.java.net/jaxb-runtime-parent/jaxb-runtime) * ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.4.0-b31 - https://hk2.java.net/hk2-locator)
* TXW2 Runtime (org.glassfish.jaxb:txw2:2.3.1 - http://jaxb.java.net/jaxb-txw-parent/txw2) * Run Level Service (org.glassfish.hk2:hk2-runlevel:2.4.0-b31 - https://hk2.java.net/hk2-runlevel)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:2.4.0-b31 - https://hk2.java.net/hk2-utils)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * OSGi resource locator bundle - used by various API providers that rely on META-INF/services mechanism to locate providers. (org.glassfish.hk2:osgi-resource-locator:1.0.1 - http://glassfish.org/osgi-resource-locator/)
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final - http://www.jboss.org/jboss-transaction-api_1.2_spec) * HK2 Spring Bridge (org.glassfish.hk2:spring-bridge:2.4.0-b31 - https://hk2.java.net/spring-bridge)
* MIME streaming extension (org.jvnet.mimepull:mimepull:1.9.7 - http://mimepull.java.net) * aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.4.0-b31 - https://hk2.java.net/external/aopalliance-repackaged)
* Extended StAX API (org.jvnet.staxex:stax-ex:1.8 - http://stax-ex.java.net/) * ASM library repackaged as OSGi bundle (org.glassfish.hk2.external:asm-all-repackaged:2.4.0-b31 - https://hk2.java.net/external/asm-all-repackaged)
* javax.validation:1.1.0.Final as OSGi bundle (org.glassfish.hk2.external:bean-validator:2.4.0-b31 - https://hk2.java.net/external/bean-validator)
Cordra (Version 2) License Agreement: * javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:javax.inject:2.4.0-b31 - https://hk2.java.net/external/javax.inject)
* jersey-repackaged-guava (org.glassfish.jersey.bundles.repackaged:jersey-guava:2.22.1 - https://jersey.java.net/project/project/jersey-guava/)
* net.cnri:cnri-servlet-container (net.cnri:cnri-servlet-container:3.0.0 - https://gitlab.com/cnri/cnri-servlet-container) * jersey-container-servlet (org.glassfish.jersey.containers:jersey-container-servlet:2.22.1 - https://jersey.java.net/project/jersey-container-servlet/)
* net.cnri:cnri-servlet-container-lib (net.cnri:cnri-servlet-container-lib:3.0.0 - https://gitlab.com/cnri/cnri-servlet-container) * jersey-container-servlet-core (org.glassfish.jersey.containers:jersey-container-servlet-core:2.22.1 - https://jersey.java.net/project/jersey-container-servlet-core/)
* net.cnri:cnriutil (net.cnri:cnriutil:2.0 - https://gitlab.com/cnri/cnriutil) * jersey-core-client (org.glassfish.jersey.core:jersey-client:2.22.1 - https://jersey.java.net/jersey-client/)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.22.1 - https://jersey.java.net/jersey-common/)
Eclipse Distribution License, Version 1.0: * jersey-core-server (org.glassfish.jersey.core:jersey-server:2.22.1 - https://jersey.java.net/jersey-server/)
* jersey-ext-entity-filtering (org.glassfish.jersey.ext:jersey-entity-filtering:2.22.1 - https://jersey.java.net/project/jersey-entity-filtering/)
* JavaBeans Activation Framework (com.sun.activation:jakarta.activation:1.2.1 - https://github.com/eclipse-ee4j/jaf/jakarta.activation) * jersey-spring3 (org.glassfish.jersey.ext:jersey-spring3:2.22.1 - https://jersey.java.net/project/jersey-spring3/)
* JavaBeans Activation Framework API jar (jakarta.activation:jakarta.activation-api:1.2.1 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) * jersey-media-jaxb (org.glassfish.jersey.media:jersey-media-jaxb:2.22.1 - https://jersey.java.net/project/jersey-media-jaxb/)
* Jakarta Activation API jar (jakarta.activation:jakarta.activation-api:1.2.2 - https://github.com/eclipse-ee4j/jaf/jakarta.activation-api) * jersey-media-json-jackson (org.glassfish.jersey.media:jersey-media-json-jackson:2.22.1 - https://jersey.java.net/project/jersey-media-json-jackson/)
* jakarta.xml.bind-api (jakarta.xml.bind:jakarta.xml.bind-api:2.3.2 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) * Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
* Jakarta XML Binding API (jakarta.xml.bind:jakarta.xml.bind-api:2.3.3 - https://github.com/eclipse-ee4j/jaxb-api/jakarta.xml.bind-api) * Type arithmetic library for Java5 (org.jvnet:tiger-types:1.4 - http://java.net/tiger-types/)
* javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final - http://hibernate.org)
Eclipse Public License: Eclipse Public License:
* System Rules (com.github.stefanbirkner:system-rules:1.19.0 - http://stefanbirkner.github.io/system-rules/) * JUnit (junit:junit:4.11 - http://junit.org)
* c3p0 (com.mchange:c3p0:0.9.5.5 - https://github.com/swaldman/c3p0) * AspectJ runtime (org.aspectj:aspectjrt:1.6.11 - http://www.aspectj.org)
* mchange-commons-java (com.mchange:mchange-commons-java:0.2.19 - https://github.com/swaldman/mchange-commons-java) * JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
* Jakarta Annotations API (jakarta.annotation:jakarta.annotation-api:1.3.5 - https://projects.eclipse.org/projects/ee4j.ca)
* jakarta.ws.rs-api (jakarta.ws.rs:jakarta.ws.rs-api:2.1.6 - https://github.com/eclipse-ee4j/jaxrs-api)
* javax.persistence-api (javax.persistence:javax.persistence-api:2.2 - https://github.com/javaee/jpa-spec)
* JUnit (junit:junit:4.13.1 - http://junit.org)
* AspectJ runtime (org.aspectj:aspectjrt:1.8.0 - http://www.aspectj.org)
* AspectJ weaver (org.aspectj:aspectjweaver:1.9.5 - http://www.aspectj.org)
* Eclipse Compiler for Java(TM) (org.eclipse.jdt:ecj:3.14.0 - http://www.eclipse.org/jdt)
* Jetty :: Apache JSP Implementation (org.eclipse.jetty:apache-jsp:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Apache :: JSTL module (org.eclipse.jetty:apache-jstl:9.4.15.v20190215 - http://tomcat.apache.org/taglibs/standard/)
* Jetty :: ALPN :: Client (org.eclipse.jetty:jetty-alpn-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-client)
* Jetty :: ALPN :: JDK9 Client Implementation (org.eclipse.jetty:jetty-alpn-java-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-client)
* Jetty :: ALPN :: JDK9 Server Implementation (org.eclipse.jetty:jetty-alpn-java-server:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-java-server)
* Jetty :: ALPN :: Server (org.eclipse.jetty:jetty-alpn-server:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-alpn-parent/jetty-alpn-server)
* Jetty :: Servlet Annotations (org.eclipse.jetty:jetty-annotations:9.4.15.v20190215 - http://www.eclipse.org/jetty)
* Jetty :: Asynchronous HTTP Client (org.eclipse.jetty:jetty-client:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-client)
* Jetty :: Continuation (org.eclipse.jetty:jetty-continuation:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-continuation)
* Jetty :: Deployers (org.eclipse.jetty:jetty-deploy:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-deploy)
* Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-http)
* Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-io)
* Jetty :: JMX Management (org.eclipse.jetty:jetty-jmx:9.4.34.v20201102 - 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.34.v20201102 - https://eclipse.org/jetty/jetty-rewrite)
* Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-security)
* Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-server)
* Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-servlet)
* Jetty :: Utility Servlets and Filters (org.eclipse.jetty:jetty-servlets:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-servlets)
* Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.41.v20210516 - https://eclipse.org/jetty/jetty-util)
* Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-webapp)
* Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.34.v20201102 - https://eclipse.org/jetty/jetty-xml)
* Jetty :: HTTP2 :: Client (org.eclipse.jetty.http2:http2-client:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-client)
* Jetty :: HTTP2 :: Common (org.eclipse.jetty.http2:http2-common:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-common)
* Jetty :: HTTP2 :: HPACK (org.eclipse.jetty.http2:http2-hpack:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-hpack)
* Jetty :: HTTP2 :: HTTP Client Transport (org.eclipse.jetty.http2:http2-http-client-transport:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-http-client-transport)
* Jetty :: HTTP2 :: Server (org.eclipse.jetty.http2:http2-server:9.4.34.v20201102 - https://eclipse.org/jetty/http2-parent/http2-server)
* Jetty :: Schemas (org.eclipse.jetty.toolchain:jetty-schemas:3.1.2 - https://eclipse.org/jetty/jetty-schemas)
* HK2 API module (org.glassfish.hk2:hk2-api:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-api)
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/hk2-locator)
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:2.6.1 - 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:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/aopalliance-repackaged)
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:jakarta.inject:2.6.1 - https://github.com/eclipse-ee4j/glassfish-hk2/external/jakarta.inject)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Java Persistence API, Version 2.1 (org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final - http://hibernate.org)
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty) * 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 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) * Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
GNU General Public License, Version 2 with the Classpath Exception:
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
GNU Lesser General Public License (LGPL): GNU Lesser General Public License (LGPL):
* 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-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)
* SpotBugs Annotations (com.github.spotbugs:spotbugs-annotations:3.1.9 - https://spotbugs.github.io/)
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/) * FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/)
* c3p0 (com.mchange:c3p0:0.9.5.5 - https://github.com/swaldman/c3p0) * MaxMind GeoIP Legacy API (com.maxmind.geoip:geoip-api:1.3.0 - https://github.com/maxmind/geoip-api-java)
* mchange-commons-java (com.mchange:mchange-commons-java:0.2.19 - https://github.com/swaldman/mchange-commons-java) * JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
* Java Native Access (net.java.dev.jna:jna:5.5.0 - https://github.com/java-native-access/jna) * DSpace TM-Extractors Dependency (org.dspace.dependencies:dspace-tm-extractors:1.0.1 - http://projects.dspace.org/dspace-pom/dspace-tm-extractors)
* JHighlight (org.codelibs:jhighlight:1.0.3 - https://github.com/codelibs/jhighlight) * A Hibernate O/RM Module (org.hibernate:hibernate-core:4.2.21.Final - http://hibernate.org)
* Hibernate ORM - hibernate-core (org.hibernate:hibernate-core:5.4.10.Final - http://hibernate.org/orm) * A Hibernate O/RM Module (org.hibernate:hibernate-ehcache:4.2.21.Final - http://hibernate.org)
* Hibernate ORM - hibernate-ehcache (org.hibernate:hibernate-ehcache:5.4.10.Final - http://hibernate.org/orm) * Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:4.0.2.Final - http://hibernate.org)
* Hibernate ORM - hibernate-jpamodelgen (org.hibernate:hibernate-jpamodelgen:5.4.10.Final - http://hibernate.org/orm)
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:5.1.0.Final - http://hibernate.org)
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/) * im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
* JacORB OMG-API (org.jacorb:jacorb-omgapi:3.9 - http://www.jacorb.org) * Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/) * JBoss Logging 3 (org.jboss.logging:jboss-logging:3.1.0.GA - http://www.jboss.org)
* Java RMI API (org.jboss.spec.javax.rmi:jboss-rmi-api_1.0_spec:1.0.6.Final - http://www.jboss.org/jboss-rmi-api_1.0_spec) * org.jdesktop - Swing Worker (org.jdesktop:swing-worker:1.1 - no url defined)
* xom (xom:xom:1.1 - http://www.xom.nu)
* XOM (xom:xom:1.2.5 - http://xom.nu) * XOM (xom:xom:1.2.5 - http://xom.nu)
Go License: ICU License:
* RE2/J (com.google.re2j:re2j:1.2 - http://github.com/google/re2j) * ICU4J (com.ibm.icu:icu4j:56.1 - http://icu-project.org/)
Handle.Net Public License Agreement (Ver.2):
* Handle Server (net.handle:handle:9.3.0 - https://www.handle.net)
JDOM License (Apache-style license): JDOM License (Apache-style license):
@@ -582,72 +387,38 @@ https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines
MIT License: MIT License:
* Java SemVer (com.github.zafarkhaja:java-semver:0.9.0 - https://github.com/zafarkhaja/jsemver) * Bouncy Castle CMS and S/MIME API (org.bouncycastle:bcmail-jdk15:1.46 - http://www.bouncycastle.org/java.html)
* DigitalCollections: IIIF API Library (de.digitalcollections.iiif:iiif-apis:0.3.9 - https://github.com/dbmdz/iiif-apis) * Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15:1.46 - http://www.bouncycastle.org/java.html)
* CDM core library (edu.ucar:cdm:4.5.5 - http://www.unidata.ucar.edu/software/netcdf-java/documentation.htm) * Main (org.jmockit:jmockit:1.21 - http://www.jmockit.org)
* GRIB IOSP and Feature Collection (edu.ucar:grib:4.5.5 - http://www.unidata.ucar.edu/software/netcdf-java/) * OpenCloud (org.mcavallo:opencloud:0.3 - http://opencloud.mcavallo.org/)
* HttpClient Wrappers (edu.ucar:httpservices:4.5.5 - http://www.unidata.ucar.edu/software/netcdf-java/documentation.htm) * Mockito (org.mockito:mockito-core:1.10.19 - http://www.mockito.org)
* netCDF-4 IOSP JNI connection to C library (edu.ucar:netcdf4:4.5.5 - http://www.unidata.ucar.edu/software/netcdf-java/netcdf4/) * JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.14 - http://www.slf4j.org)
* udunits (edu.ucar:udunits:4.5.5 - http://www.unidata.ucar.edu/software/udunits//) * JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.14 - http://www.slf4j.org)
* JOpt Simple (net.sf.jopt-simple:jopt-simple:5.0.4 - http://jopt-simple.github.io/jopt-simple) * SLF4J API Module (org.slf4j:slf4j-api:1.7.14 - http://www.slf4j.org)
* Bouncy Castle S/MIME API (org.bouncycastle:bcmail-jdk15on:1.65 - http://www.bouncycastle.org/java.html) * SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.14 - http://www.slf4j.org)
* Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (org.bouncycastle:bcpkix-jdk15on:1.65 - http://www.bouncycastle.org/java.html)
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15on:1.65 - http://www.bouncycastle.org/java.html)
* org.brotli:dec (org.brotli:dec:0.1.2 - http://brotli.org/dec)
* Checker Qual (org.checkerframework:checker-qual:3.5.0 - https://checkerframework.org)
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
* Itadaki jbzip2 (org.itadaki:bzip2:0.9.1 - https://code.google.com/p/jbzip2/)
* jsoup Java HTML Parser (org.jsoup:jsoup:1.13.1 - https://jsoup.org/)
* mockito-core (org.mockito:mockito-core:3.12.4 - https://github.com/mockito/mockito)
* mockito-inline (org.mockito:mockito-inline:3.12.4 - https://github.com/mockito/mockito)
* ORCID - Model (org.orcid:orcid-model:3.0.2 - http://github.com/ORCID/orcid-model)
* JCL 1.2 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.25 - http://www.slf4j.org)
* JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.25 - http://www.slf4j.org)
* SLF4J API Module (org.slf4j:slf4j-api:1.7.25 - http://www.slf4j.org)
* SLF4J Extensions Module (org.slf4j:slf4j-ext:1.7.28 - http://www.slf4j.org)
* toastr (org.webjars.bowergithub.codeseven:toastr:2.1.4 - http://webjars.org)
* jquery (org.webjars.bowergithub.jquery:jquery-dist:3.5.1 - https://www.webjars.org)
* bootstrap (org.webjars.bowergithub.twbs:bootstrap:4.5.2 - https://www.webjars.org)
Mozilla Public License: Mozilla Public License:
* juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/) * juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/)
* h2 (com.h2database:h2:1.4.187 - no url defined) * h2 (com.h2database:h2:1.4.187 - no url defined)
* Saxon-HE (net.sf.saxon:Saxon-HE:9.8.0-14 - http://www.saxonica.com/) * Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
* Javassist (org.javassist:javassist:3.25.0-GA - http://www.javassist.org/) * Rhino (rhino:js:1.6R7 - http://www.mozilla.org/rhino/)
* Mozilla Rhino (org.mozilla:rhino:1.7.7.2 - https://developer.mozilla.org/en/Rhino)
OGC copyright:
* GeoAPI (org.opengis:geoapi:3.0.1 - http://www.geoapi.org/geoapi/)
Public Domain: Public Domain:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client) * AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-common) * Dough Lea's util.concurrent package (concurrent:concurrent:1.3.4 - no url defined)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2) * Reflections (org.reflections:reflections:0.9.9-RC1 - http://code.google.com/p/reflections/reflections/)
* Reflections (org.reflections:reflections:0.9.12 - http://github.com/ronmamo/reflections) * XZ for Java (org.tukaani:xz:1.4 - http://tukaani.org/xz/java.html)
* XZ for Java (org.tukaani:xz:1.8 - https://tukaani.org/xz/java.html)
The JSON License: Similar to Apache License but with the acknowledgment clause removed:
* JSON in Java (org.json:json:20180130 - https://github.com/douglascrockford/JSON-java) * JDOM (org.jdom:jdom:1.1.3 - http://www.jdom.org)
UnRar License: The PostgreSQL License:
* Java UnRar (com.github.junrar:junrar:4.0.0 - https://github.com/junrar/junrar) * PostgreSQL JDBC Driver - JDBC 4.2 (org.postgresql:postgresql:9.4.1211 - https://github.com/pgjdbc/pgjdbc)
Unicode/ICU License: license.txt:
* ICU4J (com.ibm.icu:icu4j:62.1 - http://icu-project.org/) * JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
W3C license:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)
jQuery license:
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/jersey-client)
* jersey-inject-hk2 (org.glassfish.jersey.inject:jersey-hk2:2.30.1 - https://projects.eclipse.org/projects/ee4j.jersey/project/jersey-hk2)

19
NOTICE
View File

@@ -1,24 +1,11 @@
Licenses of Third-Party Libraries
=================================
DSpace uses third-party libraries which may be distributed under Licensing Notice
different licenses than specified in our LICENSE file. Information
about these licenses is detailed in the LICENSES_THIRD_PARTY file at
the root of the source tree. You must agree to the terms of these
licenses, in addition to the DSpace source code license, in order to
use this software.
Licensing Notices Fedora Commons joined with the DSpace Foundation and began operating under
=================
[July 2019] DuraSpace joined with LYRASIS (another 501(c)3 organization) in July 2019.
LYRASIS holds the copyrights of DuraSpace.
[July 2009] Fedora Commons joined with the DSpace Foundation and began operating under
the new name DuraSpace in July 2009. DuraSpace holds the copyrights of the new name DuraSpace in July 2009. DuraSpace holds the copyrights of
the DSpace Foundation, Inc. the DSpace Foundation, Inc.
[July 2007] The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007 The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007
with a mission to promote and advance the dspace platform enabling management, with a mission to promote and advance the dspace platform enabling management,
access and preservation of digital works. The Foundation was able to transfer access and preservation of digital works. The Foundation was able to transfer
the legal copyright from Hewlett-Packard Company (HP) and Massachusetts the legal copyright from Hewlett-Packard Company (HP) and Massachusetts

114
README.md
View File

@@ -1,65 +1,62 @@
# DSpace # DSpace
[![Build Status](https://github.com/DSpace/DSpace/workflows/Build/badge.svg)](https://github.com/DSpace/DSpace/actions?query=workflow%3ABuild) ## NOTE: The rest-tutorial branch has been created to support the [DSpace 7 REST documentation](https://dspace-labs.github.io/DSpace7RestTutorial/walkthrough/intro)
- This branch provides stable, referencable line numbers in code
[DSpace Documentation](https://wiki.lyrasis.org/display/DSDOC/) | [![Build Status](https://travis-ci.org/DSpace/DSpace.png?branch=master)](https://travis-ci.org/DSpace/DSpace)
[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) |
[DSpace Releases](https://github.com/DSpace/DSpace/releases) | [DSpace Releases](https://github.com/DSpace/DSpace/releases) |
[DSpace Wiki](https://wiki.lyrasis.org/display/DSPACE/Home) | [DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) |
[Support](https://wiki.lyrasis.org/display/DSPACE/Support) [Support](https://wiki.duraspace.org/display/DSPACE/Support)
## Overview
DSpace open source software is a turnkey repository application used by more than DSpace open source software is a turnkey repository application used by more than
2,000 organizations and institutions worldwide to provide durable access to digital resources. 2,000 organizations and institutions worldwide to provide durable access to digital resources.
For more information, visit http://www.dspace.org/ For more information, visit http://www.dspace.org/
DSpace consists of both a Java-based backend and an Angular-based frontend. ***
:warning: **Work on DSpace 7 has begun on our `master` branch.** This means that there is temporarily NO user interface on this `master` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) page. Additionally, the codebases can be found in the following places:
* DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-spring-rest) of this repository.
* The REST Contract is being documented at https://github.com/DSpace/Rest7Contract
* DSpace 7 Angular UI work is occurring at https://github.com/DSpace/dspace-angular
* Backend (this codebase) provides a REST API, along with other machine-based interfaces (e.g. OAI-PMH, SWORD, etc) **If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) wiki page for more info.
* The REST Contract is at https://github.com/DSpace/RestContract
* Frontend (https://github.com/DSpace/dspace-angular/) is the User Interface built on the REST API
Prior versions of DSpace (v6.x and below) used two different UIs (XMLUI and JSPUI). Those UIs are no longer supported in v7 (and above). **If you are looking for the ongoing maintenance work for DSpace 6 (or prior releases)**, you can find that work on the corresponding maintenance branch (e.g. [`dspace-6_x`](https://github.com/DSpace/DSpace/tree/dspace-6_x)) in this repository.
* A maintenance branch for older versions is still available, see `dspace-6_x` for 6.x maintenance. ***
## Downloads ## Downloads
* Backend (REST API): https://github.com/DSpace/DSpace/releases The latest release of DSpace can be downloaded from the [DSpace website](http://www.dspace.org/latest-release/) or from [GitHub](https://github.com/DSpace/DSpace/releases).
* Frontend (User Interface): https://github.com/DSpace/dspace-angular/releases
Past releases are all available via GitHub at https://github.com/DSpace/DSpace/releases
## Documentation / Installation ## Documentation / Installation
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.lyrasis.org/display/DSDOC/). Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/).
The latest DSpace Installation instructions are available at: The latest DSpace Installation instructions are available at:
https://wiki.lyrasis.org/display/DSDOC7x/Installing+DSpace https://wiki.duraspace.org/display/DSDOC6x/Installing+DSpace
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle) Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle)
and a servlet container (usually Tomcat) in order to function. 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. More information about these and all other prerequisites can be found in the Installation instructions above.
## Running DSpace 7 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 7 with Docker Compose](dspace/src/main/docker-compose/README.md)
## Contributing ## Contributing
DSpace is a community built and supported project. We do not have a centralized development or support team, DSpace is a community built and supported project. We do not have a centralized development or support team,
but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc. but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc.
We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace: We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace:
* [How to Contribute to DSpace](https://wiki.lyrasis.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc) * [How to Contribute to DSpace](https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc)
* [Code Contribution Guidelines](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc. * [Code Contribution Guidelines](https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc.
* [DSpace Community Advisory Team (DCAT)](https://wiki.lyrasis.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam). * [DSpace Community Advisory Team (DCAT)](https://wiki.duraspace.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam).
We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.lyrasis.org/display/DSPACE/Development+with+Git) guide for more info. We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.duraspace.org/display/DSPACE/Development+with+Git) guide for more info.
In addition, a listing of all known contributors to DSpace software can be In addition, a listing of all known contributors to DSpace software can be
found online at: https://wiki.lyrasis.org/display/DSPACE/DSpaceContributors found online at: https://wiki.duraspace.org/display/DSPACE/DSpaceContributors
## Getting Help ## Getting Help
@@ -67,12 +64,12 @@ DSpace provides public mailing lists where you can post questions or raise topic
We welcome everyone to participate in these lists: We welcome everyone to participate in these lists:
* [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices * [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices
* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.lyrasis.org/display/DSPACE/Troubleshoot+an+error). * [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.duraspace.org/display/DSPACE/Troubleshoot+an+error).
* [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list * [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list
Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace) Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace)
Additional support options are at https://wiki.lyrasis.org/display/DSPACE/Support Additional support options are listed at https://wiki.duraspace.org/display/DSPACE/Support
DSpace also has an active service provider network. If you'd rather hire a service provider to DSpace also has an active service provider network. If you'd rather hire a service provider to
install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our
@@ -80,62 +77,9 @@ install, upgrade, customize or host DSpace, then we recommend getting in touch w
## Issue Tracker ## Issue Tracker
DSpace uses GitHub to track issues: The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS/summary
* Backend (REST API) issues: https://github.com/DSpace/DSpace/issues
* Frontend (User Interface) issues: https://github.com/DSpace/dspace-angular/issues
## Testing
### Running Tests
By default, in DSpace, Unit Tests and Integration Tests are disabled. However, they are
run automatically by [GitHub Actions](https://github.com/DSpace/DSpace/actions?query=workflow%3ABuild) for all Pull Requests and code commits.
* How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`):
```
mvn install -DskipUnitTests=false -DskipIntegrationTests=false
```
* How to run _only_ Unit Tests:
```
mvn test -DskipUnitTests=false
```
* How to run a *single* Unit Test
```
# Run all tests in a specific test class
# NOTE: failIfNoTests=false is required to skip tests in other modules
mvn test -DskipUnitTests=false -Dtest=[full.package.testClassName] -DfailIfNoTests=false
# Run one test method in a specific test class
mvn test -DskipUnitTests=false -Dtest=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
```
* How to run _only_ Integration Tests
```
mvn install -DskipIntegrationTests=false
```
* How to run a *single* Integration Test
```
# Run all integration tests in a specific test class
# NOTE: failIfNoTests=false is required to skip tests in other modules
mvn install -DskipIntegrationTests=false -Dit.test=[full.package.testClassName] -DfailIfNoTests=false
# Run one test method in a specific test class
mvn install -DskipIntegrationTests=false -Dit.test=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
```
* How to run only tests of a specific DSpace module
```
# Before you can run only one module's tests, other modules may need installing into your ~/.m2
cd [dspace-src]
mvn clean install
# Then, move into a module subdirectory, and run the test command
cd [dspace-src]/dspace-server-webapp
# Choose your test command from the lists above
```
## License ## License
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause). DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
The full license is available in the [LICENSE](LICENSE) file or online at http://www.dspace.org/license/ The full license is available at http://www.dspace.org/license/
DSpace uses third-party libraries which may be distributed under different licenses. Those licenses are listed
in the [LICENSES_THIRD_PARTY](LICENSES_THIRD_PARTY) file.

View File

@@ -1,15 +0,0 @@
# Security Policy
## Supported Versions
For information regarding which versions of DSpace are currently under support, please see our DSpace Software Support Policy:
https://wiki.lyrasis.org/display/DSPACE/DSpace+Software+Support+Policy
## Reporting a Vulnerability
If you believe you have found a security vulnerability in a supported version of DSpace, we encourage you to let us know right away.
We will investigate all legitimate reports and do our best to quickly fix the problem. Please see our DSpace Software Support Policy
for information on privately reporting vulnerabilities:
https://wiki.lyrasis.org/display/DSPACE/DSpace+Software+Support+Policy

View File

@@ -44,16 +44,15 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
with @SuppressWarnings. See also SuppressWarningsHolder below --> with @SuppressWarnings. See also SuppressWarningsHolder below -->
<module name="SuppressWarningsFilter" /> <module name="SuppressWarningsFilter" />
<!-- Check individual Java source files for specific rules -->
<module name="TreeWalker">
<!-- Maximum line length is 120 characters --> <!-- Maximum line length is 120 characters -->
<module name="LineLength"> <module name="LineLength">
<property name="fileExtensions" value="java"/>
<property name="max" value="120"/> <property name="max" value="120"/>
<!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags --> <!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags -->
<property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/> <property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/>
</module> </module>
<!-- Check individual Java source files for specific rules -->
<module name="TreeWalker">
<!-- Highlight any TODO or FIXME comments in info messages --> <!-- Highlight any TODO or FIXME comments in info messages -->
<module name="TodoComment"> <module name="TodoComment">
<property name="severity" value="info"/> <property name="severity" value="info"/>
@@ -95,8 +94,11 @@ For more information on CheckStyle configurations below, see: http://checkstyle.
<!-- <property name="scope" value="public"/> --> <!-- <property name="scope" value="public"/> -->
<!-- TODO: Above rule has been disabled because of large amount of missing public method Javadocs --> <!-- TODO: Above rule has been disabled because of large amount of missing public method Javadocs -->
<property name="scope" value="nothing"/> <property name="scope" value="nothing"/>
<!-- Allow RuntimeExceptions to be undeclared -->
<property name="allowUndeclaredRTE" value="true"/>
<!-- Allow params, throws and return tags to be optional --> <!-- Allow params, throws and return tags to be optional -->
<property name="allowMissingParamTags" value="true"/> <property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/> <property name="allowMissingReturnTag" value="true"/>
</module> </module>

View File

@@ -1,38 +0,0 @@
version: "3.7"
services:
dspace-cli:
image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}"
container_name: dspace-cli
build:
context: .
dockerfile: Dockerfile.cli
environment:
# Below syntax may look odd, but it is how to override dspace.cfg settings via env variables.
# See https://github.com/DSpace/DSpace/blob/main/dspace/config/config-definition.xml
# __P__ => "." (e.g. dspace__P__dir => dspace.dir)
# __D__ => "-" (e.g. google__D__metadata => google-metadata)
# dspace.dir: Must match with Dockerfile's DSPACE_INSTALL directory.
dspace__P__dir: /dspace
# db.url: Ensure we are using the 'dspacedb' image for our database
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
volumes:
# Keep DSpace assetstore directory between reboots
- assetstore:/dspace/assetstore
# Mount local [src]/dspace/config/ to container. This syncs your local configs with container
# NOTE: Environment variables specified above will OVERRIDE any configs in local.cfg or dspace.cfg
- ./dspace/config:/dspace/config
entrypoint: /dspace/bin/dspace
command: help
networks:
- dspacenet
tty: true
stdin_open: true
volumes:
assetstore:
networks:
dspacenet:

View File

@@ -1,121 +0,0 @@
version: '3.7'
networks:
dspacenet:
ipam:
config:
# Define a custom subnet for our DSpace network, so that we can easily trust requests from host to container.
# If you customize this value, be sure to customize the 'proxies.trusted.ipranges' env variable below.
- subnet: 172.23.0.0/16
services:
# DSpace (backend) webapp container
dspace:
container_name: dspace
environment:
# Below syntax may look odd, but it is how to override dspace.cfg settings via env variables.
# See https://github.com/DSpace/DSpace/blob/main/dspace/config/config-definition.xml
# __P__ => "." (e.g. dspace__P__dir => dspace.dir)
# __D__ => "-" (e.g. google__D__metadata => google-metadata)
# dspace.dir: Must match with Dockerfile's DSPACE_INSTALL directory.
dspace__P__dir: /dspace
# Uncomment to set a non-default value for dspace.server.url or dspace.ui.url
# dspace__P__server__P__url: http://localhost:8080/server
# dspace__P__ui__P__url: http://localhost:4000
dspace__P__name: 'DSpace Started with Docker Compose'
# db.url: Ensure we are using the 'dspacedb' image for our database
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
# 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'
image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-7_x-test}"
build:
context: .
dockerfile: Dockerfile.test
depends_on:
- dspacedb
networks:
dspacenet:
ports:
- published: 8080
target: 8080
- published: 8009
target: 8009
stdin_open: true
tty: true
volumes:
# Keep DSpace assetstore directory between reboots
- assetstore:/dspace/assetstore
# Mount local [src]/dspace/config/ to container. This syncs your local configs with container
# NOTE: Environment variables specified above will OVERRIDE any configs in local.cfg or dspace.cfg
- ./dspace/config:/dspace/config
# Ensure that the database is ready BEFORE starting tomcat
# 1. While a TCP connection to dspacedb port 5432 is not available, continue to sleep
# 2. Then, run database migration to init database tables
# 3. Finally, start Tomcat
entrypoint:
- /bin/bash
- '-c'
- |
while (!</dev/tcp/dspacedb/5432) > /dev/null 2>&1; do sleep 1; done;
/dspace/bin/dspace database migrate
catalina.sh run
# DSpace database container
dspacedb:
container_name: dspacedb
environment:
PGDATA: /pgdata
# Uses a custom Postgres image with pgcrypto installed
image: dspace/dspace-postgres-pgcrypto
networks:
dspacenet:
ports:
- published: 5432
target: 5432
stdin_open: true
tty: true
volumes:
- pgdata:/pgdata
# DSpace Solr container
dspacesolr:
container_name: dspacesolr
# Uses official Solr image at https://hub.docker.com/_/solr/
image: solr:8.11-slim
networks:
dspacenet:
ports:
- published: 8983
target: 8983
stdin_open: true
tty: true
working_dir: /var/solr/data
volumes:
# Mount our local Solr core configs so that they are available as Solr configsets on container
- ./dspace/solr/authority:/opt/solr/server/solr/configsets/authority
- ./dspace/solr/oai:/opt/solr/server/solr/configsets/oai
- ./dspace/solr/search:/opt/solr/server/solr/configsets/search
- ./dspace/solr/statistics:/opt/solr/server/solr/configsets/statistics
# Keep Solr data directory between reboots
- solr_data:/var/solr/data
# Initialize all DSpace Solr cores using the mounted local configsets (see above), 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 updated configs from mounted configsets to this core. If it already existed, this updates core
# to the latest configs. If it's a newly created core, this is a no-op.
entrypoint:
- /bin/bash
- '-c'
- |
init-var-solr
precreate-core authority /opt/solr/server/solr/configsets/authority
cp -r -u /opt/solr/server/solr/configsets/authority/* authority
precreate-core oai /opt/solr/server/solr/configsets/oai
cp -r -u /opt/solr/server/solr/configsets/oai/* oai
precreate-core search /opt/solr/server/solr/configsets/search
cp -r -u /opt/solr/server/solr/configsets/search/* search
precreate-core statistics /opt/solr/server/solr/configsets/statistics
cp -r -u /opt/solr/server/solr/configsets/statistics/* statistics
exec solr -f
volumes:
assetstore:
pgdata:
solr_data:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,163 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.handler.extraction;
/**
* The various Solr Parameters names to use when extracting content.
**/
public interface ExtractingParams {
/**
* Map all generated attribute names to field names with lowercase and underscores.
*/
public static final String LOWERNAMES = "lowernames";
/**
* if true, ignore TikaException (give up to extract text but index meta data)
*/
public static final String IGNORE_TIKA_EXCEPTION = "ignoreTikaException";
/**
* The param prefix for mapping Tika metadata to Solr fields.
* <p>
* To map a field, add a name like:
* <pre>fmap.title=solr.title</pre>
*
* In this example, the tika "title" metadata value will be added to a Solr field named "solr.title"
*/
public static final String MAP_PREFIX = "fmap.";
/**
* The boost value for the name of the field. The boost can be specified by a name mapping.
* <p>
* For example
* <pre>
* map.title=solr.title
* boost.solr.title=2.5
* </pre>
* will boost the solr.title field for this document by 2.5
*/
public static final String BOOST_PREFIX = "boost.";
/**
* Pass in literal values to be added to the document, as in
* <pre>
* literal.myField=Foo
* </pre>
*/
public static final String LITERALS_PREFIX = "literal.";
/**
* Restrict the extracted parts of a document to be indexed
* by passing in an XPath expression. All content that satisfies the XPath expr.
* will be passed to the {@link org.apache.solr.handler.extraction.SolrContentHandler}.
* <p>
* See Tika's docs for what the extracted document looks like.
*
* @see #CAPTURE_ELEMENTS
*/
public static final String XPATH_EXPRESSION = "xpath";
/**
* Only extract and return the content, do not index it.
*/
public static final String EXTRACT_ONLY = "extractOnly";
/**
* Content output format if extractOnly is true. Default is "xml", alternative is "text".
*/
public static final String EXTRACT_FORMAT = "extractFormat";
/**
* Capture attributes separately according to the name of the element, instead of just adding them to the string
* buffer
*/
public static final String CAPTURE_ATTRIBUTES = "captureAttr";
/**
* Literal field values will by default override other values such as metadata and content. Set this to false to
* revert to pre-4.0 behaviour
*/
public static final String LITERALS_OVERRIDE = "literalsOverride";
/**
* Capture the specified fields (and everything included below it that isn't capture by some other capture field)
* separately from the default. This is different
* then the case of passing in an XPath expression.
* <p>
* The Capture field is based on the localName returned to the
* {@link org.apache.solr.handler.extraction.SolrContentHandler}
* by Tika, not to be confused by the mapped field. The field name can then
* be mapped into the index schema.
* <p>
* For instance, a Tika document may look like:
* <pre>
* &lt;html&gt;
* ...
* &lt;body&gt;
* &lt;p&gt;some text here. &lt;div&gt;more text&lt;/div&gt;&lt;/p&gt;
* Some more text
* &lt;/body&gt;
* </pre>
* By passing in the p tag, you could capture all P tags separately from the rest of the t
* Thus, in the example, the capture of the P tag would be: "some text here. more text"
*/
public static final String CAPTURE_ELEMENTS = "capture";
/**
* The type of the stream. If not specified, Tika will use mime type detection.
*/
public static final String STREAM_TYPE = "stream.type";
/**
* Optional. The file name. If specified, Tika can take this into account while
* guessing the MIME type.
*/
public static final String RESOURCE_NAME = "resource.name";
/**
* Optional. The password for this resource. Will be used instead of the rule based password lookup mechanisms
*/
public static final String RESOURCE_PASSWORD = "resource.password";
/**
* Optional. If specified, the prefix will be prepended to all Metadata, such that it would be possible
* to setup a dynamic field to automatically capture it
*/
public static final String UNKNOWN_FIELD_PREFIX = "uprefix";
/**
* Optional. If specified and the name of a potential field cannot be determined, the default Field specified
* will be used instead.
*/
public static final String DEFAULT_FIELD = "defaultField";
/**
* Optional. If specified, loads the file as a source for password lookups for Tika encrypted documents.
* <p>
* File format is Java properties format with one key=value per line.
* The key is evaluated as a regex against the file name, and the value is the password
* The rules are evaluated top-bottom, i.e. the first match will be used
* If you want a fallback password to be always used, supply a .*=&lt;defaultmypassword&gt; at the end
*/
public static final String PASSWORD_MAP_FILE = "passwordsFile";
}

View File

@@ -14,10 +14,10 @@ import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.cli.PosixParser;
import org.apache.commons.collections.CollectionUtils;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community; import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
@@ -51,7 +51,7 @@ public class CommunityFiliator {
*/ */
public static void main(String[] argv) throws Exception { public static void main(String[] argv) throws Exception {
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
@@ -180,10 +180,14 @@ public class CommunityFiliator {
// second test - circularity: parent's parents can't include proposed // second test - circularity: parent's parents can't include proposed
// child // child
List<Community> parentDads = parent.getParentCommunities(); List<Community> parentDads = parent.getParentCommunities();
if (parentDads.contains(child)) {
System.out.println("Error, circular parentage - child is parent of parent"); for (int i = 0; i < parentDads.size(); i++) {
if (parentDads.get(i).getID().equals(child.getID())) {
System.out
.println("Error, circular parentage - child is parent of parent");
System.exit(1); System.exit(1);
} }
}
// everthing's OK // everthing's OK
communityService.addSubcommunity(c, parent, child); communityService.addSubcommunity(c, parent, child);
@@ -206,15 +210,26 @@ public class CommunityFiliator {
throws SQLException, AuthorizeException, IOException { throws SQLException, AuthorizeException, IOException {
// verify that child is indeed a child of parent // verify that child is indeed a child of parent
List<Community> parentKids = parent.getSubcommunities(); List<Community> parentKids = parent.getSubcommunities();
if (!parentKids.contains(child)) { boolean isChild = false;
System.out.println("Error, child community not a child of parent community");
for (int i = 0; i < parentKids.size(); i++) {
if (parentKids.get(i).getID().equals(child.getID())) {
isChild = true;
break;
}
}
if (!isChild) {
System.out
.println("Error, child community not a child of parent community");
System.exit(1); System.exit(1);
} }
// OK remove the mappings - but leave the community, which will become // OK remove the mappings - but leave the community, which will become
// top-level // top-level
child.removeParentCommunity(parent); child.getParentCommunities().remove(parent);
parent.removeSubCommunity(child); parent.getSubcommunities().remove(child);
communityService.update(c, child); communityService.update(c, child);
communityService.update(c, parent); communityService.update(c, parent);

View File

@@ -13,9 +13,10 @@ import java.util.Locale;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.StringUtils;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.I18nUtil; import org.dspace.core.I18nUtil;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
@@ -23,8 +24,6 @@ import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
/** /**
* A command-line tool for creating an initial administrator for setting up a * A command-line tool for creating an initial administrator for setting up a
@@ -62,7 +61,7 @@ public final class CreateAdministrator {
*/ */
public static void main(String[] argv) public static void main(String[] argv)
throws Exception { throws Exception {
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
CreateAdministrator ca = new CreateAdministrator(); CreateAdministrator ca = new CreateAdministrator();
@@ -116,7 +115,7 @@ public final class CreateAdministrator {
String lastName = null; String lastName = null;
char[] password1 = null; char[] password1 = null;
char[] password2 = null; char[] password2 = null;
String language = I18nUtil.getDefaultLocale().getLanguage(); String language = I18nUtil.DEFAULTLOCALE.getLanguage();
while (!dataOK) { while (!dataOK) {
System.out.print("E-mail address: "); System.out.print("E-mail address: ");
@@ -148,10 +147,9 @@ public final class CreateAdministrator {
lastName = lastName.trim(); lastName = lastName.trim();
} }
ConfigurationService cfg = DSpaceServicesFactory.getInstance().getConfigurationService(); if (ConfigurationManager.getProperty("webui.supported.locales") != null) {
if (cfg.hasProperty("webui.supported.locales")) { System.out.println("Select one of the following languages: " + ConfigurationManager
System.out.println("Select one of the following languages: " .getProperty("webui.supported.locales"));
+ cfg.getProperty("webui.supported.locales"));
System.out.print("Language: "); System.out.print("Language: ");
System.out.flush(); System.out.flush();

View File

@@ -10,7 +10,6 @@ package org.dspace.administer;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -18,28 +17,25 @@ import java.util.Map;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.xml.serialize.Method;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchema;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.MetadataSchemaService;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.w3c.dom.DOMConfiguration; import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
/** /**
* @author Graham Triggs * @author Graham Triggs
* *
* This class creates an XML document as passed in the arguments and * This class creates an xml document as passed in the arguments and
* from the metadata schemas for the repository. * from the metadata schemas for the repository.
* *
* The form of the XML is as follows * The form of the XML is as follows
@@ -67,18 +63,15 @@ public class MetadataExporter {
/** /**
* @param args commandline arguments * @param args commandline arguments
* @throws ParseException if parser error * @throws ParseException if parser error
* @throws SAXException if XML parse error
* @throws IOException if IO error * @throws IOException if IO error
* @throws SQLException if database error * @throws SQLException if database error
* @throws RegistryExportException if export error * @throws RegistryExportException if export error
* @throws ClassNotFoundException if no suitable DOM implementation
* @throws InstantiationException if no suitable DOM implementation
* @throws IllegalAccessException if no suitable DOM implementation
*/ */
public static void main(String[] args) public static void main(String[] args)
throws ParseException, SQLException, IOException, RegistryExportException, throws ParseException, SQLException, IOException, SAXException, RegistryExportException {
ClassNotFoundException, InstantiationException, IllegalAccessException {
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
options.addOption("f", "file", true, "output xml file for registry"); options.addOption("f", "file", true, "output xml file for registry");
options.addOption("s", "schema", true, "the name of the schema to export"); options.addOption("s", "schema", true, "the name of the schema to export");
@@ -108,25 +101,26 @@ public class MetadataExporter {
* @param schema schema definition to save * @param schema schema definition to save
* @throws SQLException if database error * @throws SQLException if database error
* @throws IOException if IO error * @throws IOException if IO error
* @throws SAXException if XML error
* @throws RegistryExportException if export error * @throws RegistryExportException if export error
* @throws ClassNotFoundException if no suitable DOM implementation
* @throws InstantiationException if no suitable DOM implementation
* @throws IllegalAccessException if no suitable DOM implementation
*/ */
public static void saveRegistry(String file, String schema) public static void saveRegistry(String file, String schema)
throws SQLException, IOException, RegistryExportException, throws SQLException, IOException, SAXException, RegistryExportException {
ClassNotFoundException, InstantiationException, IllegalAccessException {
// create a context // create a context
Context context = new Context(); Context context = new Context();
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
// Initialize an XML document. OutputFormat xmlFormat = new OutputFormat(Method.XML, "UTF-8", true);
Document document = DOMImplementationRegistry.newInstance() xmlFormat.setLineWidth(120);
.getDOMImplementation("XML 3.0") xmlFormat.setIndent(4);
.createDocument(null, "dspace-dc-types", null);
XMLSerializer xmlSerializer = new XMLSerializer(new BufferedWriter(new FileWriter(file)), xmlFormat);
// XMLSerializer xmlSerializer = new XMLSerializer(System.out, xmlFormat);
xmlSerializer.startDocument();
xmlSerializer.startElement("dspace-dc-types", null);
// Save the schema definition(s) // Save the schema definition(s)
saveSchema(context, document, schema); saveSchema(context, xmlSerializer, schema);
List<MetadataField> mdFields = null; List<MetadataField> mdFields = null;
@@ -145,64 +139,55 @@ public class MetadataExporter {
mdFields = metadataFieldService.findAll(context); mdFields = metadataFieldService.findAll(context);
} }
// Compose the metadata fields // Output the metadata fields
for (MetadataField mdField : mdFields) { for (MetadataField mdField : mdFields) {
saveType(context, document, mdField); saveType(context, xmlSerializer, mdField);
} }
// Serialize the completed document to the output file. xmlSerializer.endElement("dspace-dc-types");
try (Writer writer = new BufferedWriter(new FileWriter(file))) { xmlSerializer.endDocument();
DOMImplementationLS lsImplementation
= (DOMImplementationLS) DOMImplementationRegistry.newInstance()
.getDOMImplementation("LS");
LSSerializer serializer = lsImplementation.createLSSerializer();
DOMConfiguration configuration = serializer.getDomConfig();
configuration.setParameter("format-pretty-print", true);
LSOutput lsOutput = lsImplementation.createLSOutput();
lsOutput.setEncoding("UTF-8");
lsOutput.setCharacterStream(writer);
serializer.write(document, lsOutput);
}
// abort the context, as we shouldn't have changed it!! // abort the context, as we shouldn't have changed it!!
context.abort(); context.abort();
} }
/** /**
* Compose the schema registry. If the parameter 'schema' is null or empty, save all schemas. * Serialize the schema registry. If the parameter 'schema' is null or empty, save all schemas
* *
* @param context DSpace Context * @param context DSpace Context
* @param document the document being built * @param xmlSerializer XML serializer
* @param schema schema (may be null to save all) * @param schema schema (may be null to save all)
* @throws SQLException if database error * @throws SQLException if database error
* @throws SAXException if XML error
* @throws RegistryExportException if export error * @throws RegistryExportException if export error
*/ */
public static void saveSchema(Context context, Document document, String schema) public static void saveSchema(Context context, XMLSerializer xmlSerializer, String schema)
throws SQLException, RegistryExportException { throws SQLException, SAXException, RegistryExportException {
if (schema != null && !"".equals(schema)) { if (schema != null && !"".equals(schema)) {
// Find a single named schema // Find a single named schema
MetadataSchema mdSchema = metadataSchemaService.find(context, schema); MetadataSchema mdSchema = metadataSchemaService.find(context, schema);
saveSchema(document, mdSchema); saveSchema(xmlSerializer, mdSchema);
} else { } else {
// Find all schemas // Find all schemas
List<MetadataSchema> mdSchemas = metadataSchemaService.findAll(context); List<MetadataSchema> mdSchemas = metadataSchemaService.findAll(context);
for (MetadataSchema mdSchema : mdSchemas) { for (MetadataSchema mdSchema : mdSchemas) {
saveSchema(document, mdSchema); saveSchema(xmlSerializer, mdSchema);
} }
} }
} }
/** /**
* Compose a single schema (namespace) registry entry * Serialize a single schema (namespace) registry entry
* *
* @param document the output document being built. * @param xmlSerializer XML serializer
* @param mdSchema DSpace metadata schema * @param mdSchema DSpace metadata schema
* @throws SAXException if XML error
* @throws RegistryExportException if export error * @throws RegistryExportException if export error
*/ */
private static void saveSchema(Document document, MetadataSchema mdSchema) private static void saveSchema(XMLSerializer xmlSerializer, MetadataSchema mdSchema)
throws RegistryExportException { throws SAXException, RegistryExportException {
// If we haven't got a schema, it's an error // If we haven't got a schema, it's an error
if (mdSchema == null) { if (mdSchema == null) {
throw new RegistryExportException("no schema to export"); throw new RegistryExportException("no schema to export");
@@ -221,34 +206,35 @@ public class MetadataExporter {
return; return;
} }
Element document_element = document.getDocumentElement(); // Output the parent tag
xmlSerializer.startElement("dc-schema", null);
// Compose the parent tag // Output the schema name
Element schema_element = document.createElement("dc-schema"); xmlSerializer.startElement("name", null);
document_element.appendChild(schema_element); xmlSerializer.characters(name.toCharArray(), 0, name.length());
xmlSerializer.endElement("name");
// Compose the schema name // Output the schema namespace
Element name_element = document.createElement("name"); xmlSerializer.startElement("namespace", null);
schema_element.appendChild(name_element); xmlSerializer.characters(namespace.toCharArray(), 0, namespace.length());
name_element.setTextContent(name); xmlSerializer.endElement("namespace");
// Compose the schema namespace xmlSerializer.endElement("dc-schema");
Element namespace_element = document.createElement("namespace");
schema_element.appendChild(namespace_element);
namespace_element.setTextContent(namespace);
} }
/** /**
* Compose a single metadata field registry entry to XML. * Serialize a single metadata field registry entry to xml
* *
* @param context DSpace context * @param context DSpace context
* @param document the output document being built. * @param xmlSerializer xml serializer
* @param mdField DSpace metadata field * @param mdField DSpace metadata field
* @throws SAXException if XML error
* @throws RegistryExportException if export error * @throws RegistryExportException if export error
* @throws SQLException if database error * @throws SQLException if database error
* @throws IOException if IO error
*/ */
private static void saveType(Context context, Document document, MetadataField mdField) private static void saveType(Context context, XMLSerializer xmlSerializer, MetadataField mdField)
throws RegistryExportException, SQLException { throws SAXException, RegistryExportException, SQLException, IOException {
// If we haven't been given a field, it's an error // If we haven't been given a field, it's an error
if (mdField == null) { if (mdField == null) {
throw new RegistryExportException("no field to export"); throw new RegistryExportException("no field to export");
@@ -265,39 +251,38 @@ public class MetadataExporter {
throw new RegistryExportException("incomplete field information"); throw new RegistryExportException("incomplete field information");
} }
Element document_element = document.getDocumentElement(); // Output the parent tag
xmlSerializer.startElement("dc-type", null);
// Compose the parent tag // Output the schema name
Element dc_type = document.createElement("dc-type"); xmlSerializer.startElement("schema", null);
document_element.appendChild(dc_type); xmlSerializer.characters(schemaName.toCharArray(), 0, schemaName.length());
xmlSerializer.endElement("schema");
// Compose the schema name // Output the element
Element schema_element = document.createElement("schema"); xmlSerializer.startElement("element", null);
dc_type.appendChild(schema_element); xmlSerializer.characters(element.toCharArray(), 0, element.length());
schema_element.setTextContent(schemaName); xmlSerializer.endElement("element");
// Compose the element // Output the qualifier, if present
Element element_element = document.createElement("element");
dc_type.appendChild(element_element);
element_element.setTextContent(element);
// Compose the qualifier, if present
if (qualifier != null) { if (qualifier != null) {
Element qualifier_element = document.createElement("qualifier"); xmlSerializer.startElement("qualifier", null);
dc_type.appendChild(qualifier_element); xmlSerializer.characters(qualifier.toCharArray(), 0, qualifier.length());
qualifier_element.setTextContent(qualifier); xmlSerializer.endElement("qualifier");
} else { } else {
dc_type.appendChild(document.createComment("unqualified")); xmlSerializer.comment("unqualified");
} }
// Compose the scope note, if present // Output the scope note, if present
if (scopeNote != null) { if (scopeNote != null) {
Element scope_element = document.createElement("scope_note"); xmlSerializer.startElement("scope_note", null);
dc_type.appendChild(scope_element); xmlSerializer.characters(scopeNote.toCharArray(), 0, scopeNote.length());
scope_element.setTextContent(scopeNote); xmlSerializer.endElement("scope_note");
} else { } else {
dc_type.appendChild(document.createComment("no scope note")); xmlSerializer.comment("no scope note");
} }
xmlSerializer.endElement("dc-type");
} }
static Map<Integer, String> schemaMap = new HashMap<Integer, String>(); static Map<Integer, String> schemaMap = new HashMap<Integer, String>();
@@ -332,7 +317,7 @@ public class MetadataExporter {
} }
/** /**
* Print the usage message to standard output * Print the usage message to stdout
*/ */
public static void usage() { public static void usage() {
String usage = "Use this class with the following options:\n" + String usage = "Use this class with the following options:\n" +

View File

@@ -14,14 +14,13 @@ import javax.xml.transform.TransformerException;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.xpath.XPathAPI; import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.NonUniqueMetadataException; import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataFieldService;
@@ -81,7 +80,7 @@ public class MetadataImporter {
* @throws SQLException if database error * @throws SQLException if database error
* @throws IOException if IO error * @throws IOException if IO error
* @throws TransformerException if transformer error * @throws TransformerException if transformer error
* @throws ParserConfigurationException if configuration error * @throws ParserConfigurationException if config error
* @throws AuthorizeException if authorization error * @throws AuthorizeException if authorization error
* @throws SAXException if parser error * @throws SAXException if parser error
* @throws NonUniqueMetadataException if duplicate metadata * @throws NonUniqueMetadataException if duplicate metadata
@@ -91,22 +90,25 @@ public class MetadataImporter {
throws ParseException, SQLException, IOException, TransformerException, throws ParseException, SQLException, IOException, TransformerException,
ParserConfigurationException, AuthorizeException, SAXException, ParserConfigurationException, AuthorizeException, SAXException,
NonUniqueMetadataException, RegistryImportException { NonUniqueMetadataException, RegistryImportException {
boolean forceUpdate = false;
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
options.addOption("f", "file", true, "source xml file for DC fields"); options.addOption("f", "file", true, "source xml file for DC fields");
options.addOption("u", "update", false, "update an existing schema"); options.addOption("u", "update", false, "update an existing schema");
CommandLine line = parser.parse(options, args); CommandLine line = parser.parse(options, args);
String file = null;
if (line.hasOption('f')) { if (line.hasOption('f')) {
String file = line.getOptionValue('f'); file = line.getOptionValue('f');
boolean forceUpdate = line.hasOption('u');
loadRegistry(file, forceUpdate);
} else { } else {
usage(); usage();
System.exit(1); System.exit(0);
} }
forceUpdate = line.hasOption('u');
loadRegistry(file, forceUpdate);
} }
/** /**
@@ -117,7 +119,7 @@ public class MetadataImporter {
* @throws SQLException if database error * @throws SQLException if database error
* @throws IOException if IO error * @throws IOException if IO error
* @throws TransformerException if transformer error * @throws TransformerException if transformer error
* @throws ParserConfigurationException if configuration error * @throws ParserConfigurationException if config error
* @throws AuthorizeException if authorization error * @throws AuthorizeException if authorization error
* @throws SAXException if parser error * @throws SAXException if parser error
* @throws NonUniqueMetadataException if duplicate metadata * @throws NonUniqueMetadataException if duplicate metadata
@@ -224,7 +226,7 @@ public class MetadataImporter {
/** /**
* Process a node in the metadata registry XML file. The node must * Process a node in the metadata registry XML file. The node must
* be a "dc-type" node. If the type already exists, then it * be a "dc-type" node. If the type already exists, then it
* will not be re-imported. * will not be reimported
* *
* @param context DSpace context object * @param context DSpace context object
* @param node the node in the DOM tree * @param node the node in the DOM tree
@@ -246,7 +248,7 @@ public class MetadataImporter {
// If the schema is not provided default to DC // If the schema is not provided default to DC
if (schema == null) { if (schema == null) {
schema = MetadataSchemaEnum.DC.getName(); schema = MetadataSchema.DC_SCHEMA;
} }

View File

@@ -17,14 +17,14 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.xpath.XPathAPI; import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.BitstreamFormat; import org.dspace.content.BitstreamFormat;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamFormatService;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.LogHelper; import org.dspace.core.LogManager;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
@@ -47,7 +47,7 @@ public class RegistryLoader {
/** /**
* log4j category * log4j category
*/ */
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RegistryLoader.class); private static Logger log = Logger.getLogger(RegistryLoader.class);
protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance() protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
.getBitstreamFormatService(); .getBitstreamFormatService();
@@ -95,7 +95,7 @@ public class RegistryLoader {
System.exit(1); System.exit(1);
} catch (Exception e) { } catch (Exception e) {
log.fatal(LogHelper.getHeader(context, "error_loading_registries", log.fatal(LogManager.getHeader(context, "error_loading_registries",
""), e); ""), e);
System.err.println("Error: \n - " + e.getMessage()); System.err.println("Error: \n - " + e.getMessage());
@@ -135,7 +135,7 @@ public class RegistryLoader {
loadFormat(context, n); loadFormat(context, n);
} }
log.info(LogHelper.getHeader(context, "load_bitstream_formats", log.info(LogManager.getHeader(context, "load_bitstream_formats",
"number_loaded=" + typeNodes.getLength())); "number_loaded=" + typeNodes.getLength()));
} }

View File

@@ -7,24 +7,12 @@
*/ */
package org.dspace.administer; package org.dspace.administer;
import static org.dspace.content.service.DSpaceObjectService.MD_COPYRIGHT_TEXT; import java.io.BufferedWriter;
import static org.dspace.content.service.DSpaceObjectService.MD_INTRODUCTORY_TEXT; import java.io.File;
import static org.dspace.content.service.DSpaceObjectService.MD_LICENSE; import java.io.FileWriter;
import static org.dspace.content.service.DSpaceObjectService.MD_NAME;
import static org.dspace.content.service.DSpaceObjectService.MD_PROVENANCE_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SHORT_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SIDEBAR_TEXT;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@@ -33,19 +21,12 @@ import javax.xml.transform.TransformerException;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser;
import org.apache.xpath.XPathAPI; import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection; import org.dspace.content.Collection;
import org.dspace.content.Community; import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.MetadataFieldName;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService; import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService; import org.dspace.content.service.CommunityService;
@@ -53,7 +34,6 @@ import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.jdom.Element; import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter; import org.jdom.output.XMLOutputter;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@@ -65,7 +45,7 @@ import org.xml.sax.SAXException;
* an XML file. * an XML file.
* *
* The XML file structure needs to be: * The XML file structure needs to be:
* <pre>{@code * {@code
* <import_structure> * <import_structure>
* <community> * <community>
* <name>....</name> * <name>....</name>
@@ -75,41 +55,34 @@ import org.xml.sax.SAXException;
* </collection> * </collection>
* </community> * </community>
* </import_structure> * </import_structure>
* }</pre> * }
* <p> * it can be arbitrarily deep, and supports all the metadata elements
* It can be arbitrarily deep, and supports all the metadata elements
* that make up the community and collection metadata. See the system * that make up the community and collection metadata. See the system
* documentation for more details. * documentation for more details
* *
* @author Richard Jones * @author Richard Jones
*/ */
public class StructBuilder { public class StructBuilder {
/** Name of the root element for the document to be imported. */ /**
static final String INPUT_ROOT = "import_structure"; * the output xml document which will contain updated information about the
* imported structure
/*
* Name of the root element for the document produced by importing.
* Community and collection elements are annotated with their identifiers.
*/ */
static final String RESULT_ROOT = "imported_structure"; private static org.jdom.Document xmlOutput = new org.jdom.Document(new Element("imported_structure"));
/** /**
* A table to hold metadata for the collection being worked on. * a hashtable to hold metadata for the collection being worked on
*/ */
private static final Map<String, MetadataFieldName> collectionMap = new HashMap<>(); private static Map<String, String> collectionMap = new HashMap<String, String>();
/** /**
* A table to hold metadata for the community being worked on. * a hashtable to hold metadata for the community being worked on
*/ */
private static final Map<String, MetadataFieldName> communityMap = new HashMap<>(); private static Map<String, String> communityMap = new HashMap<String, String>();
protected static CommunityService communityService protected static CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
= ContentServiceFactory.getInstance().getCommunityService(); protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected static CollectionService collectionService protected static EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
= ContentServiceFactory.getInstance().getCollectionService();
protected static EPersonService ePersonService
= EPersonServiceFactory.getInstance().getEPersonService();
/** /**
* Default constructor * Default constructor
@@ -118,356 +91,135 @@ public class StructBuilder {
/** /**
* Main method to be run from the command line to import a structure into * Main method to be run from the command line to import a structure into
* DSpacee or export existing structure to a file.The command is of the form: * DSpace
* *
* <p>{@code StructBuilder -f [XML source] -e [administrator email] -o [output file]} * This is of the form:
* *
* <p>to import, or * {@code StructBuilder -f [xml source] -e [administrator email] -o [output file]}
* *
* <p>{@code StructBuilder -x -e [administrator email] -o [output file]}</p> * The output file will contain exactly the same as the source xml document, but
* with the handle for each imported item added as an attribute.
* *
* <p>to export. The output will contain exactly the same as the source XML * @param argv the command line arguments given
* document, but with the Handle for each imported item added as an attribute. * @throws Exception if an error occurs
*
*
* @param argv command line arguments.
* @throws ParserConfigurationException passed through.
* @throws SQLException passed through.
* @throws FileNotFoundException if input or output could not be opened.
* @throws TransformerException if the input document is invalid.
*/ */
public static void main(String[] argv) public static void main(String[] argv)
throws ParserConfigurationException, SQLException, throws Exception {
FileNotFoundException, IOException, TransformerException { CommandLineParser parser = new PosixParser();
// Define command line options.
Options options = new Options(); Options options = new Options();
options.addOption("h", "help", false, "Print this help message."); options.addOption("f", "file", true, "file");
options.addOption("?", "help"); options.addOption("e", "eperson", true, "eperson");
options.addOption("x", "export", false, "Export the current structure as XML."); options.addOption("o", "output", true, "output");
options.addOption(Option.builder("e").longOpt("eperson") CommandLine line = parser.parse(options, argv);
.desc("User who is manipulating the repository's structure.")
.hasArg().argName("eperson").required().build());
options.addOption(Option.builder("f").longOpt("file") String file = null;
.desc("File of new structure information.") String eperson = null;
.hasArg().argName("input").build()); String output = null;
options.addOption(Option.builder("o").longOpt("output") if (line.hasOption('f')) {
.desc("File to receive the structure map ('-' for standard out).") file = line.getOptionValue('f');
.hasArg().argName("output").required().build());
// Parse the command line.
CommandLineParser parser = new DefaultParser();
CommandLine line = null;
try {
line = parser.parse(options, argv);
} catch (ParseException ex) {
System.err.println(ex.getMessage());
usage(options);
System.exit(1);
} }
// If the user asked for help, give it and exit. if (line.hasOption('e')) {
if (line.hasOption('h') || line.hasOption('?')) { eperson = line.getOptionValue('e');
giveHelp(options); }
if (line.hasOption('o')) {
output = line.getOptionValue('o');
}
if (output == null || eperson == null || file == null) {
usage();
System.exit(0); System.exit(0);
} }
// Otherwise, analyze the command.
// Must be import or export.
if (!(line.hasOption('f') || line.hasOption('x'))) {
giveHelp(options);
System.exit(1);
}
// Open the output stream.
String output = line.getOptionValue('o');
OutputStream outputStream;
if ("-".equals(output)) {
outputStream = System.out;
} else {
outputStream = new FileOutputStream(output);
}
// create a context // create a context
Context context = new Context(); Context context = new Context();
// set the context. // set the context
String eperson = line.getOptionValue('e');
try {
context.setCurrentUser(ePersonService.findByEmail(context, eperson)); context.setCurrentUser(ePersonService.findByEmail(context, eperson));
} catch (SQLException ex) {
System.err.format("That user could not be found: %s%n", ex.getMessage());
System.exit(1);
}
// Export? Import?
if (line.hasOption('x')) { // export
exportStructure(context, outputStream);
} else { // Must be import
String input = line.getOptionValue('f');
if (null == input) {
usage(options);
System.exit(1);
}
InputStream inputStream;
if ("-".equals(input)) {
inputStream = System.in;
} else {
inputStream = new FileInputStream(input);
}
importStructure(context, inputStream, outputStream);
// save changes from import
context.complete();
}
System.exit(0);
}
/**
* Import new Community/Collection structure.
*
* @param context
* @param input XML which describes the new communities and collections.
* @param output input, annotated with the new objects' identifiers.
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
* @throws TransformerException
* @throws SQLException
*/
static void importStructure(Context context, InputStream input, OutputStream output)
throws IOException, ParserConfigurationException, SQLException, TransformerException {
// load the XML // load the XML
Document document = null; Document document = loadXML(file);
try {
document = loadXML(input);
} catch (IOException ex) {
System.err.format("The input document could not be read: %s%n", ex.getMessage());
System.exit(1);
} catch (SAXException ex) {
System.err.format("The input document could not be parsed: %s%n", ex.getMessage());
System.exit(1);
}
// run the preliminary validation, to be sure that the the XML document // run the preliminary validation, to be sure that the the XML document
// is properly structured. // is properly structured
try {
validate(document); validate(document);
} catch (TransformerException ex) {
System.err.format("The input document is invalid: %s%n", ex.getMessage());
System.exit(1);
}
// Check for 'identifier' attributes -- possibly output by this class.
NodeList identifierNodes = XPathAPI.selectNodeList(document, "//*[@identifier]");
if (identifierNodes.getLength() > 0) {
System.err.println("The input document has 'identifier' attributes, which will be ignored.");
}
// load the mappings into the member variable hashmaps // load the mappings into the member variable hashmaps
communityMap.put("name", MD_NAME); communityMap.put("name", "name");
communityMap.put("description", MD_SHORT_DESCRIPTION); communityMap.put("description", "short_description");
communityMap.put("intro", MD_INTRODUCTORY_TEXT); communityMap.put("intro", "introductory_text");
communityMap.put("copyright", MD_COPYRIGHT_TEXT); communityMap.put("copyright", "copyright_text");
communityMap.put("sidebar", MD_SIDEBAR_TEXT); communityMap.put("sidebar", "side_bar_text");
collectionMap.put("name", MD_NAME); collectionMap.put("name", "name");
collectionMap.put("description", MD_SHORT_DESCRIPTION); collectionMap.put("description", "short_description");
collectionMap.put("intro", MD_INTRODUCTORY_TEXT); collectionMap.put("intro", "introductory_text");
collectionMap.put("copyright", MD_COPYRIGHT_TEXT); collectionMap.put("copyright", "copyright_text");
collectionMap.put("sidebar", MD_SIDEBAR_TEXT); collectionMap.put("sidebar", "side_bar_text");
collectionMap.put("license", MD_LICENSE); collectionMap.put("license", "license");
collectionMap.put("provenance", MD_PROVENANCE_DESCRIPTION); collectionMap.put("provenance", "provenance_description");
Element[] elements = new Element[]{};
try {
// get the top level community list // get the top level community list
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community"); NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
// run the import starting with the top level communities // run the import starting with the top level communities
elements = handleCommunities(context, first, null); Element[] elements = handleCommunities(context, first, null);
} catch (TransformerException ex) {
System.err.format("Input content not understood: %s%n", ex.getMessage());
System.exit(1);
} catch (AuthorizeException ex) {
System.err.format("Not authorized: %s%n", ex.getMessage());
System.exit(1);
}
// generate the output // generate the output
final Element root = new Element(RESULT_ROOT); Element root = xmlOutput.getRootElement();
for (int i = 0; i < elements.length; i++) {
for (Element element : elements) { root.addContent(elements[i]);
root.addContent(element);
} }
// finally write the string into the output file. // finally write the string into the output file
final org.jdom.Document xmlOutput = new org.jdom.Document(root);
try { try {
new XMLOutputter().output(xmlOutput, output); BufferedWriter out = new BufferedWriter(new FileWriter(output));
out.write(new XMLOutputter().outputString(xmlOutput));
out.close();
} catch (IOException e) { } catch (IOException e) {
System.out.printf("Unable to write to output file %s: %s%n", System.out.println("Unable to write to output file " + output);
output, e.getMessage()); System.exit(0);
System.exit(1);
} }
context.complete();
} }
/** /**
* Add a single community, and its children, to the Document. * Output the usage information
*
* @param community
* @return a fragment representing this Community.
*/ */
private static Element exportACommunity(Community community) { private static void usage() {
// Export this Community. System.out.println("Usage: java StructBuilder -f <source XML file> -o <output file> -e <eperson email>");
Element element = new Element("community"); System.out.println(
element.setAttribute("identifier", community.getHandle()); "Communities will be created from the top level, and a map of communities to handles will be returned in " +
element.addContent(new Element("name").setText(community.getName())); "the output file");
element.addContent(new Element("description") return;
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY)));
element.addContent(new Element("intro")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY)));
element.addContent(new Element("copyright")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY)));
element.addContent(new Element("sidebar")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY)));
// Export this Community's Community children.
for (Community subCommunity : community.getSubcommunities()) {
element.addContent(exportACommunity(subCommunity));
}
// Export this Community's Collection children.
for (Collection collection : community.getCollections()) {
element.addContent(exportACollection(collection));
}
return element;
} }
/** /**
* Add a single Collection to the Document. * Validate the XML document. This method does not return, but if validation
* * fails it generates an error and ceases execution
* @param collection
* @return a fragment representing this Collection.
*/
private static Element exportACollection(Collection collection) {
// Export this Collection.
Element element = new Element("collection");
element.setAttribute("identifier", collection.getHandle());
element.addContent(new Element("name").setText(collection.getName()));
element.addContent(new Element("description")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY)));
element.addContent(new Element("intro")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY)));
element.addContent(new Element("copyright")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY)));
element.addContent(new Element("sidebar")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY)));
element.addContent(new Element("license")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "rights", "license", Item.ANY)));
// Provenance is special: multivalued
for (MetadataValue value : collectionService.getMetadata(collection,
MetadataSchemaEnum.DC.getName(), "provenance", null, Item.ANY)) {
element.addContent(new Element("provenance")
.setText(value.getValue()));
}
return element;
}
/**
* Write out the existing Community/Collection structure.
*/
static void exportStructure(Context context, OutputStream output) {
// Build a document from the Community/Collection hierarchy.
Element rootElement = new Element(INPUT_ROOT); // To be read by importStructure, perhaps
List<Community> communities = null;
try {
communities = communityService.findAllTop(context);
} catch (SQLException ex) {
System.out.printf("Unable to get the list of top-level communities: %s%n",
ex.getMessage());
System.exit(1);
}
for (Community community : communities) {
rootElement.addContent(exportACommunity(community));
}
// Now write the structure out.
org.jdom.Document xmlOutput = new org.jdom.Document(rootElement);
try {
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(xmlOutput, output);
} catch (IOException e) {
System.out.printf("Unable to write to output file %s: %s%n",
output, e.getMessage());
System.exit(1);
}
}
/**
* Output the usage information.
*/
private static void usage(Options options) {
HelpFormatter helper = new HelpFormatter();
try (PrintWriter writer = new PrintWriter(System.out);) {
helper.printUsage(writer, 80/* FIXME Magic */,
"structure-builder", options);
}
}
/**
* Help the user more.
*/
private static void giveHelp(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("struct-builder",
"Import or export Community/Collection structure.",
options,
"When importing (-f), communities will be created from the "
+ "top level, and a map of communities to handles will "
+ "be returned in the output file. When exporting (-x),"
+ "the current structure will be written to the map file.",
true);
}
/**
* Validate the XML document. This method returns if the document is valid.
* If validation fails it generates an error and ceases execution.
* *
* @param document the XML document object * @param document the XML document object
* @throws TransformerException if transformer error * @throws TransformerException if transformer error
*/ */
private static void validate(org.w3c.dom.Document document) private static void validate(org.w3c.dom.Document document)
throws TransformerException { throws TransformerException {
StringBuilder err = new StringBuilder(); StringBuffer err = new StringBuffer();
boolean trip = false; boolean trip = false;
err.append("The following errors were encountered parsing the source XML.\n"); err.append("The following errors were encountered parsing the source XML\n");
err.append("No changes have been made to the DSpace instance.\n\n"); err.append("No changes have been made to the DSpace instance\n\n");
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community"); NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
if (first.getLength() == 0) { if (first.getLength() == 0) {
err.append("-There are no top level communities in the source document."); err.append("-There are no top level communities in the source document");
System.out.println(err.toString()); System.out.println(err.toString());
System.exit(1); System.exit(0);
} }
String errs = validateCommunities(first, 1); String errs = validateCommunities(first, 1);
@@ -478,13 +230,13 @@ public class StructBuilder {
if (trip) { if (trip) {
System.out.println(err.toString()); System.out.println(err.toString());
System.exit(1); System.exit(0);
} }
} }
/** /**
* Validate the communities section of the XML document. This returns a string * Validate the communities section of the XML document. This returns a string
* containing any errors encountered, or null if there were no errors. * containing any errors encountered, or null if there were no errors
* *
* @param communities the NodeList of communities to validate * @param communities the NodeList of communities to validate
* @param level the level in the XML document that we are at, for the purposes * @param level the level in the XML document that we are at, for the purposes
@@ -494,7 +246,7 @@ public class StructBuilder {
*/ */
private static String validateCommunities(NodeList communities, int level) private static String validateCommunities(NodeList communities, int level)
throws TransformerException { throws TransformerException {
StringBuilder err = new StringBuilder(); StringBuffer err = new StringBuffer();
boolean trip = false; boolean trip = false;
String errs = null; String errs = null;
@@ -503,9 +255,8 @@ public class StructBuilder {
NodeList name = XPathAPI.selectNodeList(n, "name"); NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1) { if (name.getLength() != 1) {
String pos = Integer.toString(i + 1); String pos = Integer.toString(i + 1);
err.append("-The level ").append(level) err.append("-The level " + level + " community in position " + pos);
.append(" community in position ").append(pos) err.append(" does not contain exactly one name field\n");
.append(" does not contain exactly one name field.\n");
trip = true; trip = true;
} }
@@ -535,7 +286,7 @@ public class StructBuilder {
/** /**
* validate the collection section of the XML document. This generates a * validate the collection section of the XML document. This generates a
* string containing any errors encountered, or returns null if no errors. * string containing any errors encountered, or returns null if no errors
* *
* @param collections a NodeList of collections to validate * @param collections a NodeList of collections to validate
* @param level the level in the XML document for the purposes of error reporting * @param level the level in the XML document for the purposes of error reporting
@@ -543,7 +294,7 @@ public class StructBuilder {
*/ */
private static String validateCollections(NodeList collections, int level) private static String validateCollections(NodeList collections, int level)
throws TransformerException { throws TransformerException {
StringBuilder err = new StringBuilder(); StringBuffer err = new StringBuffer();
boolean trip = false; boolean trip = false;
String errs = null; String errs = null;
@@ -552,9 +303,8 @@ public class StructBuilder {
NodeList name = XPathAPI.selectNodeList(n, "name"); NodeList name = XPathAPI.selectNodeList(n, "name");
if (name.getLength() != 1) { if (name.getLength() != 1) {
String pos = Integer.toString(i + 1); String pos = Integer.toString(i + 1);
err.append("-The level ").append(level) err.append("-The level " + level + " collection in position " + pos);
.append(" collection in position ").append(pos) err.append(" does not contain exactly one name field\n");
.append(" does not contain exactly one name field.\n");
trip = true; trip = true;
} }
} }
@@ -567,17 +317,17 @@ public class StructBuilder {
} }
/** /**
* Load the XML document from input. * Load in the XML from file.
* *
* @param input the filename to load from. * @param filename the filename to load from
* @return the DOM representation of the XML input. * @return the DOM representation of the XML file
*/ */
private static org.w3c.dom.Document loadXML(InputStream input) private static org.w3c.dom.Document loadXML(String filename)
throws IOException, ParserConfigurationException, SAXException { throws IOException, ParserConfigurationException, SAXException {
DocumentBuilder builder = DocumentBuilderFactory.newInstance() DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder(); .newDocumentBuilder();
org.w3c.dom.Document document = builder.parse(input); org.w3c.dom.Document document = builder.parse(new File(filename));
return document; return document;
} }
@@ -588,7 +338,7 @@ public class StructBuilder {
* @param node the node from which we want to extract the string value * @param node the node from which we want to extract the string value
* @return the string value of the node * @return the string value of the node
*/ */
private static String getStringValue(Node node) { public static String getStringValue(Node node) {
String value = node.getNodeValue(); String value = node.getNodeValue();
if (node.hasChildNodes()) { if (node.hasChildNodes()) {
@@ -613,7 +363,7 @@ public class StructBuilder {
* created communities (e.g. the handles they have been assigned) * created communities (e.g. the handles they have been assigned)
*/ */
private static Element[] handleCommunities(Context context, NodeList communities, Community parent) private static Element[] handleCommunities(Context context, NodeList communities, Community parent)
throws TransformerException, SQLException, AuthorizeException { throws TransformerException, SQLException, Exception {
Element[] elements = new Element[communities.getLength()]; Element[] elements = new Element[communities.getLength()];
for (int i = 0; i < communities.getLength(); i++) { for (int i = 0; i < communities.getLength(); i++) {
@@ -628,24 +378,24 @@ public class StructBuilder {
} }
// default the short description to be an empty string // default the short description to be an empty string
communityService.setMetadataSingleValue(context, community, communityService.setMetadata(context, community, "short_description", " ");
MD_SHORT_DESCRIPTION, null, " ");
// now update the metadata // now update the metadata
Node tn = communities.item(i); Node tn = communities.item(i);
for (Map.Entry<String, MetadataFieldName> entry : communityMap.entrySet()) { for (Map.Entry<String, String> entry : communityMap.entrySet()) {
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey()); NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
if (nl.getLength() == 1) { if (nl.getLength() == 1) {
communityService.setMetadataSingleValue(context, community, communityService.setMetadata(context, community, entry.getValue(), getStringValue(nl.item(0)));
entry.getValue(), null, getStringValue(nl.item(0)));
} }
} }
// FIXME: at the moment, if the community already exists by name // FIXME: at the moment, if the community already exists by name
// then this will throw an SQLException on a duplicate key // then this will throw a PSQLException on a duplicate key
// violation. // violation
// Ideally we'd skip this row and continue to create sub communities // Ideally we'd skip this row and continue to create sub
// and so forth where they don't exist, but it's proving difficult // communities
// and so forth where they don't exist, but it's proving
// difficult
// to isolate the community that already exists without hitting // to isolate the community that already exists without hitting
// the database directly. // the database directly.
communityService.update(context, community); communityService.update(context, community);
@@ -661,41 +411,30 @@ public class StructBuilder {
element.setAttribute("identifier", community.getHandle()); element.setAttribute("identifier", community.getHandle());
Element nameElement = new Element("name"); Element nameElement = new Element("name");
nameElement.setText(communityService.getMetadataFirstValue( nameElement.setText(communityService.getMetadata(community, "name"));
community, CommunityService.MD_NAME, Item.ANY));
element.addContent(nameElement); element.addContent(nameElement);
String fieldValue; if (communityService.getMetadata(community, "short_description") != null) {
fieldValue = communityService.getMetadataFirstValue(community,
CommunityService.MD_SHORT_DESCRIPTION, Item.ANY);
if (fieldValue != null) {
Element descriptionElement = new Element("description"); Element descriptionElement = new Element("description");
descriptionElement.setText(fieldValue); descriptionElement.setText(communityService.getMetadata(community, "short_description"));
element.addContent(descriptionElement); element.addContent(descriptionElement);
} }
fieldValue = communityService.getMetadataFirstValue(community, if (communityService.getMetadata(community, "introductory_text") != null) {
CommunityService.MD_INTRODUCTORY_TEXT, Item.ANY);
if (fieldValue != null) {
Element introElement = new Element("intro"); Element introElement = new Element("intro");
introElement.setText(fieldValue); introElement.setText(communityService.getMetadata(community, "introductory_text"));
element.addContent(introElement); element.addContent(introElement);
} }
fieldValue = communityService.getMetadataFirstValue(community, if (communityService.getMetadata(community, "copyright_text") != null) {
CommunityService.MD_COPYRIGHT_TEXT, Item.ANY);
if (fieldValue != null) {
Element copyrightElement = new Element("copyright"); Element copyrightElement = new Element("copyright");
copyrightElement.setText(fieldValue); copyrightElement.setText(communityService.getMetadata(community, "copyright_text"));
element.addContent(copyrightElement); element.addContent(copyrightElement);
} }
fieldValue = communityService.getMetadataFirstValue(community, if (communityService.getMetadata(community, "side_bar_text") != null) {
CommunityService.MD_SIDEBAR_TEXT, Item.ANY);
if (fieldValue != null) {
Element sidebarElement = new Element("sidebar"); Element sidebarElement = new Element("sidebar");
sidebarElement.setText(fieldValue); sidebarElement.setText(communityService.getMetadata(community, "side_bar_text"));
element.addContent(sidebarElement); element.addContent(sidebarElement);
} }
@@ -731,7 +470,7 @@ public class StructBuilder {
* created collections (e.g. the handle) * created collections (e.g. the handle)
*/ */
private static Element[] handleCollections(Context context, NodeList collections, Community parent) private static Element[] handleCollections(Context context, NodeList collections, Community parent)
throws TransformerException, SQLException, AuthorizeException { throws TransformerException, SQLException, AuthorizeException, IOException, Exception {
Element[] elements = new Element[collections.getLength()]; Element[] elements = new Element[collections.getLength()];
for (int i = 0; i < collections.getLength(); i++) { for (int i = 0; i < collections.getLength(); i++) {
@@ -739,16 +478,14 @@ public class StructBuilder {
Collection collection = collectionService.create(context, parent); Collection collection = collectionService.create(context, parent);
// default the short description to the empty string // default the short description to the empty string
collectionService.setMetadataSingleValue(context, collection, collectionService.setMetadata(context, collection, "short_description", " ");
MD_SHORT_DESCRIPTION, Item.ANY, " ");
// import the rest of the metadata // import the rest of the metadata
Node tn = collections.item(i); Node tn = collections.item(i);
for (Map.Entry<String, MetadataFieldName> entry : collectionMap.entrySet()) { for (Map.Entry<String, String> entry : collectionMap.entrySet()) {
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey()); NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
if (nl.getLength() == 1) { if (nl.getLength() == 1) {
collectionService.setMetadataSingleValue(context, collection, collectionService.setMetadata(context, collection, entry.getValue(), getStringValue(nl.item(0)));
entry.getValue(), null, getStringValue(nl.item(0)));
} }
} }
@@ -757,57 +494,42 @@ public class StructBuilder {
element.setAttribute("identifier", collection.getHandle()); element.setAttribute("identifier", collection.getHandle());
Element nameElement = new Element("name"); Element nameElement = new Element("name");
nameElement.setText(collectionService.getMetadataFirstValue(collection, nameElement.setText(collectionService.getMetadata(collection, "name"));
CollectionService.MD_NAME, Item.ANY));
element.addContent(nameElement); element.addContent(nameElement);
String fieldValue; if (collectionService.getMetadata(collection, "short_description") != null) {
fieldValue = collectionService.getMetadataFirstValue(collection,
CollectionService.MD_SHORT_DESCRIPTION, Item.ANY);
if (fieldValue != null) {
Element descriptionElement = new Element("description"); Element descriptionElement = new Element("description");
descriptionElement.setText(fieldValue); descriptionElement.setText(collectionService.getMetadata(collection, "short_description"));
element.addContent(descriptionElement); element.addContent(descriptionElement);
} }
fieldValue = collectionService.getMetadataFirstValue(collection, if (collectionService.getMetadata(collection, "introductory_text") != null) {
CollectionService.MD_INTRODUCTORY_TEXT, Item.ANY);
if (fieldValue != null) {
Element introElement = new Element("intro"); Element introElement = new Element("intro");
introElement.setText(fieldValue); introElement.setText(collectionService.getMetadata(collection, "introductory_text"));
element.addContent(introElement); element.addContent(introElement);
} }
fieldValue = collectionService.getMetadataFirstValue(collection, if (collectionService.getMetadata(collection, "copyright_text") != null) {
CollectionService.MD_COPYRIGHT_TEXT, Item.ANY);
if (fieldValue != null) {
Element copyrightElement = new Element("copyright"); Element copyrightElement = new Element("copyright");
copyrightElement.setText(fieldValue); copyrightElement.setText(collectionService.getMetadata(collection, "copyright_text"));
element.addContent(copyrightElement); element.addContent(copyrightElement);
} }
fieldValue = collectionService.getMetadataFirstValue(collection, if (collectionService.getMetadata(collection, "side_bar_text") != null) {
CollectionService.MD_SIDEBAR_TEXT, Item.ANY);
if (fieldValue != null) {
Element sidebarElement = new Element("sidebar"); Element sidebarElement = new Element("sidebar");
sidebarElement.setText(fieldValue); sidebarElement.setText(collectionService.getMetadata(collection, "side_bar_text"));
element.addContent(sidebarElement); element.addContent(sidebarElement);
} }
fieldValue = collectionService.getMetadataFirstValue(collection, if (collectionService.getMetadata(collection, "license") != null) {
CollectionService.MD_LICENSE, Item.ANY);
if (fieldValue != null) {
Element sidebarElement = new Element("license"); Element sidebarElement = new Element("license");
sidebarElement.setText(fieldValue); sidebarElement.setText(collectionService.getMetadata(collection, "license"));
element.addContent(sidebarElement); element.addContent(sidebarElement);
} }
fieldValue = collectionService.getMetadataFirstValue(collection, if (collectionService.getMetadata(collection, "provenance_description") != null) {
CollectionService.MD_PROVENANCE_DESCRIPTION, Item.ANY);
if (fieldValue != null) {
Element sidebarElement = new Element("provenance"); Element sidebarElement = new Element("provenance");
sidebarElement.setText(fieldValue); sidebarElement.setText(collectionService.getMetadata(collection, "provenance_description"));
element.addContent(sidebarElement); element.addContent(sidebarElement);
} }
@@ -816,4 +538,5 @@ public class StructBuilder {
return elements; return elements;
} }
} }

View File

@@ -19,7 +19,6 @@ import org.dspace.content.Item;
* @author Stuart Lewis * @author Stuart Lewis
*/ */
public class BulkEditChange { public class BulkEditChange {
/** /**
* The item these changes relate to * The item these changes relate to
*/ */

View File

@@ -8,10 +8,14 @@
package org.dspace.app.bulkedit; package org.dspace.app.bulkedit;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStream; import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -23,8 +27,6 @@ import java.util.UUID;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authority.AuthorityValue; import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory; import org.dspace.authority.factory.AuthorityServiceFactory;
import org.dspace.authority.service.AuthorityValueService; import org.dspace.authority.service.AuthorityValueService;
@@ -32,7 +34,6 @@ import org.dspace.content.Collection;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices; import org.dspace.content.authority.Choices;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
@@ -138,18 +139,18 @@ public class DSpaceCSV implements Serializable {
/** /**
* Create a new instance, reading the lines in from file * Create a new instance, reading the lines in from file
* *
* @param inputStream the input stream to read from * @param f The file to read from
* @param c The DSpace Context * @param c The DSpace Context
* @throws Exception thrown if there is an error reading or processing the file * @throws Exception thrown if there is an error reading or processing the file
*/ */
public DSpaceCSV(InputStream inputStream, Context c) throws Exception { public DSpaceCSV(File f, Context c) throws Exception {
// Initialise the class // Initialise the class
init(); init();
// Open the CSV file // Open the CSV file
BufferedReader input = null; BufferedReader input = null;
try { try {
input = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); input = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
// Read the heading line // Read the heading line
String head = input.readLine(); String head = input.readLine();
@@ -159,7 +160,7 @@ public class DSpaceCSV implements Serializable {
columnCounter++; columnCounter++;
// Remove surrounding quotes if there are any // Remove surrounding quotes if there are any
if (element.startsWith("\"") && element.endsWith("\"")) { if ((element.startsWith("\"")) && (element.endsWith("\""))) {
element = element.substring(1, element.length() - 1); element = element.substring(1, element.length() - 1);
} }
@@ -167,23 +168,17 @@ public class DSpaceCSV implements Serializable {
if ("collection".equals(element)) { if ("collection".equals(element)) {
// Store the heading // Store the heading
headings.add(element); headings.add(element);
} else if ("rowName".equals(element)) {
// Store the heading
headings.add(element);
} else if ("action".equals(element)) { // Store the action } else if ("action".equals(element)) { // Store the action
// Store the heading // Store the heading
headings.add(element); headings.add(element);
} else if (!"id".equals(element)) { } else if (!"id".equals(element)) {
String authorityPrefix = ""; String authorityPrefix = "";
if (StringUtils.startsWith(element, "[authority]")) {
element = StringUtils.substringAfter(element, "[authority]");
AuthorityValue authorityValueType = authorityValueService.getAuthorityValueType(element); AuthorityValue authorityValueType = authorityValueService.getAuthorityValueType(element);
if (authorityValueType != null) { if (authorityValueType != null) {
String authorityType = authorityValueType.getAuthorityType(); String authorityType = authorityValueType.getAuthorityType();
authorityPrefix = element.substring(0, authorityType.length() + 1); authorityPrefix = element.substring(0, authorityType.length() + 1);
element = element.substring(authorityPrefix.length()); element = element.substring(authorityPrefix.length());
} }
}
// Verify that the heading is valid in the metadata registry // Verify that the heading is valid in the metadata registry
String[] clean = element.split("\\["); String[] clean = element.split("\\[");
@@ -203,12 +198,10 @@ public class DSpaceCSV implements Serializable {
} }
// Check that the scheme exists // Check that the scheme exists
if (!StringUtils.equals(metadataSchema, MetadataSchemaEnum.RELATION.getName())) {
MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema); MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema);
if (foundSchema == null) { if (foundSchema == null) {
throw new MetadataImportInvalidHeadingException(clean[0], throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException MetadataImportInvalidHeadingException.SCHEMA,
.SCHEMA,
columnCounter); columnCounter);
} }
@@ -217,11 +210,9 @@ public class DSpaceCSV implements Serializable {
.findByElement(c, foundSchema, metadataElement, metadataQualifier); .findByElement(c, foundSchema, metadataElement, metadataQualifier);
if (foundField == null) { if (foundField == null) {
throw new MetadataImportInvalidHeadingException(clean[0], throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException MetadataImportInvalidHeadingException.ELEMENT,
.ELEMENT,
columnCounter); columnCounter);
} }
}
// Store the heading // Store the heading
headings.add(authorityPrefix + element); headings.add(authorityPrefix + element);
@@ -306,7 +297,7 @@ public class DSpaceCSV implements Serializable {
// Specify default values // Specify default values
String[] defaultValues = String[] defaultValues =
new String[] { new String[] {
"dc.date.accessioned", "dc.date.available", "dc.date.updated", "dc.description.provenance" "dc.date.accessioned, dc.date.available, dc.date.updated, dc.description.provenance"
}; };
String[] toIgnoreArray = String[] toIgnoreArray =
DSpaceServicesFactory.getInstance() DSpaceServicesFactory.getInstance()
@@ -337,15 +328,15 @@ public class DSpaceCSV implements Serializable {
/** /**
* Set the value separator for multiple values stored in one csv value. * Set the value separator for multiple values stored in one csv value.
* *
* Is set in {@code bulkedit.cfg} as {@code valueseparator}. * Is set in bulkedit.cfg as valueseparator
* *
* If not set, defaults to double pipe '||'. * If not set, defaults to double pipe '||'
*/ */
private void setValueSeparator() { private void setValueSeparator() {
// Get the value separator // Get the value separator
valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService() valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.valueseparator"); .getProperty("bulkedit.valueseparator");
if ((valueSeparator != null) && !valueSeparator.trim().isEmpty()) { if ((valueSeparator != null) && (!"".equals(valueSeparator.trim()))) {
valueSeparator = valueSeparator.trim(); valueSeparator = valueSeparator.trim();
} else { } else {
valueSeparator = "||"; valueSeparator = "||";
@@ -360,7 +351,7 @@ public class DSpaceCSV implements Serializable {
/** /**
* Set the field separator use to separate fields in the csv. * Set the field separator use to separate fields in the csv.
* *
* Is set in {@code bulkedit.cfg} as {@code fieldseparator}. * Is set in bulkedit.cfg as fieldseparator
* *
* If not set, defaults to comma ','. * If not set, defaults to comma ','.
* *
@@ -371,7 +362,7 @@ public class DSpaceCSV implements Serializable {
// Get the value separator // Get the value separator
fieldSeparator = DSpaceServicesFactory.getInstance().getConfigurationService() fieldSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.fieldseparator"); .getProperty("bulkedit.fieldseparator");
if ((fieldSeparator != null) && !fieldSeparator.trim().isEmpty()) { if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim()))) {
fieldSeparator = fieldSeparator.trim(); fieldSeparator = fieldSeparator.trim();
if ("tab".equals(fieldSeparator)) { if ("tab".equals(fieldSeparator)) {
fieldSeparator = "\t"; fieldSeparator = "\t";
@@ -395,15 +386,15 @@ public class DSpaceCSV implements Serializable {
/** /**
* Set the authority separator for value with authority data. * Set the authority separator for value with authority data.
* *
* Is set in {@code dspace.cfg} as {@code bulkedit.authorityseparator}. * Is set in dspace.cfg as bulkedit.authorityseparator
* *
* If not set, defaults to double colon '::'. * If not set, defaults to double colon '::'
*/ */
private void setAuthoritySeparator() { private void setAuthoritySeparator() {
// Get the value separator // Get the value separator
authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService() authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("bulkedit.authorityseparator"); .getProperty("bulkedit.authorityseparator");
if ((authoritySeparator != null) && !authoritySeparator.trim().isEmpty()) { if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim()))) {
authoritySeparator = authoritySeparator.trim(); authoritySeparator = authoritySeparator.trim();
} else { } else {
authoritySeparator = "::"; authoritySeparator = "::";
@@ -508,7 +499,7 @@ public class DSpaceCSV implements Serializable {
int i = 0; int i = 0;
for (String part : bits) { for (String part : bits) {
int bitcounter = part.length() - part.replaceAll("\"", "").length(); int bitcounter = part.length() - part.replaceAll("\"", "").length();
if (part.startsWith("\"") && (!part.endsWith("\"") || ((bitcounter & 1) == 1))) { if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1))) {
found = true; found = true;
String add = bits.get(i) + fieldSeparator + bits.get(i + 1); String add = bits.get(i) + fieldSeparator + bits.get(i + 1);
bits.remove(i); bits.remove(i);
@@ -524,7 +515,7 @@ public class DSpaceCSV implements Serializable {
// Deal with quotes around the elements // Deal with quotes around the elements
int i = 0; int i = 0;
for (String part : bits) { for (String part : bits) {
if (part.startsWith("\"") && part.endsWith("\"")) { if ((part.startsWith("\"")) && (part.endsWith("\""))) {
part = part.substring(1, part.length() - 1); part = part.substring(1, part.length() - 1);
bits.set(i, part); bits.set(i, part);
} }
@@ -564,7 +555,7 @@ public class DSpaceCSV implements Serializable {
for (String part : bits) { for (String part : bits) {
if (i > 0) { if (i > 0) {
// Is this a last empty item? // Is this a last empty item?
if (last && (i == headings.size())) { if ((last) && (i == headings.size())) {
part = ""; part = "";
} }
@@ -577,7 +568,7 @@ public class DSpaceCSV implements Serializable {
csvLine.add(headings.get(i - 1), null); csvLine.add(headings.get(i - 1), null);
String[] elements = part.split(escapedValueSeparator); String[] elements = part.split(escapedValueSeparator);
for (String element : elements) { for (String element : elements) {
if ((element != null) && !element.isEmpty()) { if ((element != null) && (!"".equals(element))) {
csvLine.add(headings.get(i - 1), element); csvLine.add(headings.get(i - 1), element);
} }
} }
@@ -623,24 +614,30 @@ public class DSpaceCSV implements Serializable {
} }
/** /**
* Creates and returns an InputStream from the CSV Lines in this DSpaceCSV * Save the CSV file to the given filename
* @return The InputStream created from the CSVLines in this DSpaceCSV *
* @param filename The filename to save the CSV file to
* @throws IOException Thrown if an error occurs when writing the file
*/ */
public InputStream getInputStream() { public final void save(String filename) throws IOException {
StringBuilder stringBuilder = new StringBuilder(); // Save the file
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(filename), "UTF-8"));
for (String csvLine : getCSVLinesAsStringArray()) { for (String csvLine : getCSVLinesAsStringArray()) {
stringBuilder.append(csvLine).append("\n"); out.write(csvLine + "\n");
} }
return IOUtils.toInputStream(stringBuilder.toString(), StandardCharsets.UTF_8); out.flush();
out.close();
} }
/** /**
* Is it okay to export this value? When exportAll is set to false, we don't export * Is it Ok to export this value? When exportAll is set to false, we don't export
* some of the metadata elements. * some of the metadata elements.
* *
* The list can be configured via the key ignore-on-export in {@code bulkedit.cfg}. * The list can be configured via the key ignore-on-export in bulkedit.cfg
* *
* @param md The MetadataField to examine * @param md The Metadatum to examine
* @return Whether or not it is OK to export this element * @return Whether or not it is OK to export this element
*/ */
protected boolean okToExport(MetadataField md) { protected boolean okToExport(MetadataField md) {
@@ -649,8 +646,12 @@ public class DSpaceCSV implements Serializable {
if (md.getQualifier() != null) { if (md.getQualifier() != null) {
key += "." + md.getQualifier(); key += "." + md.getQualifier();
} }
if (ignore.get(key) != null) {
return false;
}
// Must be OK, so don't ignore // Must be OK, so don't ignore
return ignore.get(key) == null; return true;
} }
/** /**

View File

@@ -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.bulkedit;
import java.sql.SQLException;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.ArrayUtils;
import org.dspace.content.MetadataField;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace;
/**
* {@link DSpaceRunnable} implementation to delete all the values of the given
* metadata field.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class MetadataDeletion extends DSpaceRunnable<MetadataDeletionScriptConfiguration<MetadataDeletion>> {
private MetadataValueService metadataValueService;
private MetadataFieldService metadataFieldService;
private ConfigurationService configurationService;
private String metadataField;
private boolean list;
@Override
public void internalRun() throws Exception {
if (list) {
listErasableMetadata();
return;
}
Context context = new Context();
try {
context.turnOffAuthorisationSystem();
performMetadataValuesDeletion(context);
} finally {
context.restoreAuthSystemState();
context.complete();
}
}
private void listErasableMetadata() {
String[] erasableMetadata = getErasableMetadata();
if (ArrayUtils.isEmpty(erasableMetadata)) {
handler.logInfo("No fields has been configured to be cleared via bulk deletion");
} else {
handler.logInfo("The fields that can be bulk deleted are: " + String.join(", ", erasableMetadata));
}
}
private void performMetadataValuesDeletion(Context context) throws SQLException {
MetadataField field = metadataFieldService.findByString(context, metadataField, '.');
if (field == null) {
throw new IllegalArgumentException("No metadata field found with name " + metadataField);
}
if (!ArrayUtils.contains(getErasableMetadata(), metadataField)) {
throw new IllegalArgumentException("The given metadata field cannot be bulk deleted");
}
handler.logInfo(String.format("Deleting the field '%s' from all objects", metadataField));
metadataValueService.deleteByMetadataField(context, field);
}
private String[] getErasableMetadata() {
return configurationService.getArrayProperty("bulkedit.allow-bulk-deletion");
}
@Override
@SuppressWarnings("unchecked")
public MetadataDeletionScriptConfiguration<MetadataDeletion> getScriptConfiguration() {
return new DSpace().getServiceManager()
.getServiceByName("metadata-deletion", MetadataDeletionScriptConfiguration.class);
}
@Override
public void setup() throws ParseException {
metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
metadataField = commandLine.getOptionValue('m');
list = commandLine.hasOption('l');
if (!list && metadataField == null) {
throw new ParseException("One of the following parameters is required: -m or -l");
}
}
}

View File

@@ -1,18 +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.bulkedit;
/**
* The {@link MetadataDeletion} for CLI.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class MetadataDeletionCli extends MetadataDeletion {
}

View File

@@ -1,18 +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.bulkedit;
/**
* Script configuration for {@link MetadataDeletionCli}.
*
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*
*/
public class MetadataDeletionCliScriptConfiguration extends MetadataDeletionScriptConfiguration<MetadataDeletionCli> {
}

View File

@@ -1,68 +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.bulkedit;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link MetadataDeletion} script.
*/
public class MetadataDeletionScriptConfiguration<T extends MetadataDeletion> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> 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("m", "metadata", true, "metadata field name");
options.getOption("m").setType(String.class);
options.addOption("l", "list", false, "lists the metadata fields that can be deleted");
options.getOption("l").setType(boolean.class);
super.options = options;
}
return options;
}
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
/**
* Generic setter for the dspaceRunnableClass
* @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataDeletionScriptConfiguration
*/
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
}

View File

@@ -8,115 +8,271 @@
package org.dspace.app.bulkedit; package org.dspace.app.bulkedit;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.UUID; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.common.collect.Iterators;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.cli.PosixParser;
import org.dspace.app.util.factory.UtilServiceFactory; import org.dspace.content.Collection;
import org.dspace.app.util.service.DSpaceObjectUtils; import org.dspace.content.Community;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataDSpaceCsvExportService; import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.utils.DSpace;
/** /**
* Metadata exporter to allow the batch export of metadata into a file * Metadata exporter to allow the batch export of metadata into a file
* *
* @author Stuart Lewis * @author Stuart Lewis
*/ */
public class MetadataExport extends DSpaceRunnable<MetadataExportScriptConfiguration> { public class MetadataExport {
/**
* The items to export
*/
protected Iterator<Item> toExport;
private boolean help = false; protected ItemService itemService;
private String filename = null;
private String identifier = null;
private boolean exportAllMetadata = false;
private boolean exportAllItems = false;
private static final String EXPORT_CSV = "exportCSV"; protected Context context;
private MetadataDSpaceCsvExportService metadataDSpaceCsvExportService = new DSpace().getServiceManager() /**
.getServicesByType(MetadataDSpaceCsvExportService.class).get(0); * Whether to export all metadata, or just normally edited metadata
*/
protected boolean exportAll;
private EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected MetadataExport() {
itemService = ContentServiceFactory.getInstance().getItemService();
private DSpaceObjectUtils dSpaceObjectUtils = UtilServiceFactory.getInstance().getDSpaceObjectUtils();
@Override
public void internalRun() throws Exception {
if (help) {
logHelpInfo();
printHelp();
return;
} }
Context context = new Context();
context.turnOffAuthorisationSystem(); /**
* Set up a new metadata export
*
* @param c The Context
* @param toExport The ItemIterator of items to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Iterator<Item> toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
// Store the export settings
this.toExport = toExport;
this.exportAll = exportAll;
this.context = c;
}
/**
* Method to export a community (and sub-communities and collections)
*
* @param c The Context
* @param toExport The Community to export
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
*/
public MetadataExport(Context c, Community toExport, boolean exportAll) {
itemService = ContentServiceFactory.getInstance().getItemService();
try { try {
context.setCurrentUser(ePersonService.find(context, this.getEpersonIdentifier())); // Try to export the community
} catch (SQLException e) { this.toExport = buildFromCommunity(c, toExport, 0);
handler.handleException(e); this.exportAll = exportAll;
this.context = c;
} catch (SQLException sqle) {
// Something went wrong...
System.err.println("Error running exporter:");
sqle.printStackTrace(System.err);
System.exit(1);
} }
DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService
.handleExport(context, exportAllItems, exportAllMetadata, identifier,
handler);
handler.writeFilestream(context, filename, dSpaceCSV.getInputStream(), EXPORT_CSV);
context.restoreAuthSystemState();
context.complete();
} }
protected void logHelpInfo() { /**
handler.logInfo("\nfull export: metadata-export"); * Build an array list of item ids that are in a community (include sub-communities and collections)
handler.logInfo("partial export: metadata-export -i handle/UUID"); *
* @param context DSpace context
* @param community The community to build from
* @param indent How many spaces to use when writing out the names of items added
* @return The list of item ids
* @throws SQLException if database error
*/
protected Iterator<Item> buildFromCommunity(Context context, Community community, int indent)
throws SQLException {
// Add all the collections
List<Collection> collections = community.getCollections();
Iterator<Item> result = null;
for (Collection collection : collections) {
for (int i = 0; i < indent; i++) {
System.out.print(" ");
} }
@Override Iterator<Item> items = itemService.findByCollection(context, collection);
public MetadataExportScriptConfiguration getScriptConfiguration() { result = addItemsToResult(result, items);
return new DSpace().getServiceManager().getServiceByName("metadata-export",
MetadataExportScriptConfiguration.class);
}
@Override
public void setup() throws ParseException {
if (commandLine.hasOption('h')) {
help = true;
return;
}
if (!commandLine.hasOption('i')) {
exportAllItems = true;
}
identifier = commandLine.getOptionValue('i');
filename = getFileNameForExportFile();
exportAllMetadata = commandLine.hasOption('a');
} }
// Add all the sub-communities
protected String getFileNameForExportFile() throws ParseException { List<Community> communities = community.getSubcommunities();
Context context = new Context(); for (Community subCommunity : communities) {
try { for (int i = 0; i < indent; i++) {
DSpaceObject dso = null; System.out.print(" ");
if (StringUtils.isNotBlank(identifier)) {
dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, identifier);
if (dso == null) {
dso = dSpaceObjectUtils.findDSpaceObject(context, UUID.fromString(identifier));
} }
Iterator<Item> items = buildFromCommunity(context, subCommunity, indent + 1);
result = addItemsToResult(result, items);
}
return result;
}
private Iterator<Item> addItemsToResult(Iterator<Item> result, Iterator<Item> items) {
if (result == null) {
result = items;
} else { } else {
dso = ContentServiceFactory.getInstance().getSiteService().findSite(context); result = Iterators.concat(result, items);
} }
if (dso == null) {
throw new ParseException("An identifier was given that wasn't able to be parsed to a DSpaceObject"); return result;
} }
return dso.getID().toString() + ".csv";
} catch (SQLException e) { /**
handler.handleException("Something went wrong trying to retrieve DSO for identifier: " + identifier, e); * Run the export
*
* @return the exported CSV lines
*/
public DSpaceCSV export() {
try {
Context.Mode originalMode = context.getCurrentMode();
context.setMode(Context.Mode.READ_ONLY);
// Process each item
DSpaceCSV csv = new DSpaceCSV(exportAll);
while (toExport.hasNext()) {
Item item = toExport.next();
csv.addItem(item);
context.uncacheEntity(item);
} }
context.setMode(originalMode);
// Return the results
return csv;
} catch (Exception e) {
// Something went wrong...
System.err.println("Error exporting to CSV:");
e.printStackTrace();
return null; return null;
} }
} }
/**
* Print the help message
*
* @param options The command line options the user gave
* @param exitCode the system exit code to use
*/
private static void printHelp(Options options, int exitCode) {
// print the help message
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MetadataExport\n", options);
System.out.println("\nfull export: metadataexport -f filename");
System.out.println("partial export: metadataexport -i handle -f filename");
System.exit(exitCode);
}
/**
* main method to run the metadata exporter
*
* @param argv the command line arguments given
* @throws Exception if error occurs
*/
public static void main(String[] argv) throws Exception {
// Create an options object and populate it
CommandLineParser parser = new PosixParser();
Options options = new Options();
options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
options.addOption("f", "file", true, "destination where you want file written");
options.addOption("a", "all", false,
"include all metadata fields that are not normally changed (e.g. provenance)");
options.addOption("h", "help", false, "help");
CommandLine line = null;
try {
line = parser.parse(options, argv);
} catch (ParseException pe) {
System.err.println("Error with commands.");
printHelp(options, 1);
System.exit(0);
}
if (line.hasOption('h')) {
printHelp(options, 0);
}
// Check a filename is given
if (!line.hasOption('f')) {
System.err.println("Required parameter -f missing!");
printHelp(options, 1);
}
String filename = line.getOptionValue('f');
// Create a context
Context c = new Context(Context.Mode.READ_ONLY);
c.turnOffAuthorisationSystem();
// The things we'll export
Iterator<Item> toExport = null;
MetadataExport exporter = null;
// Export everything?
boolean exportAll = line.hasOption('a');
ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
// Check we have an item OK
ItemService itemService = contentServiceFactory.getItemService();
if (!line.hasOption('i')) {
System.out.println("Exporting whole repository WARNING: May take some time!");
exporter = new MetadataExport(c, itemService.findAll(c), exportAll);
} else {
String handle = line.getOptionValue('i');
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle);
if (dso == null) {
System.err.println("Item '" + handle + "' does not resolve to an item in your repository!");
printHelp(options, 1);
}
if (dso.getType() == Constants.ITEM) {
System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")");
List<Item> item = new ArrayList<>();
item.add((Item) dso);
exporter = new MetadataExport(c, item.iterator(), exportAll);
} else if (dso.getType() == Constants.COLLECTION) {
System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")");
Collection collection = (Collection) dso;
toExport = itemService.findByCollection(c, collection);
exporter = new MetadataExport(c, toExport, exportAll);
} else if (dso.getType() == Constants.COMMUNITY) {
System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")");
exporter = new MetadataExport(c, (Community) dso, exportAll);
} else {
System.err.println("Error identifying '" + handle + "'");
System.exit(1);
}
}
// Perform the export
DSpaceCSV csv = exporter.export();
// Save the files to the file
csv.save(filename);
// Finish off and tidy up
c.restoreAuthSystemState();
c.complete();
}
}

View File

@@ -1,33 +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.bulkedit;
import org.apache.commons.cli.ParseException;
public class MetadataExportCli extends MetadataExport {
@Override
protected String getFileNameForExportFile() {
return commandLine.getOptionValue('f');
}
@Override
public void setup() throws ParseException {
super.setup();
// Check a filename is given
if (!commandLine.hasOption('f')) {
throw new ParseException("Required parameter -f missing!");
}
}
@Override
protected void logHelpInfo() {
handler.logInfo("\nfull export: metadata-export -f filename");
handler.logInfo("partial export: metadata-export -i handle -f filename");
}
}

View File

@@ -1,26 +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.bulkedit;
import java.io.OutputStream;
import org.apache.commons.cli.Options;
public class MetadataExportCliScriptConfiguration extends MetadataExportScriptConfiguration<MetadataExportCli> {
@Override
public Options getOptions() {
Options options = super.getOptions();
options.addOption("f", "file", true, "destination where you want file written");
options.getOption("f").setType(OutputStream .class);
options.getOption("f").setRequired(true);
super.options = options;
return options;
}
}

View File

@@ -1,70 +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.bulkedit;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link MetadataExport} script
*/
public class MetadataExportScriptConfiguration<T extends MetadataExport> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
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 MetadataExportScriptConfiguration
*/
@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("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
options.getOption("i").setType(String.class);
options.addOption("a", "all", false,
"include all metadata fields that are not normally changed (e.g. provenance)");
options.getOption("a").setType(boolean.class);
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
super.options = options;
}
return options;
}
}

View File

@@ -1,68 +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.bulkedit;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.UUID;
import org.apache.commons.cli.ParseException;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
* CLI variant for the {@link MetadataImport} class
* This has been made so that we can specify the behaviour of the determineChanges method to be specific for the CLI
*/
public class MetadataImportCLI extends MetadataImport {
@Override
protected boolean determineChange(DSpaceRunnableHandler handler) throws IOException {
handler.logInfo("Do you want to make these changes? [y/n] ");
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
String yn = bufferedReader.readLine();
if ("y".equalsIgnoreCase(yn)) {
return true;
}
return false;
}
}
@Override
protected void assignCurrentUserInContext(Context context) throws ParseException {
try {
if (commandLine.hasOption('e')) {
EPerson eperson;
String e = commandLine.getOptionValue('e');
if (e.indexOf('@') != -1) {
eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, e);
} else {
eperson = EPersonServiceFactory.getInstance().getEPersonService().find(context, UUID.fromString(e));
}
if (eperson == null) {
throw new ParseException("Error, eperson cannot be found: " + e);
}
context.setCurrentUser(eperson);
}
} catch (Exception e) {
throw new ParseException("Unable to find DSpace user: " + e.getMessage());
}
}
@Override
public void setup() throws ParseException {
super.setup();
if (!commandLine.hasOption('e')) {
throw new ParseException("Required parameter -e missing!");
}
}
}

View File

@@ -1,27 +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.bulkedit;
import org.apache.commons.cli.Options;
import org.dspace.scripts.configuration.ScriptConfiguration;
/**
* The {@link ScriptConfiguration} for the {@link org.dspace.app.bulkedit.MetadataImportCLI} CLI script
*/
public class MetadataImportCliScriptConfiguration extends MetadataImportScriptConfiguration<MetadataImportCLI> {
@Override
public Options getOptions() {
Options options = super.getOptions();
options.addOption("e", "email", true, "email address or user id of user (required if adding new items)");
options.getOption("e").setType(String.class);
options.getOption("e").setRequired(true);
super.options = options;
return options;
}
}

View File

@@ -1,81 +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.bulkedit;
import java.io.InputStream;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The {@link ScriptConfiguration} for the {@link MetadataImport} script
*/
public class MetadataImportScriptConfiguration<T extends MetadataImport> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
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 MetadataImportScriptConfiguration
*/
@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("f", "file", true, "source file");
options.getOption("f").setType(InputStream.class);
options.getOption("f").setRequired(true);
options.addOption("s", "silent", false,
"silent operation - doesn't request confirmation of changes USE WITH CAUTION");
options.getOption("s").setType(boolean.class);
options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow");
options.getOption("w").setType(boolean.class);
options.addOption("n", "notify", false,
"notify - when adding new items using a workflow, send notification emails");
options.getOption("n").setType(boolean.class);
options.addOption("v", "validate-only", false,
"validate - just validate the csv, don't run the import");
options.getOption("v").setType(boolean.class);
options.addOption("t", "template", false,
"template - when adding new items, use the collection template (if it exists)");
options.getOption("t").setType(boolean.class);
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
super.options = options;
}
return options;
}
}

View File

@@ -17,13 +17,13 @@ import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option; import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.ParseException;
import org.apache.logging.log4j.LogManager; import org.apache.commons.cli.PosixParser;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.checker.BitstreamDispatcher; import org.dspace.checker.BitstreamDispatcher;
import org.dspace.checker.CheckerCommand; import org.dspace.checker.CheckerCommand;
import org.dspace.checker.HandleDispatcher; import org.dspace.checker.HandleDispatcher;
@@ -48,7 +48,7 @@ import org.dspace.core.Utils;
* @author Nathan Sarr * @author Nathan Sarr
*/ */
public final class ChecksumChecker { public final class ChecksumChecker {
private static final Logger LOG = LogManager.getLogger(ChecksumChecker.class); private static final Logger LOG = Logger.getLogger(ChecksumChecker.class);
private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
@@ -86,7 +86,7 @@ public final class ChecksumChecker {
*/ */
public static void main(String[] args) throws SQLException { public static void main(String[] args) throws SQLException {
// set up command line parser // set up command line parser
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
CommandLine line = null; CommandLine line = null;
// create an options object and populate it // create an options object and populate it
@@ -101,21 +101,19 @@ public final class ChecksumChecker {
options.addOption("a", "handle", true, "Specify a handle to check"); options.addOption("a", "handle", true, "Specify a handle to check");
options.addOption("v", "verbose", false, "Report all processing"); options.addOption("v", "verbose", false, "Report all processing");
Option option; OptionBuilder.withArgName("bitstream-ids").hasArgs().withDescription(
"Space separated list of bitstream ids");
Option useBitstreamIds = OptionBuilder.create('b');
option = Option.builder("b") options.addOption(useBitstreamIds);
.longOpt("bitstream-ids")
.hasArgs()
.desc("Space separated list of bitstream ids")
.build();
options.addOption(option);
option = Option.builder("p") options.addOption("p", "prune", false, "Prune configuration file");
.longOpt("prune") options.addOption(OptionBuilder
.optionalArg(true) .withArgName("prune")
.desc("Prune old results (optionally using specified properties file for configuration)") .hasOptionalArgs(1)
.build(); .withDescription(
options.addOption(option); "Prune old results (optionally using specified properties file for configuration)")
.create('p'));
try { try {
line = parser.parse(options, args); line = parser.parse(options, args);

View File

@@ -13,8 +13,11 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection; import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
@@ -33,223 +36,224 @@ import org.dspace.harvest.HarvestingException;
import org.dspace.harvest.OAIHarvester; import org.dspace.harvest.OAIHarvester;
import org.dspace.harvest.factory.HarvestServiceFactory; import org.dspace.harvest.factory.HarvestServiceFactory;
import org.dspace.harvest.service.HarvestedCollectionService; import org.dspace.harvest.service.HarvestedCollectionService;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.utils.DSpace;
/** /**
* Test class for harvested collections. * Test class for harvested collections.
* *
* @author Alexey Maslov * @author Alexey Maslov
*/ */
public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> { public class Harvest {
private static Context context;
private HarvestedCollectionService harvestedCollectionService; private static final HarvestedCollectionService harvestedCollectionService =
protected EPersonService ePersonService;
private CollectionService collectionService;
private boolean help;
private String command = null;
private String collection = null;
private String oaiSource = null;
private String oaiSetID = null;
private String metadataKey = null;
private int harvestType = 0;
protected Context context;
public HarvestScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager()
.getServiceByName("harvest", HarvestScriptConfiguration.class);
}
public void setup() throws ParseException {
harvestedCollectionService =
HarvestServiceFactory.getInstance().getHarvestedCollectionService(); HarvestServiceFactory.getInstance().getHarvestedCollectionService();
ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
collectionService = private static final CollectionService collectionService =
ContentServiceFactory.getInstance().getCollectionService(); ContentServiceFactory.getInstance().getCollectionService();
assignCurrentUserInContext(); public static void main(String[] argv) throws Exception {
// create an options object and populate it
CommandLineParser parser = new PosixParser();
help = commandLine.hasOption('h'); Options options = new Options();
options.addOption("p", "purge", false, "delete all items in the collection");
options.addOption("r", "run", false, "run the standard harvest procedure");
options.addOption("g", "ping", false, "test the OAI server and set");
options.addOption("o", "once", false, "run the harvest procedure with specified parameters");
options.addOption("s", "setup", false, "Set the collection up for harvesting");
options.addOption("S", "start", false, "start the harvest loop");
options.addOption("R", "reset", false, "reset harvest status on all collections");
options.addOption("P", "purge", false, "purge all harvestable collections");
if (commandLine.hasOption('s')) { options.addOption("e", "eperson", true,
"eperson");
options.addOption("c", "collection", true,
"harvesting collection (handle or id)");
options.addOption("t", "type", true,
"type of harvesting (0 for none)");
options.addOption("a", "address", true,
"address of the OAI-PMH server");
options.addOption("i", "oai_set_id", true,
"id of the PMH set representing the harvested collection");
options.addOption("m", "metadata_format", true,
"the name of the desired metadata format for harvesting, resolved to namespace and " +
"crosswalk in dspace.cfg");
options.addOption("h", "help", false, "help");
CommandLine line = parser.parse(options, argv);
String command = null;
String eperson = null;
String collection = null;
String oaiSource = null;
String oaiSetID = null;
String metadataKey = null;
int harvestType = 0;
if (line.hasOption('h')) {
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("Harvest\n", options);
System.out.println("\nPING OAI server: Harvest -g -a oai_source -i oai_set_id");
System.out.println(
"RUNONCE harvest with arbitrary options: Harvest -o -e eperson -c collection -t harvest_type -a " +
"oai_source -i oai_set_id -m metadata_format");
System.out.println(
"SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i " +
"oai_set_id -m metadata_format");
System.out.println("RUN harvest once: Harvest -r -e eperson -c collection");
System.out.println("START harvest scheduler: Harvest -S");
System.out.println("RESET all harvest status: Harvest -R");
System.out.println("PURGE a collection of items and settings: Harvest -p -e eperson -c collection");
System.out.println("PURGE all harvestable collections: Harvest -P -e eperson");
System.exit(0);
}
if (line.hasOption('s')) {
command = "config"; command = "config";
} }
if (commandLine.hasOption('p')) { if (line.hasOption('p')) {
command = "purge"; command = "purge";
} }
if (commandLine.hasOption('r')) { if (line.hasOption('r')) {
command = "run"; command = "run";
} }
if (commandLine.hasOption('g')) { if (line.hasOption('g')) {
command = "ping"; command = "ping";
} }
if (commandLine.hasOption('S')) { if (line.hasOption('o')) {
command = "runOnce";
}
if (line.hasOption('S')) {
command = "start"; command = "start";
} }
if (commandLine.hasOption('R')) { if (line.hasOption('R')) {
command = "reset"; command = "reset";
} }
if (commandLine.hasOption('P')) { if (line.hasOption('P')) {
command = "purgeAll"; command = "purgeAll";
} }
if (commandLine.hasOption('o')) {
command = "reimport";
if (line.hasOption('e')) {
eperson = line.getOptionValue('e');
} }
if (commandLine.hasOption('c')) { if (line.hasOption('c')) {
collection = commandLine.getOptionValue('c'); collection = line.getOptionValue('c');
} }
if (commandLine.hasOption('t')) { if (line.hasOption('t')) {
harvestType = Integer.parseInt(commandLine.getOptionValue('t')); harvestType = Integer.parseInt(line.getOptionValue('t'));
} else { } else {
harvestType = 0; harvestType = 0;
} }
if (commandLine.hasOption('a')) { if (line.hasOption('a')) {
oaiSource = commandLine.getOptionValue('a'); oaiSource = line.getOptionValue('a');
} }
if (commandLine.hasOption('i')) { if (line.hasOption('i')) {
oaiSetID = commandLine.getOptionValue('i'); oaiSetID = line.getOptionValue('i');
}
if (commandLine.hasOption('m')) {
metadataKey = commandLine.getOptionValue('m');
} }
if (line.hasOption('m')) {
metadataKey = line.getOptionValue('m');
} }
/**
* This method will assign the currentUser to the {@link Context} variable which is also created in this method.
* The instance of the method in this class will fetch the EPersonIdentifier from this class, this identifier
* was given to this class upon instantiation, it'll then be used to find the {@link EPerson} associated with it
* and this {@link EPerson} will be set as the currentUser of the created {@link Context}
* @throws ParseException If something went wrong with the retrieval of the EPerson Identifier
*/
protected void assignCurrentUserInContext() throws ParseException {
UUID currentUserUuid = this.getEpersonIdentifier();
try {
this.context = new Context(Context.Mode.BATCH_EDIT);
EPerson eperson = ePersonService.find(context, currentUserUuid);
if (eperson == null) {
super.handler.logError("EPerson not found: " + currentUserUuid);
throw new IllegalArgumentException("Unable to find a user with uuid: " + currentUserUuid);
}
this.context.setCurrentUser(eperson);
} catch (SQLException e) {
handler.handleException("Something went wrong trying to fetch eperson for uuid: " + currentUserUuid, e);
}
}
public void internalRun() throws Exception { // Instantiate our class
if (help) { Harvest harvester = new Harvest();
printHelp(); harvester.context = new Context(Context.Mode.BATCH_EDIT);
handler.logInfo("PING OAI server: Harvest -g -a oai_source -i oai_set_id");
handler.logInfo(
"SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i " +
"oai_set_id -m metadata_format");
handler.logInfo("RUN harvest once: Harvest -r -e eperson -c collection");
handler.logInfo("START harvest scheduler: Harvest -S");
handler.logInfo("RESET all harvest status: Harvest -R");
handler.logInfo("PURGE a collection of items and settings: Harvest -p -e eperson -c collection");
handler.logInfo("PURGE all harvestable collections: Harvest -P -e eperson");
return;
}
if (StringUtils.isBlank(command)) { // Check our options
handler.logError("No parameters specified (run with -h flag for details)"); if (command == null) {
throw new UnsupportedOperationException("No command specified"); System.out
.println("Error - no parameters specified (run with -h flag for details)");
System.exit(1);
} else if ("run".equals(command)) { } else if ("run".equals(command)) {
// Run a single harvest cycle on a collection using saved settings. // Run a single harvest cycle on a collection using saved settings.
if (collection == null || context.getCurrentUser() == null) { if (collection == null || eperson == null) {
handler.logError("A target collection and eperson must be provided (run with -h flag for details)"); System.out
throw new UnsupportedOperationException("A target collection and eperson must be provided"); .println("Error - a target collection and eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
} }
runHarvest(context, collection);
harvester.runHarvest(collection, eperson);
} else if ("start".equals(command)) { } else if ("start".equals(command)) {
// start the harvest loop // start the harvest loop
startHarvester(); startHarvester();
} else if ("reset".equals(command)) { } else if ("reset".equals(command)) {
// reset harvesting status // reset harvesting status
resetHarvesting(context); resetHarvesting();
} else if ("purgeAll".equals(command)) { } else if ("purgeAll".equals(command)) {
// purge all collections that are set up for harvesting (obviously for testing purposes only) // purge all collections that are set up for harvesting (obviously for testing purposes only)
if (context.getCurrentUser() == null) { if (eperson == null) {
handler.logError("An eperson must be provided (run with -h flag for details)"); System.out
throw new UnsupportedOperationException("An eperson must be provided"); .println("Error - an eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
} }
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context); List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
for (HarvestedCollection harvestedCollection : harvestedCollections) { for (HarvestedCollection harvestedCollection : harvestedCollections) {
handler.logInfo( System.out.println(
"Purging the following collections (deleting items and resetting harvest status): " + "Purging the following collections (deleting items and resetting harvest status): " +
harvestedCollection harvestedCollection
.getCollection().getID().toString()); .getCollection().getID().toString());
purgeCollection(context, harvestedCollection.getCollection().getID().toString()); harvester.purgeCollection(harvestedCollection.getCollection().getID().toString(), eperson);
} }
context.complete(); context.complete();
} else if ("purge".equals(command)) { } else if ("purge".equals(command)) {
// Delete all items in a collection. Useful for testing fresh harvests. // Delete all items in a collection. Useful for testing fresh harvests.
if (collection == null || context.getCurrentUser() == null) { if (collection == null || eperson == null) {
handler.logError("A target collection and eperson must be provided (run with -h flag for details)"); System.out
throw new UnsupportedOperationException("A target collection and eperson must be provided"); .println("Error - a target collection and eperson must be provided");
System.out.println(" (run with -h flag for details)");
System.exit(1);
} }
purgeCollection(context, collection); harvester.purgeCollection(collection, eperson);
context.complete();
} else if ("reimport".equals(command)) {
// Delete all items in a collection. Useful for testing fresh harvests.
if (collection == null || context.getCurrentUser() == null) {
handler.logError("A target collection and eperson must be provided (run with -h flag for details)");
throw new UnsupportedOperationException("A target collection and eperson must be provided");
}
purgeCollection(context, collection);
runHarvest(context, collection);
context.complete(); context.complete();
//TODO: implement this... remove all items and remember to unset "last-harvested" settings
} else if ("config".equals(command)) { } else if ("config".equals(command)) {
// Configure a collection with the three main settings // Configure a collection with the three main settings
if (collection == null) { if (collection == null) {
handler.logError("A target collection must be provided (run with -h flag for details)"); System.out.println("Error - a target collection must be provided");
throw new UnsupportedOperationException("A target collection must be provided"); System.out.println(" (run with -h flag for details)");
System.exit(1);
} }
if (oaiSource == null || oaiSetID == null) { if (oaiSource == null || oaiSetID == null) {
handler.logError( System.out.println("Error - both the OAI server address and OAI set id must be specified");
"Both the OAI server address and OAI set id must be specified (run with -h flag for details)"); System.out.println(" (run with -h flag for details)");
throw new UnsupportedOperationException("Both the OAI server address and OAI set id must be specified"); System.exit(1);
} }
if (metadataKey == null) { if (metadataKey == null) {
handler.logError( System.out
"A metadata key (commonly the prefix) must be specified for this collection (run with -h flag" + .println("Error - a metadata key (commonly the prefix) must be specified for this collection");
" for details)"); System.out.println(" (run with -h flag for details)");
throw new UnsupportedOperationException( System.exit(1);
"A metadata key (commonly the prefix) must be specified for this collection");
} }
configureCollection(context, collection, harvestType, oaiSource, oaiSetID, metadataKey); harvester.configureCollection(collection, harvestType, oaiSource, oaiSetID, metadataKey);
} else if ("ping".equals(command)) { } else if ("ping".equals(command)) {
if (oaiSource == null || oaiSetID == null) { if (oaiSource == null || oaiSetID == null) {
handler.logError( System.out.println("Error - both the OAI server address and OAI set id must be specified");
"Both the OAI server address and OAI set id must be specified (run with -h flag for details)"); System.out.println(" (run with -h flag for details)");
throw new UnsupportedOperationException("Both the OAI server address and OAI set id must be specified"); System.exit(1);
} }
pingResponder(oaiSource, oaiSetID, metadataKey); pingResponder(oaiSource, oaiSetID, metadataKey);
} else {
handler.logError(
"Your command '" + command + "' was not recognized properly (run with -h flag for details)");
throw new UnsupportedOperationException("Your command '" + command + "' was not recognized properly");
} }
} }
/* /*
* Resolve the ID into a collection and check to see if its harvesting options are set. If so, return * Resolve the ID into a collection and check to see if its harvesting options are set. If so, return
* the collection, if not, bail out. * the collection, if not, bail out.
*/ */
private Collection resolveCollection(Context context, String collectionID) { private Collection resolveCollection(String collectionID) {
DSpaceObject dso; DSpaceObject dso;
Collection targetCollection = null; Collection targetCollection = null;
@@ -268,15 +272,16 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
targetCollection = (Collection) dso; targetCollection = (Collection) dso;
} }
} else { } else {
// not a handle, try and treat it as an collection database UUID // not a handle, try and treat it as an integer collection database ID
handler.logInfo("Looking up by UUID: " + collectionID + ", " + "in context: " + context); System.out.println("Looking up by id: " + collectionID + ", parsed as '" + Integer
.parseInt(collectionID) + "', " + "in context: " + context);
targetCollection = collectionService.find(context, UUID.fromString(collectionID)); targetCollection = collectionService.find(context, UUID.fromString(collectionID));
} }
} }
// was the collection valid? // was the collection valid?
if (targetCollection == null) { if (targetCollection == null) {
handler.logError("Cannot resolve " + collectionID + " to collection"); System.out.println("Cannot resolve " + collectionID + " to collection");
throw new UnsupportedOperationException("Cannot resolve " + collectionID + " to collection"); System.exit(1);
} }
} catch (SQLException se) { } catch (SQLException se) {
se.printStackTrace(); se.printStackTrace();
@@ -286,12 +291,12 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
} }
private void configureCollection(Context context, String collectionID, int type, String oaiSource, String oaiSetId, private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId,
String mdConfigId) { String mdConfigId) {
handler.logInfo("Running: configure collection"); System.out.println("Running: configure collection");
Collection collection = resolveCollection(context, collectionID); Collection collection = resolveCollection(collectionID);
handler.logInfo(String.valueOf(collection.getID())); System.out.println(collection.getID());
try { try {
HarvestedCollection hc = harvestedCollectionService.find(context, collection); HarvestedCollection hc = harvestedCollectionService.find(context, collection);
@@ -306,8 +311,9 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
context.restoreAuthSystemState(); context.restoreAuthSystemState();
context.complete(); context.complete();
} catch (Exception e) { } catch (Exception e) {
handler.logError("Changes could not be committed"); System.out.println("Changes could not be committed");
handler.handleException(e); e.printStackTrace();
System.exit(1);
} finally { } finally {
if (context != null) { if (context != null) {
context.restoreAuthSystemState(); context.restoreAuthSystemState();
@@ -318,15 +324,18 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
/** /**
* Purges a collection of all harvest-related data and settings. All items in the collection will be deleted. * Purges a collection of all harvest-related data and settings. All items in the collection will be deleted.
* @param collectionID
* *
* @param collectionID
* @param email
*/ */
private void purgeCollection(Context context, String collectionID) { private void purgeCollection(String collectionID, String email) {
handler.logInfo( System.out.println(
"Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID); "Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID);
Collection collection = resolveCollection(context, collectionID); Collection collection = resolveCollection(collectionID);
try { try {
EPerson eperson = ePersonService.findByEmail(context, email);
context.setCurrentUser(eperson);
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
ItemService itemService = ContentServiceFactory.getInstance().getItemService(); ItemService itemService = ContentServiceFactory.getInstance().getItemService();
@@ -335,7 +344,7 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
while (it.hasNext()) { while (it.hasNext()) {
i++; i++;
Item item = it.next(); Item item = it.next();
handler.logInfo("Deleting: " + item.getHandle()); System.out.println("Deleting: " + item.getHandle());
collectionService.removeItem(context, collection, item); collectionService.removeItem(context, collection, item);
context.uncacheEntity(item);// Dispatch events every 50 items context.uncacheEntity(item);// Dispatch events every 50 items
if (i % 50 == 0) { if (i % 50 == 0) {
@@ -355,8 +364,9 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
context.restoreAuthSystemState(); context.restoreAuthSystemState();
context.dispatchEvents(); context.dispatchEvents();
} catch (Exception e) { } catch (Exception e) {
handler.logError("Changes could not be committed"); System.out.println("Changes could not be committed");
handler.handleException(e); e.printStackTrace();
System.exit(1);
} finally { } finally {
context.restoreAuthSystemState(); context.restoreAuthSystemState();
} }
@@ -366,42 +376,50 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
/** /**
* Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson * Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson
*/ */
private void runHarvest(Context context, String collectionID) { private void runHarvest(String collectionID, String email) {
handler.logInfo("Running: a harvest cycle on " + collectionID); System.out.println("Running: a harvest cycle on " + collectionID);
handler.logInfo("Initializing the harvester... "); System.out.print("Initializing the harvester... ");
OAIHarvester harvester = null; OAIHarvester harvester = null;
try { try {
Collection collection = resolveCollection(context, collectionID); Collection collection = resolveCollection(collectionID);
HarvestedCollection hc = harvestedCollectionService.find(context, collection); HarvestedCollection hc = harvestedCollectionService.find(context, collection);
harvester = new OAIHarvester(context, collection, hc); harvester = new OAIHarvester(context, collection, hc);
handler.logInfo("Initialized the harvester successfully"); System.out.println("success. ");
} catch (HarvestingException hex) { } catch (HarvestingException hex) {
handler.logError("Initializing the harvester failed."); System.out.print("failed. ");
System.out.println(hex.getMessage());
throw new IllegalStateException("Unable to harvest", hex); throw new IllegalStateException("Unable to harvest", hex);
} catch (SQLException se) { } catch (SQLException se) {
handler.logError("Initializing the harvester failed."); System.out.print("failed. ");
System.out.println(se.getMessage());
throw new IllegalStateException("Unable to access database", se); throw new IllegalStateException("Unable to access database", se);
} }
try { try {
// Harvest will not work for an anonymous user // Harvest will not work for an anonymous user
handler.logInfo("Harvest started... "); EPerson eperson = ePersonService.findByEmail(context, email);
System.out.println("Harvest started... ");
context.setCurrentUser(eperson);
harvester.runHarvest(); harvester.runHarvest();
context.complete(); context.complete();
} catch (SQLException | AuthorizeException | IOException e) { } catch (SQLException e) {
throw new IllegalStateException("Failed to run harvester", e);
} catch (AuthorizeException e) {
throw new IllegalStateException("Failed to run harvester", e);
} catch (IOException e) {
throw new IllegalStateException("Failed to run harvester", e); throw new IllegalStateException("Failed to run harvester", e);
} }
handler.logInfo("Harvest complete. "); System.out.println("Harvest complete. ");
} }
/** /**
* Resets harvest_status and harvest_start_time flags for all collections that have a row in the * Resets harvest_status and harvest_start_time flags for all collections that have a row in the
* harvested_collections table * harvested_collections table
*/ */
private void resetHarvesting(Context context) { private static void resetHarvesting() {
handler.logInfo("Resetting harvest status flag on all collections... "); System.out.print("Resetting harvest status flag on all collections... ");
try { try {
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context); List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
@@ -411,21 +429,21 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
harvestedCollection.setHarvestStatus(HarvestedCollection.STATUS_READY); harvestedCollection.setHarvestStatus(HarvestedCollection.STATUS_READY);
harvestedCollectionService.update(context, harvestedCollection); harvestedCollectionService.update(context, harvestedCollection);
} }
handler.logInfo("Reset harvest status flag successfully"); System.out.println("success. ");
} catch (Exception ex) { } catch (Exception ex) {
handler.logError("Resetting harvest status flag failed"); System.out.println("failed. ");
handler.handleException(ex); ex.printStackTrace();
} }
} }
/** /**
* Starts up the harvest scheduler. Terminating this process will stop the scheduler. * Starts up the harvest scheduler. Terminating this process will stop the scheduler.
*/ */
private void startHarvester() { private static void startHarvester() {
try { try {
handler.logInfo("Starting harvest loop... "); System.out.print("Starting harvest loop... ");
HarvestServiceFactory.getInstance().getHarvestSchedulingService().startNewScheduler(); HarvestServiceFactory.getInstance().getHarvestSchedulingService().startNewScheduler();
handler.logInfo("running. "); System.out.println("running. ");
} catch (Exception ex) { } catch (Exception ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
@@ -438,31 +456,29 @@ public class Harvest extends DSpaceRunnable<HarvestScriptConfiguration> {
* @param set name of an item set. * @param set name of an item set.
* @param metadataFormat local prefix name, or null for "dc". * @param metadataFormat local prefix name, or null for "dc".
*/ */
private void pingResponder(String server, String set, String metadataFormat) { private static void pingResponder(String server, String set, String metadataFormat) {
List<String> errors; List<String> errors;
handler.logInfo("Testing basic PMH access: "); System.out.print("Testing basic PMH access: ");
errors = harvestedCollectionService.verifyOAIharvester(server, set, errors = OAIHarvester.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", false); (null != metadataFormat) ? metadataFormat : "dc", false);
if (errors.isEmpty()) { if (errors.isEmpty()) {
handler.logInfo("OK"); System.out.println("OK");
} else { } else {
for (String error : errors) { for (String error : errors) {
handler.logError(error); System.err.println(error);
} }
} }
handler.logInfo("Testing ORE support: "); System.out.print("Testing ORE support: ");
errors = harvestedCollectionService.verifyOAIharvester(server, set, errors = OAIHarvester.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", true); (null != metadataFormat) ? metadataFormat : "dc", true);
if (errors.isEmpty()) { if (errors.isEmpty()) {
handler.logInfo("OK"); System.out.println("OK");
} else { } else {
for (String error : errors) { for (String error : errors) {
handler.logError(error); System.err.println(error);
} }
} }
} }
} }

View File

@@ -1,45 +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.harvest;
import java.sql.SQLException;
import org.apache.commons.cli.ParseException;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
public class HarvestCli extends Harvest {
/**
* This is the overridden instance of the {@link Harvest#assignCurrentUserInContext()} method in the parent class
* {@link Harvest}.
* This is done so that the CLI version of the Script is able to retrieve its currentUser from the -e flag given
* with the parameters of the Script.
*
* @throws ParseException If the e flag was not given to the parameters when calling the script
*/
@Override
protected void assignCurrentUserInContext() throws ParseException {
if (this.commandLine.hasOption('e')) {
String ePersonEmail = this.commandLine.getOptionValue('e');
this.context = new Context(Context.Mode.BATCH_EDIT);
try {
EPerson ePerson = ePersonService.findByEmail(this.context, ePersonEmail);
if (ePerson == null) {
super.handler.logError("EPerson not found: " + ePersonEmail);
throw new IllegalArgumentException("Unable to find a user with email: " + ePersonEmail);
}
this.context.setCurrentUser(ePerson);
} catch (SQLException e) {
throw new IllegalArgumentException("SQLException trying to find user with email: " + ePersonEmail);
}
}
}
}

View File

@@ -1,22 +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.harvest;
import org.apache.commons.cli.Options;
public class HarvestCliScriptConfiguration extends HarvestScriptConfiguration {
public Options getOptions() {
Options options = super.getOptions();
options.addOption("e", "eperson", true,
"eperson");
return options;
}
}

View File

@@ -1,79 +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.harvest;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
public class HarvestScriptConfiguration<T extends Harvest> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
public boolean isAllowedToExecute(final 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);
}
}
public Options getOptions() {
Options options = new Options();
options.addOption("p", "purge", false, "delete all items in the collection");
options.getOption("p").setType(boolean.class);
options.addOption("r", "run", false, "run the standard harvest procedure");
options.getOption("r").setType(boolean.class);
options.addOption("g", "ping", false, "test the OAI server and set");
options.getOption("g").setType(boolean.class);
options.addOption("s", "setup", false, "Set the collection up for harvesting");
options.getOption("s").setType(boolean.class);
options.addOption("S", "start", false, "start the harvest loop");
options.getOption("S").setType(boolean.class);
options.addOption("R", "reset", false, "reset harvest status on all collections");
options.getOption("R").setType(boolean.class);
options.addOption("P", "purgeCollections", false, "purge all harvestable collections");
options.getOption("P").setType(boolean.class);
options.addOption("o", "reimport", false, "reimport all items in the collection, " +
"this is equivalent to -p -r, purging all items in a collection and reimporting them");
options.getOption("o").setType(boolean.class);
options.addOption("c", "collection", true,
"harvesting collection (handle or id)");
options.addOption("t", "type", true,
"type of harvesting (0 for none)");
options.addOption("a", "address", true,
"address of the OAI-PMH server");
options.addOption("i", "oai_set_id", true,
"id of the PMH set representing the harvested collection");
options.addOption("m", "metadata_format", true,
"the name of the desired metadata format for harvesting, resolved to namespace and " +
"crosswalk in dspace.cfg");
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
return options;
}
}

View File

@@ -15,9 +15,9 @@ import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.app.itemexport.factory.ItemExportServiceFactory; import org.dspace.app.itemexport.factory.ItemExportServiceFactory;
import org.dspace.app.itemexport.service.ItemExportService; import org.dspace.app.itemexport.service.ItemExportService;
import org.dspace.content.Collection; import org.dspace.content.Collection;
@@ -69,7 +69,7 @@ public class ItemExportCLITool {
*/ */
public static void main(String[] argv) throws Exception { public static void main(String[] argv) throws Exception {
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();

View File

@@ -16,7 +16,6 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@@ -33,8 +32,8 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.itemexport.service.ItemExportService; import org.dspace.app.itemexport.service.ItemExportService;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.Bundle; import org.dspace.content.Bundle;
@@ -43,21 +42,21 @@ import org.dspace.content.Community;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchemaEnum; import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CommunityService; import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.Email; import org.dspace.core.Email;
import org.dspace.core.I18nUtil; import org.dspace.core.I18nUtil;
import org.dspace.core.LogHelper; import org.dspace.core.LogManager;
import org.dspace.core.Utils; import org.dspace.core.Utils;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -94,14 +93,12 @@ public class ItemExportServiceImpl implements ItemExportService {
protected ItemService itemService; protected ItemService itemService;
@Autowired(required = true) @Autowired(required = true)
protected HandleService handleService; protected HandleService handleService;
@Autowired(required = true)
protected ConfigurationService configurationService;
/** /**
* log4j logger * log4j logger
*/ */
private final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemExportServiceImpl.class); private Logger log = Logger.getLogger(ItemExportServiceImpl.class);
protected ItemExportServiceImpl() { protected ItemExportServiceImpl() {
@@ -130,7 +127,7 @@ public class ItemExportServiceImpl implements ItemExportService {
while (i.hasNext()) { while (i.hasNext()) {
if (SUBDIR_LIMIT > 0 && ++counter == SUBDIR_LIMIT) { if (SUBDIR_LIMIT > 0 && ++counter == SUBDIR_LIMIT) {
subdir = Integer.toString(subDirSuffix++); subdir = Integer.valueOf(subDirSuffix++).toString();
fullPath = destDirName + File.separatorChar + subdir; fullPath = destDirName + File.separatorChar + subdir;
counter = 0; counter = 0;
@@ -192,7 +189,7 @@ public class ItemExportServiceImpl implements ItemExportService {
*/ */
protected void writeMetadata(Context c, Item i, File destDir, boolean migrate) protected void writeMetadata(Context c, Item i, File destDir, boolean migrate)
throws Exception { throws Exception {
Set<String> schemas = new HashSet<>(); Set<String> schemas = new HashSet<String>();
List<MetadataValue> dcValues = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY); List<MetadataValue> dcValues = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
for (MetadataValue metadataValue : dcValues) { for (MetadataValue metadataValue : dcValues) {
schemas.add(metadataValue.getMetadataField().getMetadataSchema().getName()); schemas.add(metadataValue.getMetadataField().getMetadataSchema().getName());
@@ -217,7 +214,7 @@ public class ItemExportServiceImpl implements ItemExportService {
protected void writeMetadata(Context c, String schema, Item i, protected void writeMetadata(Context c, String schema, Item i,
File destDir, boolean migrate) throws Exception { File destDir, boolean migrate) throws Exception {
String filename; String filename;
if (schema.equals(MetadataSchemaEnum.DC.getName())) { if (schema.equals(MetadataSchema.DC_SCHEMA)) {
filename = "dublin_core.xml"; filename = "dublin_core.xml";
} else { } else {
filename = "metadata_" + schema + ".xml"; filename = "metadata_" + schema + ".xml";
@@ -268,14 +265,15 @@ public class ItemExportServiceImpl implements ItemExportService {
+ Utils.addEntities(dcv.getValue()) + "</dcvalue>\n") + Utils.addEntities(dcv.getValue()) + "</dcvalue>\n")
.getBytes("UTF-8"); .getBytes("UTF-8");
if (!migrate || if ((!migrate) ||
(migrate && !( (migrate && !(
("date".equals(metadataField.getElement()) && "issued".equals(qualifier)) || ("date".equals(metadataField.getElement()) && "issued".equals(qualifier)) ||
("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier)) || ("date".equals(metadataField.getElement()) && "accessioned".equals(qualifier)) ||
("date".equals(metadataField.getElement()) && "available".equals(qualifier)) || ("date".equals(metadataField.getElement()) && "available".equals(qualifier)) ||
("identifier".equals(metadataField.getElement()) && "uri".equals(qualifier) && ("identifier".equals(metadataField.getElement()) && "uri".equals(qualifier) &&
(dcv.getValue() != null && dcv.getValue().startsWith( (dcv.getValue() != null && dcv.getValue().startsWith("http://hdl.handle.net/" +
handleService.getCanonicalPrefix() + handleService.getPrefix() + "/"))) || handleService
.getPrefix() + "/"))) ||
("description".equals(metadataField.getElement()) && "provenance".equals(qualifier)) || ("description".equals(metadataField.getElement()) && "provenance".equals(qualifier)) ||
("format".equals(metadataField.getElement()) && "extent".equals(qualifier)) || ("format".equals(metadataField.getElement()) && "extent".equals(qualifier)) ||
("format".equals(metadataField.getElement()) && "mimetype".equals(qualifier))))) { ("format".equals(metadataField.getElement()) && "mimetype".equals(qualifier))))) {
@@ -293,10 +291,10 @@ public class ItemExportServiceImpl implements ItemExportService {
} }
// When migrating, only keep date.issued if it is different to date.accessioned // When migrating, only keep date.issued if it is different to date.accessioned
if (migrate && if ((migrate) &&
(dateIssued != null) && (dateIssued != null) &&
(dateAccessioned != null) && (dateAccessioned != null) &&
!dateIssued.equals(dateAccessioned)) { (!dateIssued.equals(dateAccessioned))) {
utf8 = (" <dcvalue element=\"date\" " utf8 = (" <dcvalue element=\"date\" "
+ "qualifier=\"issued\">" + "qualifier=\"issued\">"
+ Utils.addEntities(dateIssued) + "</dcvalue>\n") + Utils.addEntities(dateIssued) + "</dcvalue>\n")
@@ -331,7 +329,7 @@ public class ItemExportServiceImpl implements ItemExportService {
File outFile = new File(destDir, filename); File outFile = new File(destDir, filename);
if (outFile.createNewFile()) { if (outFile.createNewFile()) {
PrintWriter out = new PrintWriter(new FileWriter(outFile, StandardCharsets.UTF_8)); PrintWriter out = new PrintWriter(new FileWriter(outFile));
out.println(i.getHandle()); out.println(i.getHandle());
@@ -361,7 +359,7 @@ public class ItemExportServiceImpl implements ItemExportService {
File outFile = new File(destDir, "contents"); File outFile = new File(destDir, "contents");
if (outFile.createNewFile()) { if (outFile.createNewFile()) {
PrintWriter out = new PrintWriter(new FileWriter(outFile, StandardCharsets.UTF_8)); PrintWriter out = new PrintWriter(new FileWriter(outFile));
List<Bundle> bundles = i.getBundles(); List<Bundle> bundles = i.getBundles();
@@ -475,7 +473,7 @@ public class ItemExportServiceImpl implements ItemExportService {
public void createDownloadableExport(DSpaceObject dso, public void createDownloadableExport(DSpaceObject dso,
Context context, boolean migrate) throws Exception { Context context, boolean migrate) throws Exception {
EPerson eperson = context.getCurrentUser(); EPerson eperson = context.getCurrentUser();
ArrayList<DSpaceObject> list = new ArrayList<>(1); ArrayList<DSpaceObject> list = new ArrayList<DSpaceObject>(1);
list.add(dso); list.add(dso);
processDownloadableExport(list, context, eperson == null ? null processDownloadableExport(list, context, eperson == null ? null
: eperson.getEmail(), migrate); : eperson.getEmail(), migrate);
@@ -492,7 +490,7 @@ public class ItemExportServiceImpl implements ItemExportService {
@Override @Override
public void createDownloadableExport(DSpaceObject dso, public void createDownloadableExport(DSpaceObject dso,
Context context, String additionalEmail, boolean migrate) throws Exception { Context context, String additionalEmail, boolean migrate) throws Exception {
ArrayList<DSpaceObject> list = new ArrayList<>(1); ArrayList<DSpaceObject> list = new ArrayList<DSpaceObject>(1);
list.add(dso); list.add(dso);
processDownloadableExport(list, context, additionalEmail, migrate); processDownloadableExport(list, context, additionalEmail, migrate);
} }
@@ -549,7 +547,7 @@ public class ItemExportServiceImpl implements ItemExportService {
List<Bitstream> bitstreams = bundle.getBitstreams(); List<Bitstream> bitstreams = bundle.getBitstreams();
for (Bitstream bitstream : bitstreams) { for (Bitstream bitstream : bitstreams) {
// add up the size // add up the size
size += bitstream.getSizeBytes(); size += bitstream.getSize();
} }
} }
items.add(item.getID()); items.add(item.getID());
@@ -576,7 +574,7 @@ public class ItemExportServiceImpl implements ItemExportService {
List<Bitstream> bitstreams = bundle.getBitstreams(); List<Bitstream> bitstreams = bundle.getBitstreams();
for (Bitstream bitstream : bitstreams) { for (Bitstream bitstream : bitstreams) {
// add up the size // add up the size
size += bitstream.getSizeBytes(); size += bitstream.getSize();
} }
} }
items.add(item.getID()); items.add(item.getID());
@@ -595,7 +593,7 @@ public class ItemExportServiceImpl implements ItemExportService {
List<Bitstream> bitstreams = bundle.getBitstreams(); List<Bitstream> bitstreams = bundle.getBitstreams();
for (Bitstream bitstream : bitstreams) { for (Bitstream bitstream : bitstreams) {
// add up the size // add up the size
size += bitstream.getSizeBytes(); size += bitstream.getSize();
} }
} }
ArrayList<UUID> items = new ArrayList<>(); ArrayList<UUID> items = new ArrayList<>();
@@ -608,7 +606,7 @@ public class ItemExportServiceImpl implements ItemExportService {
// check the size of all the bitstreams against the configuration file // check the size of all the bitstreams against the configuration file
// entry if it exists // entry if it exists
String megaBytes = configurationService String megaBytes = ConfigurationManager
.getProperty("org.dspace.app.itemexport.max.size"); .getProperty("org.dspace.app.itemexport.max.size");
if (megaBytes != null) { if (megaBytes != null) {
float maxSize = 0; float maxSize = 0;
@@ -653,7 +651,7 @@ public class ItemExportServiceImpl implements ItemExportService {
while (iter.hasNext()) { while (iter.hasNext()) {
String keyName = iter.next(); String keyName = iter.next();
List<UUID> uuids = itemsMap.get(keyName); List<UUID> uuids = itemsMap.get(keyName);
List<Item> items = new ArrayList<>(); List<Item> items = new ArrayList<Item>();
for (UUID uuid : uuids) { for (UUID uuid : uuids) {
items.add(itemService.find(context, uuid)); items.add(itemService.find(context, uuid));
} }
@@ -733,7 +731,7 @@ public class ItemExportServiceImpl implements ItemExportService {
@Override @Override
public String getExportDownloadDirectory(EPerson ePerson) public String getExportDownloadDirectory(EPerson ePerson)
throws Exception { throws Exception {
String downloadDir = configurationService String downloadDir = ConfigurationManager
.getProperty("org.dspace.app.itemexport.download.dir"); .getProperty("org.dspace.app.itemexport.download.dir");
if (downloadDir == null) { if (downloadDir == null) {
throw new Exception( throw new Exception(
@@ -750,7 +748,7 @@ public class ItemExportServiceImpl implements ItemExportService {
@Override @Override
public String getExportWorkDirectory() throws Exception { public String getExportWorkDirectory() throws Exception {
String exportDir = configurationService String exportDir = ConfigurationManager
.getProperty("org.dspace.app.itemexport.work.dir"); .getProperty("org.dspace.app.itemexport.work.dir");
if (exportDir == null) { if (exportDir == null) {
throw new Exception( throw new Exception(
@@ -856,7 +854,7 @@ public class ItemExportServiceImpl implements ItemExportService {
return null; return null;
} }
List<String> fileNames = new ArrayList<>(); List<String> fileNames = new ArrayList<String>();
for (String fileName : downloadDir.list()) { for (String fileName : downloadDir.list()) {
if (fileName.contains("export") && fileName.endsWith(".zip")) { if (fileName.contains("export") && fileName.endsWith(".zip")) {
@@ -873,11 +871,11 @@ public class ItemExportServiceImpl implements ItemExportService {
@Override @Override
public void deleteOldExportArchives(EPerson eperson) throws Exception { public void deleteOldExportArchives(EPerson eperson) throws Exception {
int hours = configurationService int hours = ConfigurationManager
.getIntProperty("org.dspace.app.itemexport.life.span.hours"); .getIntProperty("org.dspace.app.itemexport.life.span.hours");
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
now.setTime(new Date()); now.setTime(new Date());
now.add(Calendar.HOUR, -hours); now.add(Calendar.HOUR, (-hours));
File downloadDir = new File(getExportDownloadDirectory(eperson)); File downloadDir = new File(getExportDownloadDirectory(eperson));
if (downloadDir.exists()) { if (downloadDir.exists()) {
File[] files = downloadDir.listFiles(); File[] files = downloadDir.listFiles();
@@ -894,11 +892,11 @@ public class ItemExportServiceImpl implements ItemExportService {
@Override @Override
public void deleteOldExportArchives() throws Exception { public void deleteOldExportArchives() throws Exception {
int hours = configurationService.getIntProperty("org.dspace.app.itemexport.life.span.hours"); int hours = ConfigurationManager.getIntProperty("org.dspace.app.itemexport.life.span.hours");
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
now.setTime(new Date()); now.setTime(new Date());
now.add(Calendar.HOUR, -hours); now.add(Calendar.HOUR, (-hours));
File downloadDir = new File(configurationService.getProperty("org.dspace.app.itemexport.download.dir")); File downloadDir = new File(ConfigurationManager.getProperty("org.dspace.app.itemexport.download.dir"));
if (downloadDir.exists()) { if (downloadDir.exists()) {
// Get a list of all the sub-directories, potentially one for each ePerson. // Get a list of all the sub-directories, potentially one for each ePerson.
File[] dirs = downloadDir.listFiles(); File[] dirs = downloadDir.listFiles();
@@ -932,12 +930,12 @@ public class ItemExportServiceImpl implements ItemExportService {
Locale supportedLocale = I18nUtil.getEPersonLocale(eperson); Locale supportedLocale = I18nUtil.getEPersonLocale(eperson);
Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_success")); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_success"));
email.addRecipient(eperson.getEmail()); email.addRecipient(eperson.getEmail());
email.addArgument(configurationService.getProperty("dspace.ui.url") + "/exportdownload/" + fileName); email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/exportdownload/" + fileName);
email.addArgument(configurationService.getProperty("org.dspace.app.itemexport.life.span.hours")); email.addArgument(ConfigurationManager.getProperty("org.dspace.app.itemexport.life.span.hours"));
email.send(); email.send();
} catch (Exception e) { } catch (Exception e) {
log.warn(LogHelper.getHeader(context, "emailSuccessMessage", "cannot notify user of export"), e); log.warn(LogManager.getHeader(context, "emailSuccessMessage", "cannot notify user of export"), e);
} }
} }
@@ -950,7 +948,7 @@ public class ItemExportServiceImpl implements ItemExportService {
Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_error")); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "export_error"));
email.addRecipient(eperson.getEmail()); email.addRecipient(eperson.getEmail());
email.addArgument(error); email.addArgument(error);
email.addArgument(configurationService.getProperty("dspace.ui.url") + "/feedback"); email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/feedback");
email.send(); email.send();
} catch (Exception e) { } catch (Exception e) {

View File

@@ -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.itemimport;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import gr.ekt.bte.core.DataLoader;
import gr.ekt.bte.core.TransformationEngine;
import gr.ekt.bte.dataloader.FileDataLoader;
/**
* This class acts as a Service in the procedure to batch import using the Biblio-Transformation-Engine
*/
public class BTEBatchImportService {
TransformationEngine transformationEngine;
Map<String, DataLoader> dataLoaders = new HashMap<String, DataLoader>();
Map<String, String> outputMap = new HashMap<String, String>();
/**
* Default constructor
*/
public BTEBatchImportService() {
super();
}
/**
* Setter method for dataLoaders parameter
*
* @param dataLoaders map of data loaders
*/
public void setDataLoaders(Map<String, DataLoader> dataLoaders) {
this.dataLoaders = dataLoaders;
}
/**
* Get data loaders
*
* @return the map of DataLoaders
*/
public Map<String, DataLoader> getDataLoaders() {
return dataLoaders;
}
/**
* Get output map
*
* @return the outputMapping
*/
public Map<String, String> getOutputMap() {
return outputMap;
}
/**
* Setter method for the outputMapping
*
* @param outputMap the output mapping
*/
public void setOutputMap(Map<String, String> outputMap) {
this.outputMap = outputMap;
}
/**
* Get transformation engine
*
* @return transformation engine
*/
public TransformationEngine getTransformationEngine() {
return transformationEngine;
}
/**
* set transformation engine
*
* @param transformationEngine transformation engine
*/
public void setTransformationEngine(TransformationEngine transformationEngine) {
this.transformationEngine = transformationEngine;
}
/**
* Getter of file data loaders
*
* @return List of file data loaders
*/
public List<String> getFileDataLoaders() {
List<String> result = new ArrayList<String>();
for (String key : dataLoaders.keySet()) {
DataLoader dl = dataLoaders.get(key);
if (dl instanceof FileDataLoader) {
result.add(key);
}
}
return result;
}
}

View File

@@ -8,7 +8,6 @@
package org.dspace.app.itemimport; package org.dspace.app.itemimport;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@@ -16,9 +15,9 @@ import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.app.itemimport.factory.ItemImportServiceFactory; import org.dspace.app.itemimport.factory.ItemImportServiceFactory;
import org.dspace.app.itemimport.service.ItemImportService; import org.dspace.app.itemimport.service.ItemImportService;
import org.dspace.content.Collection; import org.dspace.content.Collection;
@@ -68,14 +67,16 @@ public class ItemImportCLITool {
try { try {
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
options.addOption("a", "add", false, "add items to DSpace"); options.addOption("a", "add", false, "add items to DSpace");
options.addOption("b", "add-bte", false, "add items to DSpace via Biblio-Transformation-Engine (BTE)");
options.addOption("r", "replace", false, "replace items in mapfile"); options.addOption("r", "replace", false, "replace items in mapfile");
options.addOption("d", "delete", false, options.addOption("d", "delete", false,
"delete items listed in mapfile"); "delete items listed in mapfile");
options.addOption("i", "inputtype", true, "input type in case of BTE import");
options.addOption("s", "source", true, "source of items (directory)"); options.addOption("s", "source", true, "source of items (directory)");
options.addOption("z", "zip", true, "name of zip file"); options.addOption("z", "zip", true, "name of zip file");
options.addOption("c", "collection", true, options.addOption("c", "collection", true,
@@ -99,6 +100,7 @@ public class ItemImportCLITool {
CommandLine line = parser.parse(options, argv); CommandLine line = parser.parse(options, argv);
String command = null; // add replace remove, etc String command = null; // add replace remove, etc
String bteInputType = null; //ris, endnote, tsv, csv, bibtex
String sourcedir = null; String sourcedir = null;
String mapfile = null; String mapfile = null;
String eperson = null; // db ID or email String eperson = null; // db ID or email
@@ -142,6 +144,14 @@ public class ItemImportCLITool {
command = "delete"; command = "delete";
} }
if (line.hasOption('b')) {
command = "add-bte";
}
if (line.hasOption('i')) {
bteInputType = line.getOptionValue('i');
}
if (line.hasOption('w')) { if (line.hasOption('w')) {
useWorkflow = true; useWorkflow = true;
if (line.hasOption('n')) { if (line.hasOption('n')) {
@@ -225,6 +235,37 @@ public class ItemImportCLITool {
System.out.println("No collections given. Assuming 'collections' file inside item directory"); System.out.println("No collections given. Assuming 'collections' file inside item directory");
commandLineCollections = false; commandLineCollections = false;
} }
} else if ("add-bte".equals(command)) {
//Source dir can be null, the user can specify the parameters for his loader in the Spring XML
// configuration file
if (mapfile == null) {
System.out
.println("Error - a map file to hold importing results must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (eperson == null) {
System.out
.println("Error - an eperson to do the importing must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
if (collections == null) {
System.out.println("No collections given. Assuming 'collections' file inside item directory");
commandLineCollections = false;
}
if (bteInputType == null) {
System.out
.println(
"Error - an input type (tsv, csv, ris, endnote, bibtex or any other type you have " +
"specified in BTE Spring XML configuration file) must be specified");
System.out.println(" (run with -h flag for details)");
System.exit(1);
}
} else if ("delete".equals(command)) { } else if ("delete".equals(command)) {
if (eperson == null) { if (eperson == null) {
System.out System.out
@@ -239,9 +280,9 @@ public class ItemImportCLITool {
} }
// can only resume for adds // can only resume for adds
if (isResume && !"add".equals(command)) { if (isResume && !"add".equals(command) && !"add-bte".equals(command)) {
System.out System.out
.println("Error - resume option only works with the --add command"); .println("Error - resume option only works with the --add or the --add-bte commands");
System.exit(1); System.exit(1);
} }
@@ -296,36 +337,29 @@ public class ItemImportCLITool {
// validate each collection arg to see if it's a real collection // validate each collection arg to see if it's a real collection
for (int i = 0; i < collections.length; i++) { for (int i = 0; i < collections.length; i++) {
Collection resolved = null;
if (collections[i] != null) {
// is the ID a handle? // is the ID a handle?
if (collections[i].indexOf('/') != -1) { if (collections[i].indexOf('/') != -1) {
// string has a / so it must be a handle - try and resolve // string has a / so it must be a handle - try and resolve
// it // it
resolved = ((Collection) handleService mycollections.add((Collection) handleService
.resolveToObject(c, collections[i])); .resolveToObject(c, collections[i]));
} else { // resolved, now make sure it's a collection
// not a handle, try and treat it as an integer collection database ID if ((mycollections.get(i) == null)
resolved = collectionService.find(c, UUID.fromString(collections[i])); || (mycollections.get(i).getType() != Constants.COLLECTION)) {
mycollections.set(i, null);
} }
} else if (collections[i] != null) {
// not a handle, try and treat it as an integer collection database ID
mycollections.set(i, collectionService.find(c, UUID.fromString(collections[i])));
} }
// was the collection valid? // was the collection valid?
if ((resolved == null) if (mycollections.get(i) == null) {
|| (resolved.getType() != Constants.COLLECTION)) {
throw new IllegalArgumentException("Cannot resolve " throw new IllegalArgumentException("Cannot resolve "
+ collections[i] + " to collection"); + collections[i] + " to collection");
} }
// add resolved collection to list
mycollections.add(resolved);
// print progress info // print progress info
String owningPrefix = ""; String owningPrefix = "";
@@ -334,7 +368,7 @@ public class ItemImportCLITool {
} }
System.out.println(owningPrefix + " Collection: " System.out.println(owningPrefix + " Collection: "
+ resolved.getName()); + mycollections.get(i).getName());
} }
} // end of validating collections } // end of validating collections
@@ -353,6 +387,8 @@ public class ItemImportCLITool {
myloader.replaceItems(c, mycollections, sourcedir, mapfile, template); myloader.replaceItems(c, mycollections, sourcedir, mapfile, template);
} else if ("delete".equals(command)) { } else if ("delete".equals(command)) {
myloader.deleteItems(c, mapfile); myloader.deleteItems(c, mapfile);
} else if ("add-bte".equals(command)) {
myloader.addBTEItems(c, mycollections, sourcedir, mapfile, template, bteInputType, null);
} }
// complete all transactions // complete all transactions
@@ -372,7 +408,7 @@ public class ItemImportCLITool {
"Deleting temporary zip directory: " + myloader.getTempWorkDirFile().getAbsolutePath()); "Deleting temporary zip directory: " + myloader.getTempWorkDirFile().getAbsolutePath());
myloader.cleanupZipTemp(); myloader.cleanupZipTemp();
} }
} catch (IOException ex) { } catch (Exception ex) {
System.out.println("Unable to delete temporary zip archive location: " + myloader.getTempWorkDirFile() System.out.println("Unable to delete temporary zip archive location: " + myloader.getTempWorkDirFile()
.getAbsolutePath()); .getAbsolutePath());
} }

View File

@@ -7,13 +7,6 @@
*/ */
package org.dspace.app.itemimport; package org.dspace.app.itemimport;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_HEIGHT_QUALIFIER;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_IMAGE_ELEMENT;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_LABEL_ELEMENT;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_SCHEMA;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_TOC_ELEMENT;
import static org.dspace.iiif.util.IIIFSharedUtils.METADATA_IIIF_WIDTH_QUALIFIER;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
@@ -52,17 +45,23 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import org.apache.commons.collections4.ComparatorUtils; import gr.ekt.bte.core.DataLoader;
import gr.ekt.bte.core.TransformationEngine;
import gr.ekt.bte.core.TransformationResult;
import gr.ekt.bte.core.TransformationSpec;
import gr.ekt.bte.dataloader.FileDataLoader;
import gr.ekt.bteio.generators.DSpaceOutputGenerator;
import gr.ekt.bteio.loaders.OAIPMHDataLoader;
import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.io.FileDeleteStrategy; import org.apache.commons.io.FileDeleteStrategy;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.xpath.XPathAPI; import org.apache.xpath.XPathAPI;
import org.dspace.app.itemimport.service.ItemImportService; import org.dspace.app.itemimport.service.ItemImportService;
import org.dspace.app.util.LocalSchemaFilenameFilter; import org.dspace.app.util.LocalSchemaFilenameFilter;
import org.dspace.app.util.RelationshipUtils;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy; import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService; import org.dspace.authorize.service.AuthorizeService;
@@ -75,10 +74,6 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.Relationship;
import org.dspace.content.RelationshipType;
import org.dspace.content.WorkspaceItem; import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.BitstreamFormatService; import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService; import org.dspace.content.service.BitstreamService;
@@ -88,21 +83,19 @@ import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService; import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService; import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.WorkspaceItemService; import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants; import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.Email; import org.dspace.core.Email;
import org.dspace.core.I18nUtil; import org.dspace.core.I18nUtil;
import org.dspace.core.LogHelper; import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.handle.service.HandleService; import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService; import org.dspace.utils.DSpace;
import org.dspace.workflow.WorkflowItem; import org.dspace.workflow.WorkflowItem;
import org.dspace.workflow.WorkflowService; import org.dspace.workflow.WorkflowService;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@@ -131,7 +124,7 @@ import org.xml.sax.SAXException;
* allow the registration of files (bitstreams) into DSpace. * allow the registration of files (bitstreams) into DSpace.
*/ */
public class ItemImportServiceImpl implements ItemImportService, InitializingBean { public class ItemImportServiceImpl implements ItemImportService, InitializingBean {
private final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemImportServiceImpl.class); private final Logger log = Logger.getLogger(ItemImportServiceImpl.class);
@Autowired(required = true) @Autowired(required = true)
protected AuthorizeService authorizeService; protected AuthorizeService authorizeService;
@@ -163,16 +156,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
protected WorkspaceItemService workspaceItemService; protected WorkspaceItemService workspaceItemService;
@Autowired(required = true) @Autowired(required = true)
protected WorkflowService workflowService; protected WorkflowService workflowService;
@Autowired(required = true)
protected ConfigurationService configurationService;
@Autowired(required = true)
protected RelationshipService relationshipService;
@Autowired(required = true)
protected RelationshipTypeService relationshipTypeService;
@Autowired(required = true)
protected MetadataValueService metadataValueService;
protected String tempWorkDir; protected final String tempWorkDir = ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir");
protected boolean isTest = false; protected boolean isTest = false;
protected boolean isResume = false; protected boolean isResume = false;
@@ -180,12 +165,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
protected boolean useWorkflowSendEmail = false; protected boolean useWorkflowSendEmail = false;
protected boolean isQuiet = false; protected boolean isQuiet = false;
//remember which folder item was imported from
Map<String, Item> itemFolderMap = null;
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
tempWorkDir = configurationService.getProperty("org.dspace.app.batchitemimport.work.dir");
//Ensure tempWorkDir exists //Ensure tempWorkDir exists
File tempWorkDirFile = new File(tempWorkDir); File tempWorkDirFile = new File(tempWorkDir);
if (!tempWorkDirFile.exists()) { if (!tempWorkDirFile.exists()) {
@@ -215,6 +196,100 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
} }
/**
* In this method, the BTE is instantiated. THe workflow generates the DSpace files
* necessary for the upload, and the default item import method is called
*
* @param c The contect
* @param mycollections The collections the items are inserted to
* @param sourceDir The filepath to the file to read data from
* @param mapFile The filepath to mapfile to be generated
* @param template whether to use collection template item as starting point
* @param inputType The type of the input data (bibtex, csv, etc.)
* @param workingDir The path to create temporary files (for command line or UI based)
* @throws Exception if error occurs
*/
@Override
public void addBTEItems(Context c, List<Collection> mycollections,
String sourceDir, String mapFile, boolean template, String inputType, String workingDir)
throws Exception {
//Determine the folder where BTE will output the results
String outputFolder = null;
if (workingDir == null) { //This indicates a command line import, create a random path
File importDir = new File(ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir"));
if (!importDir.exists()) {
boolean success = importDir.mkdir();
if (!success) {
log.info("Cannot create batch import directory!");
throw new Exception("Cannot create batch import directory!");
}
}
//Get a random folder in case two admins batch import data at the same time
outputFolder = importDir + File.separator + generateRandomFilename(true);
} else { //This indicates a UI import, working dir is preconfigured
outputFolder = workingDir;
}
BTEBatchImportService dls = new DSpace().getSingletonService(BTEBatchImportService.class);
DataLoader dataLoader = dls.getDataLoaders().get(inputType);
Map<String, String> outputMap = dls.getOutputMap();
TransformationEngine te = dls.getTransformationEngine();
if (dataLoader == null) {
System.out.println(
"ERROR: The key used in -i parameter must match a valid DataLoader in the BTE Spring XML " +
"configuration file!");
return;
}
if (outputMap == null) {
System.out.println(
"ERROR: The key used in -i parameter must match a valid outputMapping in the BTE Spring XML " +
"configuration file!");
return;
}
if (dataLoader instanceof FileDataLoader) {
FileDataLoader fdl = (FileDataLoader) dataLoader;
if (!StringUtils.isBlank(sourceDir)) {
System.out.println(
"INFO: Dataloader will load data from the file specified in the command prompt (and not from the " +
"Spring XML configuration file)");
fdl.setFilename(sourceDir);
}
} else if (dataLoader instanceof OAIPMHDataLoader) {
OAIPMHDataLoader fdl = (OAIPMHDataLoader) dataLoader;
System.out.println(sourceDir);
if (!StringUtils.isBlank(sourceDir)) {
System.out.println(
"INFO: Dataloader will load data from the address specified in the command prompt (and not from " +
"the Spring XML configuration file)");
fdl.setServerAddress(sourceDir);
}
}
if (dataLoader != null) {
System.out.println("INFO: Dataloader " + dataLoader.toString() + " will be used for the import!");
te.setDataLoader(dataLoader);
DSpaceOutputGenerator outputGenerator = new DSpaceOutputGenerator(outputMap);
outputGenerator.setOutputDirectory(outputFolder);
te.setOutputGenerator(outputGenerator);
try {
TransformationResult res = te.transform(new TransformationSpec());
List<String> output = res.getOutput();
outputGenerator.writeOutput(output);
} catch (Exception e) {
System.err.println("Exception");
e.printStackTrace();
throw e;
}
addItems(c, mycollections, outputFolder, mapFile, template);
}
}
@Override @Override
public void addItemsAtomic(Context c, List<Collection> mycollections, String sourceDir, String mapFile, public void addItemsAtomic(Context c, List<Collection> mycollections, String sourceDir, String mapFile,
boolean template) throws Exception { boolean template) throws Exception {
@@ -234,13 +309,10 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
// create the mapfile // create the mapfile
File outFile = null; File outFile = null;
PrintWriter mapOut = null; PrintWriter mapOut = null;
try { try {
Map<String, String> skipItems = new HashMap<>(); // set of items to skip if in 'resume' Map<String, String> skipItems = new HashMap<>(); // set of items to skip if in 'resume'
// mode // mode
itemFolderMap = new HashMap<>();
System.out.println("Adding items from directory: " + sourceDir); System.out.println("Adding items from directory: " + sourceDir);
log.debug("Adding items from directory: " + sourceDir); log.debug("Adding items from directory: " + sourceDir);
System.out.println("Generating mapfile: " + mapFile); System.out.println("Generating mapfile: " + mapFile);
@@ -281,12 +353,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
for (int i = 0; i < dircontents.length; i++) { for (int i = 0; i < dircontents.length; i++) {
if (skipItems.containsKey(dircontents[i])) { if (skipItems.containsKey(dircontents[i])) {
System.out.println("Skipping import of " + dircontents[i]); System.out.println("Skipping import of " + dircontents[i]);
//we still need the item in the map for relationship linking
String skippedHandle = skipItems.get(dircontents[i]);
Item skippedItem = (Item) handleService.resolveToObject(c, skippedHandle);
itemFolderMap.put(dircontents[i], skippedItem);
} else { } else {
List<Collection> clist; List<Collection> clist;
if (directoryFileCollections) { if (directoryFileCollections) {
@@ -306,19 +372,12 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
} else { } else {
clist = mycollections; clist = mycollections;
} }
Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template); Item item = addItem(c, clist, sourceDir, dircontents[i], mapOut, template);
itemFolderMap.put(dircontents[i], item);
c.uncacheEntity(item); c.uncacheEntity(item);
System.out.println(i + " " + dircontents[i]); System.out.println(i + " " + dircontents[i]);
} }
} }
//now that all items are imported, iterate again to link relationships
addRelationships(c, sourceDir);
} finally { } finally {
if (mapOut != null) { if (mapOut != null) {
mapOut.flush(); mapOut.flush();
@@ -327,276 +386,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
} }
} }
/**
* Add relationships from a 'relationships' manifest file.
*
* @param c Context
* @param sourceDir The parent import source directory
* @throws Exception
*/
protected void addRelationships(Context c, String sourceDir) throws Exception {
for (Map.Entry<String, Item> itemEntry : itemFolderMap.entrySet()) {
String folderName = itemEntry.getKey();
String path = sourceDir + File.separatorChar + folderName;
Item item = itemEntry.getValue();
//look for a 'relationship' manifest
Map<String, List<String>> relationships = processRelationshipFile(path, "relationships");
if (!relationships.isEmpty()) {
for (Map.Entry<String, List<String>> relEntry : relationships.entrySet()) {
String relationshipType = relEntry.getKey();
List<String> identifierList = relEntry.getValue();
for (String itemIdentifier : identifierList) {
if (isTest) {
System.out.println("\tAdding relationship (type: " + relationshipType +
") from " + folderName + " to " + itemIdentifier);
continue;
}
//find referenced item
Item relationItem = resolveRelatedItem(c, itemIdentifier);
if (null == relationItem) {
throw new Exception("Could not find item for " + itemIdentifier);
}
//get entity type of entity and item
String itemEntityType = getEntityType(item);
String relatedEntityType = getEntityType(relationItem);
//find matching relationship type
List<RelationshipType> relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName(
c, relationshipType);
RelationshipType foundRelationshipType = RelationshipUtils.matchRelationshipType(
relTypes, relatedEntityType, itemEntityType, relationshipType);
if (foundRelationshipType == null) {
throw new Exception("No Relationship type found for:\n" +
"Target type: " + relatedEntityType + "\n" +
"Origin referer type: " + itemEntityType + "\n" +
"with typeName: " + relationshipType
);
}
boolean left = false;
if (foundRelationshipType.getLeftwardType().equalsIgnoreCase(relationshipType)) {
left = true;
}
// Placeholder items for relation placing
Item leftItem = null;
Item rightItem = null;
if (left) {
leftItem = item;
rightItem = relationItem;
} else {
leftItem = relationItem;
rightItem = item;
}
// Create the relationship
int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem);
int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem);
Relationship persistedRelationship = relationshipService.create(
c, leftItem, rightItem, foundRelationshipType, leftPlace, rightPlace);
// relationshipService.update(c, persistedRelationship);
System.out.println("\tAdded relationship (type: " + relationshipType + ") from " +
leftItem.getHandle() + " to " + rightItem.getHandle());
}
}
}
}
}
/**
* Get the item's entity type from meta.
*
* @param item
* @return
*/
protected String getEntityType(Item item) throws Exception {
return itemService.getMetadata(item, "dspace", "entity", "type", Item.ANY).get(0).getValue();
}
/**
* Read the relationship manifest file.
*
* Each line in the file contains a relationship type id and an item identifier in the following format:
*
* relation.<relation_key> <handle|uuid|folderName:import_item_folder|schema.element[.qualifier]:value>
*
* The input_item_folder should refer the folder name of another item in this import batch.
*
* @param path The main import folder path.
* @param filename The name of the manifest file to check ('relationships')
* @return Map of found relationships
* @throws Exception
*/
protected Map<String, List<String>> processRelationshipFile(String path, String filename) throws Exception {
File file = new File(path + File.separatorChar + filename);
Map<String, List<String>> result = new HashMap<>();
if (file.exists()) {
System.out.println("\tProcessing relationships file: " + filename);
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
String line = null;
while ((line = br.readLine()) != null) {
line = line.trim();
if ("".equals(line)) {
continue;
}
String relationshipType = null;
String itemIdentifier = null;
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
relationshipType = st.nextToken();
if (relationshipType.split("\\.").length > 1) {
relationshipType = relationshipType.split("\\.")[1];
}
} else {
throw new Exception("Bad mapfile line:\n" + line);
}
if (st.hasMoreTokens()) {
itemIdentifier = st.nextToken("").trim();
} else {
throw new Exception("Bad mapfile line:\n" + line);
}
if (!result.containsKey(relationshipType)) {
result.put(relationshipType, new ArrayList<>());
}
result.get(relationshipType).add(itemIdentifier);
}
} catch (FileNotFoundException e) {
System.out.println("\tNo relationships file found.");
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
System.out.println("Non-critical problem releasing resources.");
}
}
}
}
return result;
}
/**
* Resolve an item identifier referred to in the relationships manifest file.
*
* The import item map will be checked first to see if the identifier refers to an item folder
* that was just imported. Next it will try to find the item by handle or UUID, or by a unique
* meta value.
*
* @param c Context
* @param itemIdentifier The identifier string found in the import manifest (handle, uuid, or import subfolder)
* @return Item if found, or null.
* @throws Exception
*/
protected Item resolveRelatedItem(Context c, String itemIdentifier) throws Exception {
if (itemIdentifier.contains(":")) {
if (itemIdentifier.startsWith("folderName:") || itemIdentifier.startsWith("rowName:")) {
//identifier refers to a folder name in this import
int i = itemIdentifier.indexOf(":");
String folderName = itemIdentifier.substring(i + 1);
if (itemFolderMap.containsKey(folderName)) {
return itemFolderMap.get(folderName);
}
} else {
//lookup by meta value
int i = itemIdentifier.indexOf(":");
String metaKey = itemIdentifier.substring(0, i);
String metaValue = itemIdentifier.substring(i + 1);
return findItemByMetaValue(c, metaKey, metaValue);
}
} else if (itemIdentifier.indexOf('/') != -1) {
//resolve by handle
return (Item) handleService.resolveToObject(c, itemIdentifier);
} else {
//try to resolve by UUID
return itemService.findByIdOrLegacyId(c, itemIdentifier);
}
return null;
}
/**
* Lookup an item by a (unique) meta value.
*
* @param metaKey
* @param metaValue
* @return Item
* @throws Exception if single item not found.
*/
protected Item findItemByMetaValue(Context c, String metaKey, String metaValue) throws Exception {
Item item = null;
String mf[] = metaKey.split("\\.");
if (mf.length < 2) {
throw new Exception("Bad metadata field in reference: '" + metaKey +
"' (expected syntax is schema.element[.qualifier])");
}
String schema = mf[0];
String element = mf[1];
String qualifier = mf.length == 2 ? null : mf[2];
try {
MetadataField mfo = metadataFieldService.findByElement(c, schema, element, qualifier);
Iterator<MetadataValue> mdv = metadataValueService.findByFieldAndValue(c, mfo, metaValue);
if (mdv.hasNext()) {
MetadataValue mdvVal = mdv.next();
UUID uuid = mdvVal.getDSpaceObject().getID();
if (mdv.hasNext()) {
throw new Exception("Ambiguous reference; multiple matches in db: " + metaKey);
}
item = itemService.find(c, uuid);
}
} catch (SQLException e) {
throw new Exception("Error looking up item by metadata reference: " + metaKey, e);
}
if (item == null) {
throw new Exception("Item not found by metadata reference: " + metaKey);
}
return item;
}
@Override @Override
public void replaceItems(Context c, List<Collection> mycollections, public void replaceItems(Context c, List<Collection> mycollections,
String sourceDir, String mapFile, boolean template) throws Exception { String sourceDir, String mapFile, boolean template) throws Exception {
@@ -888,7 +677,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem( Node schemaAttr = metadata.item(0).getAttributes().getNamedItem(
"schema"); "schema");
if (schemaAttr == null) { if (schemaAttr == null) {
schema = MetadataSchemaEnum.DC.getName(); schema = MetadataSchema.DC_SCHEMA;
} else { } else {
schema = schemaAttr.getNodeValue(); schema = schemaAttr.getNodeValue();
} }
@@ -1179,59 +968,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
boolean bundleExists = false; boolean bundleExists = false;
boolean permissionsExist = false; boolean permissionsExist = false;
boolean descriptionExists = false; boolean descriptionExists = false;
boolean labelExists = false;
boolean heightExists = false;
boolean widthExists = false;
boolean tocExists = false;
// look for label
String labelMarker = "\tiiif-label";
int lMarkerIndex = line.indexOf(labelMarker);
int lEndIndex = 0;
if (lMarkerIndex > 0) {
lEndIndex = line.indexOf("\t", lMarkerIndex + 1);
if (lEndIndex == -1) {
lEndIndex = line.length();
}
labelExists = true;
}
// look for height
String heightMarker = "\tiiif-height";
int hMarkerIndex = line.indexOf(heightMarker);
int hEndIndex = 0;
if (hMarkerIndex > 0) {
hEndIndex = line.indexOf("\t", hMarkerIndex + 1);
if (hEndIndex == -1) {
hEndIndex = line.length();
}
heightExists = true;
}
// look for width
String widthMarker = "\tiiif-width";
int wMarkerIndex = line.indexOf(widthMarker);
int wEndIndex = 0;
if (wMarkerIndex > 0) {
wEndIndex = line.indexOf("\t", wMarkerIndex + 1);
if (wEndIndex == -1) {
wEndIndex = line.length();
}
widthExists = true;
}
// look for toc
String tocMarker = "\tiiif-toc";
int tMarkerIndex = line.indexOf(tocMarker);
int tEndIndex = 0;
if (tMarkerIndex > 0) {
tEndIndex = line.indexOf("\t", tMarkerIndex + 1);
if (tEndIndex == -1) {
tEndIndex = line.length();
}
tocExists = true;
}
// look for a bundle name // look for a bundle name
String bundleMarker = "\tbundle:"; String bundleMarker = "\tbundle:";
@@ -1291,9 +1027,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
System.out.println("\tBitstream: " + bitstreamName + primaryStr); System.out.println("\tBitstream: " + bitstreamName + primaryStr);
} }
if (permissionsExist || descriptionExists || labelExists || heightExists if (permissionsExist || descriptionExists) {
|| widthExists || tocExists) {
System.out.println("Gathering options.");
String extraInfo = bitstreamName; String extraInfo = bitstreamName;
if (permissionsExist) { if (permissionsExist) {
@@ -1306,26 +1040,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
+ line.substring(dMarkerIndex, dEndIndex); + line.substring(dMarkerIndex, dEndIndex);
} }
if (labelExists) {
extraInfo = extraInfo
+ line.substring(lMarkerIndex, lEndIndex);
}
if (heightExists) {
extraInfo = extraInfo
+ line.substring(hMarkerIndex, hEndIndex);
}
if (widthExists) {
extraInfo = extraInfo
+ line.substring(wMarkerIndex, wEndIndex);
}
if (tocExists) {
extraInfo = extraInfo
+ line.substring(tMarkerIndex, tEndIndex);
}
options.add(extraInfo); options.add(extraInfo);
} }
} }
@@ -1507,16 +1221,11 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
*/ */
protected void processOptions(Context c, Item myItem, List<String> options) protected void processOptions(Context c, Item myItem, List<String> options)
throws SQLException, AuthorizeException { throws SQLException, AuthorizeException {
System.out.println("Processing options.");
for (String line : options) { for (String line : options) {
System.out.println("\tprocessing " + line); System.out.println("\tprocessing " + line);
boolean permissionsExist = false; boolean permissionsExist = false;
boolean descriptionExists = false; boolean descriptionExists = false;
boolean labelExists = false;
boolean heightExists = false;
boolean widthExists = false;
boolean tocExists = false;
String permissionsMarker = "\tpermissions:"; String permissionsMarker = "\tpermissions:";
int pMarkerIndex = line.indexOf(permissionsMarker); int pMarkerIndex = line.indexOf(permissionsMarker);
@@ -1540,56 +1249,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
descriptionExists = true; descriptionExists = true;
} }
// look for label
String labelMarker = "\tiiif-label:";
int lMarkerIndex = line.indexOf(labelMarker);
int lEndIndex = 0;
if (lMarkerIndex > 0) {
lEndIndex = line.indexOf("\t", lMarkerIndex + 1);
if (lEndIndex == -1) {
lEndIndex = line.length();
}
labelExists = true;
}
// look for height
String heightMarker = "\tiiif-height:";
int hMarkerIndex = line.indexOf(heightMarker);
int hEndIndex = 0;
if (hMarkerIndex > 0) {
hEndIndex = line.indexOf("\t", hMarkerIndex + 1);
if (hEndIndex == -1) {
hEndIndex = line.length();
}
heightExists = true;
}
// look for width
String widthMarker = "\tiiif-width:";
int wMarkerIndex = line.indexOf(widthMarker);
int wEndIndex = 0;
if (wMarkerIndex > 0) {
wEndIndex = line.indexOf("\t", wMarkerIndex + 1);
if (wEndIndex == -1) {
wEndIndex = line.length();
}
widthExists = true;
}
// look for toc
String tocMarker = "\tiiif-toc:";
int tMarkerIndex = line.indexOf(tocMarker);
int tEndIndex = 0;
if (tMarkerIndex > 0) {
tEndIndex = line.indexOf("\t", tMarkerIndex + 1);
if (tEndIndex == -1) {
tEndIndex = line.length();
}
tocExists = true;
}
int bsEndIndex = line.indexOf("\t"); int bsEndIndex = line.indexOf("\t");
String bitstreamName = line.substring(0, bsEndIndex); String bitstreamName = line.substring(0, bsEndIndex);
@@ -1639,38 +1298,8 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
.trim(); .trim();
} }
String thisLabel = "";
if (labelExists) {
thisLabel = line.substring(
lMarkerIndex + labelMarker.length(), lEndIndex)
.trim();
}
String thisHeight = "";
if (heightExists) {
thisHeight = line.substring(
hMarkerIndex + heightMarker.length(), hEndIndex)
.trim();
}
String thisWidth = "";
if (widthExists) {
thisWidth = line.substring(
wMarkerIndex + widthMarker.length(), wEndIndex)
.trim();
}
String thisToc = "";
if (tocExists) {
thisToc = line.substring(
tMarkerIndex + tocMarker.length(), tEndIndex)
.trim();
}
Bitstream bs = null; Bitstream bs = null;
boolean notfound = true; boolean notfound = true;
boolean updateRequired = false;
if (!isTest) { if (!isTest) {
// find bitstream // find bitstream
List<Bitstream> bitstreams = itemService.getNonInternalBitstreams(c, myItem); List<Bitstream> bitstreams = itemService.getNonInternalBitstreams(c, myItem);
@@ -1705,45 +1334,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
System.out.println("\tSetting description for " System.out.println("\tSetting description for "
+ bitstreamName); + bitstreamName);
bs.setDescription(c, thisDescription); bs.setDescription(c, thisDescription);
updateRequired = true;
}
if (labelExists) {
MetadataField metadataField = metadataFieldService
.findByElement(c, METADATA_IIIF_SCHEMA, METADATA_IIIF_LABEL_ELEMENT, null);
System.out.println("\tSetting label to " + thisLabel + " in element "
+ metadataField.getElement() + " on " + bitstreamName);
bitstreamService.addMetadata(c, bs, metadataField, null, thisLabel);
updateRequired = true;
}
if (heightExists) {
MetadataField metadataField = metadataFieldService
.findByElement(c, METADATA_IIIF_SCHEMA, METADATA_IIIF_IMAGE_ELEMENT,
METADATA_IIIF_HEIGHT_QUALIFIER);
System.out.println("\tSetting height to " + thisHeight + " in element "
+ metadataField.getElement() + " on " + bitstreamName);
bitstreamService.addMetadata(c, bs, metadataField, null, thisHeight);
updateRequired = true;
}
if (widthExists) {
MetadataField metadataField = metadataFieldService
.findByElement(c, METADATA_IIIF_SCHEMA, METADATA_IIIF_IMAGE_ELEMENT,
METADATA_IIIF_WIDTH_QUALIFIER);
System.out.println("\tSetting width to " + thisWidth + " in element "
+ metadataField.getElement() + " on " + bitstreamName);
bitstreamService.addMetadata(c, bs, metadataField, null, thisWidth);
updateRequired = true;
}
if (tocExists) {
MetadataField metadataField = metadataFieldService
.findByElement(c, METADATA_IIIF_SCHEMA, METADATA_IIIF_TOC_ELEMENT, null);
System.out.println("\tSetting toc to " + thisToc + " in element "
+ metadataField.getElement() + " on " + bitstreamName);
bitstreamService.addMetadata(c, bs, metadataField, null, thisToc);
updateRequired = true;
}
if (updateRequired) {
bitstreamService.update(c, bs); bitstreamService.update(c, bs);
} }
} }
@@ -1890,7 +1480,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
File tempdir = new File(destinationDir); File tempdir = new File(destinationDir);
if (!tempdir.isDirectory()) { if (!tempdir.isDirectory()) {
log.error("'" + configurationService.getProperty("org.dspace.app.itemexport.work.dir") + log.error("'" + ConfigurationManager.getProperty("org.dspace.app.itemexport.work.dir") +
"' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " + "' as defined by the key 'org.dspace.app.itemexport.work.dir' in dspace.cfg " +
"is not a valid directory"); "is not a valid directory");
} }
@@ -1915,24 +1505,16 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
log.error("Unable to create contents directory: " + zipDir + entry.getName()); log.error("Unable to create contents directory: " + zipDir + entry.getName());
} }
} else { } else {
String entryName = entry.getName(); System.out.println("Extracting file: " + entry.getName());
File outFile = new File(zipDir + entryName); log.info("Extracting file: " + entry.getName());
// Verify that this file will be extracted into our zipDir (and not somewhere else!)
if (!outFile.toPath().normalize().startsWith(zipDir)) {
throw new IOException("Bad zip entry: '" + entryName
+ "' in file '" + zipfile.getAbsolutePath() + "'!"
+ " Cannot process this file.");
} else {
System.out.println("Extracting file: " + entryName);
log.info("Extracting file: " + entryName);
int index = entryName.lastIndexOf('/'); int index = entry.getName().lastIndexOf('/');
if (index == -1) { if (index == -1) {
// Was it created on Windows instead? // Was it created on Windows instead?
index = entryName.lastIndexOf('\\'); index = entry.getName().lastIndexOf('\\');
} }
if (index > 0) { if (index > 0) {
File dir = new File(zipDir + entryName.substring(0, index)); File dir = new File(zipDir + entry.getName().substring(0, index));
if (!dir.exists() && !dir.mkdirs()) { if (!dir.exists() && !dir.mkdirs()) {
log.error("Unable to create directory: " + dir.getAbsolutePath()); log.error("Unable to create directory: " + dir.getAbsolutePath());
} }
@@ -1945,18 +1527,20 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
// item2 / contents|dublin_core|... // item2 / contents|dublin_core|...
//regex supports either windows or *nix file paths //regex supports either windows or *nix file paths
String[] entryChunks = entryName.split("/|\\\\"); String[] entryChunks = entry.getName().split("/|\\\\");
if (entryChunks.length > 2) { if (entryChunks.length > 2) {
if (StringUtils.equals(sourceDirForZip, sourcedir)) { if (StringUtils.equals(sourceDirForZip, sourcedir)) {
sourceDirForZip = sourcedir + "/" + entryChunks[0]; sourceDirForZip = sourcedir + "/" + entryChunks[0];
} }
} }
} }
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int len; int len;
InputStream in = zf.getInputStream(entry); InputStream in = zf.getInputStream(entry);
BufferedOutputStream out = new BufferedOutputStream( BufferedOutputStream out = new BufferedOutputStream(
new FileOutputStream(outFile)); new FileOutputStream(zipDir + entry.getName()));
while ((len = in.read(buffer)) >= 0) { while ((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len); out.write(buffer, 0, len);
} }
@@ -1964,7 +1548,6 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
out.close(); out.close();
} }
} }
}
//Close zip file //Close zip file
zf.close(); zf.close();
@@ -2055,7 +1638,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
} }
} }
importDir = configurationService.getProperty( importDir = ConfigurationManager.getProperty(
"org.dspace.app.batchitemimport.work.dir") + File.separator + "batchuploads" + File.separator "org.dspace.app.batchitemimport.work.dir") + File.separator + "batchuploads" + File.separator
+ context + context
.getCurrentUser() .getCurrentUser()
@@ -2145,6 +1728,9 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
if (theInputType.equals("saf") || theInputType if (theInputType.equals("saf") || theInputType
.equals("safupload")) { //In case of Simple Archive Format import .equals("safupload")) { //In case of Simple Archive Format import
addItems(context, finalCollections, dataDir, mapFilePath, template); addItems(context, finalCollections, dataDir, mapFilePath, template);
} else { // For all other imports (via BTE)
addBTEItems(context, finalCollections, theFilePath, mapFilePath, useTemplateItem, theInputType,
dataDir);
} }
// email message letting user know the file is ready for // email message letting user know the file is ready for
@@ -2197,7 +1783,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
email.send(); email.send();
} catch (Exception e) { } catch (Exception e) {
log.warn(LogHelper.getHeader(context, "emailSuccessMessage", "cannot notify user of import"), e); log.warn(LogManager.getHeader(context, "emailSuccessMessage", "cannot notify user of import"), e);
} }
} }
@@ -2210,7 +1796,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_error")); Email email = Email.getEmail(I18nUtil.getEmailFilename(supportedLocale, "bte_batch_import_error"));
email.addRecipient(eperson.getEmail()); email.addRecipient(eperson.getEmail());
email.addArgument(error); email.addArgument(error);
email.addArgument(configurationService.getProperty("dspace.ui.url") + "/feedback"); email.addArgument(ConfigurationManager.getProperty("dspace.url") + "/feedback");
email.send(); email.send();
} catch (Exception e) { } catch (Exception e) {
@@ -2248,7 +1834,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
@Override @Override
public String getImportUploadableDirectory(EPerson ePerson) public String getImportUploadableDirectory(EPerson ePerson)
throws Exception { throws Exception {
String uploadDir = configurationService.getProperty("org.dspace.app.batchitemimport.work.dir"); String uploadDir = ConfigurationManager.getProperty("org.dspace.app.batchitemimport.work.dir");
if (uploadDir == null) { if (uploadDir == null) {
throw new Exception( throw new Exception(
"A dspace.cfg entry for 'org.dspace.app.batchitemimport.work.dir' does not exist."); "A dspace.cfg entry for 'org.dspace.app.batchitemimport.work.dir' does not exist.");
@@ -2331,5 +1917,4 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
public void setQuiet(boolean isQuiet) { public void setQuiet(boolean isQuiet) {
this.isQuiet = isQuiet; this.isQuiet = isQuiet;
} }
} }

View File

@@ -105,7 +105,7 @@ public interface ItemImportService {
String inputType, Context context, boolean template) throws Exception; String inputType, Context context, boolean template) throws Exception;
/** /**
* If a batch import is done in a new thread we are unable to communicate * Since the BTE batch import is done in a new thread we are unable to communicate
* with calling method about success or failure. We accomplish this * with calling method about success or failure. We accomplish this
* communication with email instead. Send a success email once the batch * communication with email instead. Send a success email once the batch
* import is complete * import is complete
@@ -119,7 +119,7 @@ public interface ItemImportService {
String fileName) throws MessagingException; String fileName) throws MessagingException;
/** /**
* If a batch import is done in a new thread we are unable to communicate * Since the BTE batch import is done in a new thread we are unable to communicate
* with calling method about success or failure. We accomplis this * with calling method about success or failure. We accomplis this
* communication with email instead. Send an error email if the batch * communication with email instead. Send an error email if the batch
* import fails * import fails
@@ -183,6 +183,21 @@ public interface ItemImportService {
*/ */
public void deleteItems(Context c, String mapfile) throws Exception; public void deleteItems(Context c, String mapfile) throws Exception;
/**
* Add items
*
* @param c DSpace Context
* @param mycollections List of Collections
* @param sourcedir source directory
* @param mapfile map file
* @param template whether to use template item
* @param bteInputType The input type of the data (bibtex, csv, etc.), in case of local file
* @param workingDir working directory
* @throws Exception if error
*/
public void addBTEItems(Context c, List<Collection> mycollections, String sourcedir, String mapfile,
boolean template, String bteInputType, String workingDir) throws Exception;
/** /**
* Get temporary work directory * Get temporary work directory
* *

View File

@@ -11,8 +11,6 @@ import java.io.UnsupportedEncodingException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.Util; import org.dspace.app.util.Util;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.Bundle; import org.dspace.content.Bundle;
@@ -36,9 +34,8 @@ public class ItemMarkingAvailabilityBitstreamStrategy implements ItemMarkingExtr
@Autowired(required = true) @Autowired(required = true)
protected ItemService itemService; protected ItemService itemService;
private static final Logger LOG = LogManager.getLogger();
public ItemMarkingAvailabilityBitstreamStrategy() { public ItemMarkingAvailabilityBitstreamStrategy() {
} }
@Override @Override
@@ -46,14 +43,14 @@ public class ItemMarkingAvailabilityBitstreamStrategy implements ItemMarkingExtr
throws SQLException { throws SQLException {
List<Bundle> bundles = itemService.getBundles(item, "ORIGINAL"); List<Bundle> bundles = itemService.getBundles(item, "ORIGINAL");
if (bundles.isEmpty()) { if (bundles.size() == 0) {
ItemMarkingInfo markInfo = new ItemMarkingInfo(); ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName); markInfo.setImageName(nonAvailableImageName);
return markInfo; return markInfo;
} else { } else {
Bundle originalBundle = bundles.iterator().next(); Bundle originalBundle = bundles.iterator().next();
if (originalBundle.getBitstreams().isEmpty()) { if (originalBundle.getBitstreams().size() == 0) {
ItemMarkingInfo markInfo = new ItemMarkingInfo(); ItemMarkingInfo markInfo = new ItemMarkingInfo();
markInfo.setImageName(nonAvailableImageName); markInfo.setImageName(nonAvailableImageName);
@@ -75,7 +72,8 @@ public class ItemMarkingAvailabilityBitstreamStrategy implements ItemMarkingExtr
try { try {
bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING); bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
LOG.warn("DSpace uses an unsupported encoding", e);
e.printStackTrace();
} }
signInfo.setLink(bsLink); signInfo.setLink(bsLink);

View File

@@ -7,7 +7,6 @@
*/ */
package org.dspace.app.itemupdate; package org.dspace.app.itemupdate;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@@ -21,25 +20,22 @@ import java.util.Map;
public class ActionManager implements Iterable<UpdateAction> { public class ActionManager implements Iterable<UpdateAction> {
protected Map<Class<? extends UpdateAction>, UpdateAction> registry protected Map<Class<? extends UpdateAction>, UpdateAction> registry
= new LinkedHashMap<>(); = new LinkedHashMap<Class<? extends UpdateAction>, UpdateAction>();
/** /**
* Get update action. * Get update action
* *
* @param actionClass UpdateAction class * @param actionClass UpdateAction class
* @return instantiation of UpdateAction class * @return instantiation of UpdateAction class
* @throws InstantiationException if instantiation error * @throws InstantiationException if instantiation error
* @throws IllegalAccessException if illegal access error * @throws IllegalAccessException if illegal access error
* @throws NoSuchMethodException passed through.
* @throws InvocationTargetException passed through.
*/ */
public UpdateAction getUpdateAction(Class<? extends UpdateAction> actionClass) public UpdateAction getUpdateAction(Class<? extends UpdateAction> actionClass)
throws InstantiationException, IllegalAccessException, throws InstantiationException, IllegalAccessException {
NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
UpdateAction action = registry.get(actionClass); UpdateAction action = registry.get(actionClass);
if (action == null) { if (action == null) {
action = actionClass.getDeclaredConstructor().newInstance(); action = actionClass.newInstance();
registry.put(actionClass, action); registry.put(actionClass, action);
} }
@@ -62,8 +58,7 @@ public class ActionManager implements Iterable<UpdateAction> {
@Override @Override
public Iterator<UpdateAction> iterator() { public Iterator<UpdateAction> iterator() {
return new Iterator<UpdateAction>() { return new Iterator<UpdateAction>() {
private final Iterator<Class<? extends UpdateAction>> itr private Iterator<Class<? extends UpdateAction>> itr = registry.keySet().iterator();
= registry.keySet().iterator();
@Override @Override
public boolean hasNext() { public boolean hasNext() {

View File

@@ -105,7 +105,6 @@ public class ContentsEntry {
return new ContentsEntry(arp[0], arp[1], actionId, groupName, arp[3]); return new ContentsEntry(arp[0], arp[1], actionId, groupName, arp[3]);
} }
@Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(filename); StringBuilder sb = new StringBuilder(filename);
if (bundlename != null) { if (bundlename != null) {

View File

@@ -120,7 +120,6 @@ class DtoMetadata {
return true; return true;
} }
@Override
public String toString() { public String toString() {
String s = "\tSchema: " + schema + " Element: " + element; String s = "\tSchema: " + schema + " Element: " + element;
if (qualifier != null) { if (qualifier != null) {

View File

@@ -17,7 +17,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@@ -31,7 +30,7 @@ import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactory;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.util.LocalSchemaFilenameFilter; import org.dspace.app.util.LocalSchemaFilenameFilter;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
@@ -48,7 +47,7 @@ import org.w3c.dom.Document;
* Encapsulates the Item in the context of the DSpace Archive Format * Encapsulates the Item in the context of the DSpace Archive Format
*/ */
public class ItemArchive { public class ItemArchive {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemArchive.class); private static final Logger log = Logger.getLogger(ItemArchive.class);
public static final String DUBLIN_CORE_XML = "dublin_core.xml"; public static final String DUBLIN_CORE_XML = "dublin_core.xml";
@@ -56,7 +55,7 @@ public class ItemArchive {
protected Transformer transformer = null; protected Transformer transformer = null;
protected List<DtoMetadata> dtomList = null; protected List<DtoMetadata> dtomList = null;
protected List<DtoMetadata> undoDtomList = new ArrayList<>(); protected List<DtoMetadata> undoDtomList = new ArrayList<DtoMetadata>();
protected List<UUID> undoAddContents = new ArrayList<>(); // for undo of add protected List<UUID> undoAddContents = new ArrayList<>(); // for undo of add
@@ -326,7 +325,7 @@ public class ItemArchive {
PrintWriter pw = null; PrintWriter pw = null;
try { try {
File f = new File(dir, ItemUpdate.DELETE_CONTENTS_FILE); File f = new File(dir, ItemUpdate.DELETE_CONTENTS_FILE);
pw = new PrintWriter(new BufferedWriter(new FileWriter(f, StandardCharsets.UTF_8))); pw = new PrintWriter(new BufferedWriter(new FileWriter(f)));
for (UUID i : undoAddContents) { for (UUID i : undoAddContents) {
pw.println(i); pw.println(i);
} }

View File

@@ -24,19 +24,18 @@ import java.util.UUID;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option; import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
/** /**
* Provides some batch editing capabilities for items in DSpace: * Provides some batch editing capabilities for items in DSpace:
@@ -79,7 +78,6 @@ public class ItemUpdate {
protected static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService();
protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
static { static {
filterAliases.put("ORIGINAL", "org.dspace.app.itemupdate.OriginalBitstreamFilter"); filterAliases.put("ORIGINAL", "org.dspace.app.itemupdate.OriginalBitstreamFilter");
@@ -109,7 +107,7 @@ public class ItemUpdate {
// instance variables // instance variables
protected ActionManager actionMgr = new ActionManager(); protected ActionManager actionMgr = new ActionManager();
protected List<String> undoActionList = new ArrayList<>(); protected List<String> undoActionList = new ArrayList<String>();
protected String eperson; protected String eperson;
/** /**
@@ -117,7 +115,7 @@ public class ItemUpdate {
*/ */
public static void main(String[] argv) { public static void main(String[] argv) {
// create an options object and populate it // create an options object and populate it
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
Options options = new Options(); Options options = new Options();
@@ -275,8 +273,7 @@ public class ItemUpdate {
Class<?> cfilter = Class.forName(filterClassname); Class<?> cfilter = Class.forName(filterClassname);
pr("BitstreamFilter class to instantiate: " + cfilter.toString()); pr("BitstreamFilter class to instantiate: " + cfilter.toString());
filter = (BitstreamFilter) cfilter.getDeclaredConstructor() filter = (BitstreamFilter) cfilter.newInstance(); //unfortunate cast, an erasure consequence
.newInstance(); //unfortunate cast, an erasure consequence
} catch (Exception e) { } catch (Exception e) {
pr("Error: Failure instantiating bitstream filter class: " + filterClassname); pr("Error: Failure instantiating bitstream filter class: " + filterClassname);
System.exit(1); System.exit(1);
@@ -333,7 +330,10 @@ public class ItemUpdate {
iu.setEPerson(context, iu.eperson); iu.setEPerson(context, iu.eperson);
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
HANDLE_PREFIX = handleService.getCanonicalPrefix(); HANDLE_PREFIX = ConfigurationManager.getProperty("handle.canonical.prefix");
if (HANDLE_PREFIX == null || HANDLE_PREFIX.length() == 0) {
HANDLE_PREFIX = "http://hdl.handle.net/";
}
iu.processArchive(context, sourcedir, itemField, metadataIndexName, alterProvenance, isTest); iu.processArchive(context, sourcedir, itemField, metadataIndexName, alterProvenance, isTest);

View File

@@ -28,18 +28,17 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource; import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamResult;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.xpath.XPathAPI; import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataField; import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NamedNodeMap;
@@ -190,7 +189,7 @@ public class MetadataUtilities {
NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core"); NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core");
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema"); Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema");
if (schemaAttr == null) { if (schemaAttr == null) {
schema = MetadataSchemaEnum.DC.getName(); schema = MetadataSchema.DC_SCHEMA;
} else { } else {
schema = schemaAttr.getNodeValue(); schema = schemaAttr.getNodeValue();
} }
@@ -226,9 +225,7 @@ public class MetadataUtilities {
if (language == null) { if (language == null) {
language = "en"; language = "en";
} else if ("".equals(language)) { } else if ("".equals(language)) {
language = DSpaceServicesFactory.getInstance() language = ConfigurationManager.getProperty("default.language");
.getConfigurationService()
.getProperty("default.language");
} }
DtoMetadata dtom = DtoMetadata.create(schema, element, qualifier, language, value); DtoMetadata dtom = DtoMetadata.create(schema, element, qualifier, language, value);

View File

@@ -10,22 +10,9 @@ package org.dspace.app.launcher;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.TreeMap; 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.core.Context;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
import org.dspace.scripts.service.ScriptService;
import org.dspace.servicemanager.DSpaceKernelImpl; import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit; import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService; import org.dspace.services.RequestService;
@@ -40,9 +27,6 @@ import org.jdom.input.SAXBuilder;
* @author Mark Diggory * @author Mark Diggory
*/ */
public class ScriptLauncher { public class ScriptLauncher {
private static final Logger log = LogManager.getLogger();
/** /**
* The service manager kernel * The service manager kernel
*/ */
@@ -51,8 +35,7 @@ public class ScriptLauncher {
/** /**
* Default constructor * Default constructor
*/ */
private ScriptLauncher() { private ScriptLauncher() { }
}
/** /**
* Execute the DSpace script launcher * Execute the DSpace script launcher
@@ -62,7 +45,7 @@ public class ScriptLauncher {
* @throws FileNotFoundException if file doesn't exist * @throws FileNotFoundException if file doesn't exist
*/ */
public static void main(String[] args) public static void main(String[] args)
throws FileNotFoundException, IOException, IllegalAccessException, InstantiationException { throws FileNotFoundException, IOException {
// Initialise the service manager kernel // Initialise the service manager kernel
try { try {
kernelImpl = DSpaceKernelInit.getKernel(null); kernelImpl = DSpaceKernelInit.getKernel(null);
@@ -93,9 +76,8 @@ public class ScriptLauncher {
} }
// Look up command in the configuration, and execute. // Look up command in the configuration, and execute.
int status;
CommandLineDSpaceRunnableHandler commandLineDSpaceRunnableHandler = new CommandLineDSpaceRunnableHandler(); status = runOneCommand(commandConfigs, args);
int status = handleScript(args, commandConfigs, commandLineDSpaceRunnableHandler, kernelImpl);
// Destroy the service kernel if it is still alive // Destroy the service kernel if it is still alive
if (kernelImpl != null) { if (kernelImpl != null) {
@@ -104,55 +86,6 @@ public class ScriptLauncher {
} }
System.exit(status); System.exit(status);
}
/**
* This method will take the arguments from a commandline input and it'll find the script that the first argument
* refers to and it'll execute this script.
* It can return a 1 or a 0 depending on whether the script failed or passed respectively
* @param args The arguments for the script and the script as first one in the array
* @param commandConfigs The Document
* @param dSpaceRunnableHandler The DSpaceRunnableHandler for this execution
* @param kernelImpl The relevant DSpaceKernelImpl
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
public static int handleScript(String[] args, Document commandConfigs,
DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceKernelImpl kernelImpl) throws InstantiationException, IllegalAccessException {
int status;
ScriptService scriptService = ScriptServiceFactory.getInstance().getScriptService();
ScriptConfiguration scriptConfiguration = scriptService.getScriptConfiguration(args[0]);
DSpaceRunnable script = null;
if (scriptConfiguration != null) {
script = scriptService.createDSpaceRunnableForScriptConfiguration(scriptConfiguration);
}
if (script != null) {
status = executeScript(args, dSpaceRunnableHandler, script);
} else {
status = runOneCommand(commandConfigs, args, kernelImpl);
}
return status;
}
/**
* This method will simply execute the script
* @param args The arguments of the script with the script name as first place in the array
* @param dSpaceRunnableHandler The relevant DSpaceRunnableHandler
* @param script The script to be executed
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
private static int executeScript(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceRunnable script) {
try {
script.initialize(args, dSpaceRunnableHandler, null);
script.run();
return 0;
} catch (ParseException e) {
script.printHelp();
e.printStackTrace();
return 1;
}
} }
protected static int runOneCommand(Document commandConfigs, String[] args) { protected static int runOneCommand(Document commandConfigs, String[] args) {
@@ -165,7 +98,7 @@ public class ScriptLauncher {
* @param commandConfigs Document * @param commandConfigs Document
* @param args the command line arguments given * @param args the command line arguments given
*/ */
protected static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) { public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
String request = args[0]; String request = args[0];
Element root = commandConfigs.getRootElement(); Element root = commandConfigs.getRootElement();
List<Element> commands = root.getChildren("command"); List<Element> commands = root.getChildren("command");
@@ -322,53 +255,11 @@ public class ScriptLauncher {
} }
/** /**
* Display the commands that are defined in launcher.xml and/or the script service. * Display the commands that the current launcher config file knows about
*
* @param commandConfigs configs as Document * @param commandConfigs configs as Document
*/ */
private static void display(Document commandConfigs) { private static void display(Document commandConfigs) {
// usage
System.out.println("Usage: dspace [command-name] {parameters}");
// commands from launcher.xml
Collection<Element> launcherCommands = getLauncherCommands(commandConfigs);
if (launcherCommands.size() > 0) {
System.out.println("\nCommands from launcher.xml");
for (Element command : launcherCommands) {
displayCommand(
command.getChild("name").getValue(),
command.getChild("description").getValue()
);
}
}
// commands from script service
Collection<ScriptConfiguration> serviceCommands = getServiceCommands();
if (serviceCommands.size() > 0) {
System.out.println("\nCommands from script service");
for (ScriptConfiguration command : serviceCommands) {
displayCommand(
command.getName(),
command.getDescription()
);
}
}
}
/**
* Display a single command using a fixed format. Used by {@link #display}.
* @param name the name that can be used to invoke the command
* @param description the description of the command
*/
private static void displayCommand(String name, String description) {
System.out.format(" - %s: %s\n", name, description);
}
/**
* Get a sorted collection of the commands that are specified in launcher.xml. Used by {@link #display}.
* @param commandConfigs the contexts of launcher.xml
* @return sorted collection of commands
*/
private static Collection<Element> getLauncherCommands(Document commandConfigs) {
// List all command elements // List all command elements
List<Element> commands = commandConfigs.getRootElement().getChildren("command"); List<Element> commands = commandConfigs.getRootElement().getChildren("command");
@@ -380,32 +271,11 @@ public class ScriptLauncher {
sortedCommands.put(command.getChild("name").getValue(), command); sortedCommands.put(command.getChild("name").getValue(), command);
} }
return sortedCommands.values(); // Display the sorted list
System.out.println("Usage: dspace [command-name] {parameters}");
for (Element command : sortedCommands.values()) {
System.out.println(" - " + command.getChild("name").getValue() +
": " + command.getChild("description").getValue());
} }
/**
* Get a sorted collection of the commands that are defined as beans. Used by {@link #display}.
* @return sorted collection of commands
*/
private static Collection<ScriptConfiguration> getServiceCommands() {
ScriptService scriptService = ScriptServiceFactory.getInstance().getScriptService();
Context throwAwayContext = new Context();
throwAwayContext.turnOffAuthorisationSystem();
List<ScriptConfiguration> scriptConfigurations = scriptService.getScriptConfigurations(throwAwayContext);
throwAwayContext.restoreAuthSystemState();
try {
throwAwayContext.complete();
} catch (SQLException exception) {
exception.printStackTrace();
throwAwayContext.abort();
} }
scriptConfigurations.sort(Comparator.comparing(ScriptConfiguration::getName));
return scriptConfigurations;
}
} }

View File

@@ -12,8 +12,7 @@ import java.io.InputStream;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.services.ConfigurationService; import org.dspace.core.ConfigurationManager;
import org.dspace.services.factory.DSpaceServicesFactory;
/** /**
* Filter image bitstreams, scaling the image to be within the bounds of * Filter image bitstreams, scaling the image to be within the bounds of
@@ -67,19 +66,17 @@ public class BrandedPreviewJPEGFilter extends MediaFilter {
BufferedImage buf = ImageIO.read(source); BufferedImage buf = ImageIO.read(source);
// get config params // get config params
ConfigurationService configurationService float xmax = (float) ConfigurationManager
= DSpaceServicesFactory.getInstance().getConfigurationService();
float xmax = (float) configurationService
.getIntProperty("webui.preview.maxwidth"); .getIntProperty("webui.preview.maxwidth");
float ymax = (float) configurationService float ymax = (float) ConfigurationManager
.getIntProperty("webui.preview.maxheight"); .getIntProperty("webui.preview.maxheight");
boolean blurring = (boolean) configurationService boolean blurring = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.blurring"); .getBooleanProperty("webui.preview.blurring");
boolean hqscaling = (boolean) configurationService boolean hqscaling = (boolean) ConfigurationManager
.getBooleanProperty("webui.preview.hqscaling"); .getBooleanProperty("webui.preview.hqscaling");
int brandHeight = configurationService.getIntProperty("webui.preview.brand.height"); int brandHeight = ConfigurationManager.getIntProperty("webui.preview.brand.height");
String brandFont = configurationService.getProperty("webui.preview.brand.font"); String brandFont = ConfigurationManager.getProperty("webui.preview.brand.font");
int brandFontPoint = configurationService.getIntProperty("webui.preview.brand.fontpoint"); int brandFontPoint = ConfigurationManager.getIntProperty("webui.preview.brand.fontpoint");
JPEGFilter jpegFilter = new JPEGFilter(); JPEGFilter jpegFilter = new JPEGFilter();
return jpegFilter return jpegFilter

View File

@@ -11,7 +11,7 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.poi.POITextExtractor; import org.apache.poi.POITextExtractor;
import org.apache.poi.extractor.ExtractorFactory; import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hssf.extractor.ExcelExtractor; import org.apache.poi.hssf.extractor.ExcelExtractor;
@@ -36,7 +36,7 @@ import org.dspace.content.Item;
*/ */
public class ExcelFilter extends MediaFilter { public class ExcelFilter extends MediaFilter {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(ExcelFilter.class); private static Logger log = Logger.getLogger(ExcelFilter.class);
public String getFilteredName(String oldFilename) { public String getFilteredName(String oldFilename) {
return oldFilename + ".txt"; return oldFilename + ".txt";

View File

@@ -9,7 +9,6 @@ package org.dspace.app.mediafilter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import javax.swing.text.Document; import javax.swing.text.Document;
import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.HTMLEditorKit;
@@ -74,9 +73,9 @@ public class HTMLFilter extends MediaFilter {
String extractedText = doc.getText(0, doc.getLength()); String extractedText = doc.getText(0, doc.getLength());
// generate an input stream with the extracted text // generate an input stream with the extracted text
byte[] textBytes = extractedText.getBytes(StandardCharsets.UTF_8); byte[] textBytes = extractedText.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(textBytes); ByteArrayInputStream bais = new ByteArrayInputStream(textBytes);
return bais; return bais; // will this work? or will the byte array be out of scope?
} }
} }

View File

@@ -19,9 +19,8 @@ import org.dspace.content.Bundle;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.im4java.core.ConvertCmd; import org.im4java.core.ConvertCmd;
import org.im4java.core.IM4JavaException; import org.im4java.core.IM4JavaException;
import org.im4java.core.IMOperation; import org.im4java.core.IMOperation;
@@ -34,18 +33,36 @@ import org.im4java.process.ProcessStarter;
* no bigger than. Creates only JPEGs. * no bigger than. Creates only JPEGs.
*/ */
public abstract class ImageMagickThumbnailFilter extends MediaFilter { public abstract class ImageMagickThumbnailFilter extends MediaFilter {
private static final int DEFAULT_WIDTH = 180; protected static int width = 180;
private static final int DEFAULT_HEIGHT = 120; protected static int height = 120;
static final String DEFAULT_PATTERN = "Generated Thumbnail"; private static boolean flatten = true;
static String bitstreamDescription = "IM Thumbnail";
static final String defaultPattern = "Generated Thumbnail";
static Pattern replaceRegex = Pattern.compile(defaultPattern);
protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected static final ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
protected static final String PRE = ImageMagickThumbnailFilter.class.getName(); static String cmyk_profile;
static String srgb_profile;
static { static {
String s = configurationService.getProperty(PRE + ".ProcessStarter"); String pre = ImageMagickThumbnailFilter.class.getName();
String s = ConfigurationManager.getProperty(pre + ".ProcessStarter");
ProcessStarter.setGlobalSearchPath(s); ProcessStarter.setGlobalSearchPath(s);
width = ConfigurationManager.getIntProperty("thumbnail.maxwidth", width);
height = ConfigurationManager.getIntProperty("thumbnail.maxheight", height);
flatten = ConfigurationManager.getBooleanProperty(pre + ".flatten", flatten);
String description = ConfigurationManager.getProperty(pre + ".bitstreamDescription");
cmyk_profile = ConfigurationManager.getProperty(pre + ".cmyk_profile");
srgb_profile = ConfigurationManager.getProperty(pre + ".srgb_profile");
if (description != null) {
bitstreamDescription = description;
}
try {
String patt = ConfigurationManager.getProperty(pre + ".replaceRegex");
replaceRegex = Pattern.compile(patt == null ? defaultPattern : patt);
} catch (PatternSyntaxException e) {
System.err.println("Invalid thumbnail replacement pattern: " + e.getMessage());
}
} }
public ImageMagickThumbnailFilter() { public ImageMagickThumbnailFilter() {
@@ -77,7 +94,7 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
*/ */
@Override @Override
public String getDescription() { public String getDescription() {
return configurationService.getProperty(PRE + ".bitstreamDescription", "IM Thumbnail"); return bitstreamDescription;
} }
public File inputStreamToTempFile(InputStream source, String prefix, String suffix) throws IOException { public File inputStreamToTempFile(InputStream source, String prefix, String suffix) throws IOException {
@@ -103,8 +120,7 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
IMOperation op = new IMOperation(); IMOperation op = new IMOperation();
op.autoOrient(); op.autoOrient();
op.addImage(f.getAbsolutePath()); op.addImage(f.getAbsolutePath());
op.thumbnail(configurationService.getIntProperty("thumbnail.maxwidth", DEFAULT_WIDTH), op.thumbnail(width, height);
configurationService.getIntProperty("thumbnail.maxheight", DEFAULT_HEIGHT));
op.addImage(f2.getAbsolutePath()); op.addImage(f2.getAbsolutePath());
if (verbose) { if (verbose) {
System.out.println("IM Thumbnail Param: " + op); System.out.println("IM Thumbnail Param: " + op);
@@ -121,16 +137,13 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
IMOperation op = new IMOperation(); IMOperation op = new IMOperation();
String s = "[" + page + "]"; String s = "[" + page + "]";
op.addImage(f.getAbsolutePath() + s); op.addImage(f.getAbsolutePath() + s);
if (configurationService.getBooleanProperty(PRE + ".flatten", true)) { if (flatten) {
op.flatten(); op.flatten();
} }
// PDFs using the CMYK color system can be handled specially if // PDFs using the CMYK color system can be handled specially if
// profiles are defined // profiles are defined
String cmyk_profile = configurationService.getProperty(PRE + ".cmyk_profile");
String srgb_profile = configurationService.getProperty(PRE + ".srgb_profile");
if (cmyk_profile != null && srgb_profile != null) { if (cmyk_profile != null && srgb_profile != null) {
Info imageInfo = new Info(f.getAbsolutePath() + s, true); Info imageInfo = new Info(f.getAbsolutePath(), true);
String imageClass = imageInfo.getImageClass(); String imageClass = imageInfo.getImageClass();
if (imageClass.contains("CMYK")) { if (imageClass.contains("CMYK")) {
op.profile(cmyk_profile); op.profile(cmyk_profile);
@@ -161,32 +174,24 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter {
String description = bit.getDescription(); String description = bit.getDescription();
// If anything other than a generated thumbnail // If anything other than a generated thumbnail
// is found, halt processing // is found, halt processing
Pattern replaceRegex;
try {
String patt = configurationService.getProperty(PRE + ".replaceRegex", DEFAULT_PATTERN);
replaceRegex = Pattern.compile(patt == null ? DEFAULT_PATTERN : patt);
} catch (PatternSyntaxException e) {
System.err.println("Invalid thumbnail replacement pattern: " + e.getMessage());
throw e;
}
if (description != null) { if (description != null) {
if (replaceRegex.matcher(description).matches()) { if (replaceRegex.matcher(description).matches()) {
if (verbose) { if (verbose) {
System.out.format("%s %s matches pattern and is replacable.%n", System.out.println(description + " " + nsrc
description, nsrc); + " matches pattern and is replacable.");
} }
continue; continue;
} }
if (description.equals(getDescription())) { if (description.equals(bitstreamDescription)) {
if (verbose) { if (verbose) {
System.out.format("%s %s is replaceable.%n", System.out.println(bitstreamDescription + " " + nsrc
getDescription(), nsrc); + " is replacable.");
} }
continue; continue;
} }
} }
System.out.format("Custom Thumbnail exists for %s for item %s. Thumbnail will not be generated.%n", System.out.println("Custom Thumbnail exists for " + nsrc + " for item "
nsrc, item.getHandle()); + item.getHandle() + ". Thumbnail will not be generated. ");
return false; return false;
} }
} }

View File

@@ -22,8 +22,7 @@ import java.io.InputStream;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.services.ConfigurationService; import org.dspace.core.ConfigurationManager;
import org.dspace.services.factory.DSpaceServicesFactory;
/** /**
* Filter image bitstreams, scaling the image to be within the bounds of * Filter image bitstreams, scaling the image to be within the bounds of
@@ -81,15 +80,13 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
public InputStream getThumb(Item currentItem, BufferedImage buf, boolean verbose) public InputStream getThumb(Item currentItem, BufferedImage buf, boolean verbose)
throws Exception { throws Exception {
// get config params // get config params
final ConfigurationService configurationService float xmax = (float) ConfigurationManager
= DSpaceServicesFactory.getInstance().getConfigurationService();
float xmax = (float) configurationService
.getIntProperty("thumbnail.maxwidth"); .getIntProperty("thumbnail.maxwidth");
float ymax = (float) configurationService float ymax = (float) ConfigurationManager
.getIntProperty("thumbnail.maxheight"); .getIntProperty("thumbnail.maxheight");
boolean blurring = (boolean) configurationService boolean blurring = (boolean) ConfigurationManager
.getBooleanProperty("thumbnail.blurring"); .getBooleanProperty("thumbnail.blurring");
boolean hqscaling = (boolean) configurationService boolean hqscaling = (boolean) ConfigurationManager
.getBooleanProperty("thumbnail.hqscaling"); .getBooleanProperty("thumbnail.hqscaling");
return getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, 0, 0, null); return getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, 0, 0, null);
@@ -172,11 +169,9 @@ public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats
g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null); g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null);
if (brandHeight != 0) { if (brandHeight != 0) {
ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5); Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5);
BufferedImage brandImage = brand.create(configurationService.getProperty("webui.preview.brand"), BufferedImage brandImage = brand.create(ConfigurationManager.getProperty("webui.preview.brand"),
configurationService.getProperty("webui.preview.brand.abbrev"), ConfigurationManager.getProperty("webui.preview.brand.abbrev"),
currentItem == null ? "" : "hdl:" + currentItem.getHandle()); currentItem == null ? "" : "hdl:" + currentItem.getHandle());
g2d.drawImage(brandImage, (int) 0, (int) ysize, (int) xsize, (int) 20, null); g2d.drawImage(brandImage, (int) 0, (int) ysize, (int) xsize, (int) 20, null);

View File

@@ -14,8 +14,15 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.cli.ParseException; import org.apache.commons.cli.CommandLine;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.MissingArgumentException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.ArrayUtils;
import org.dspace.app.mediafilter.factory.MediaFilterServiceFactory; import org.dspace.app.mediafilter.factory.MediaFilterServiceFactory;
import org.dspace.app.mediafilter.service.MediaFilterService; import org.dspace.app.mediafilter.service.MediaFilterService;
import org.dspace.content.Collection; import org.dspace.content.Collection;
@@ -27,9 +34,7 @@ import org.dspace.core.Context;
import org.dspace.core.SelfNamedPlugin; import org.dspace.core.SelfNamedPlugin;
import org.dspace.core.factory.CoreServiceFactory; import org.dspace.core.factory.CoreServiceFactory;
import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.services.factory.DSpaceServicesFactory; import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.utils.DSpace;
/** /**
* MediaFilterManager is the class that invokes the media/format filters over the * MediaFilterManager is the class that invokes the media/format filters over the
@@ -40,7 +45,7 @@ import org.dspace.utils.DSpace;
* scope to a community, collection or item; and -m [max] limits processing to a * scope to a community, collection or item; and -m [max] limits processing to a
* maximum number of items. * maximum number of items.
*/ */
public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfiguration> { public class MediaFilterCLITool {
//key (in dspace.cfg) which lists all enabled filters by name //key (in dspace.cfg) which lists all enabled filters by name
private static final String MEDIA_FILTER_PLUGINS_KEY = "filter.plugins"; private static final String MEDIA_FILTER_PLUGINS_KEY = "filter.plugins";
@@ -51,86 +56,130 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
//suffix (in dspace.cfg) for input formats supported by each filter //suffix (in dspace.cfg) for input formats supported by each filter
private static final String INPUT_FORMATS_SUFFIX = "inputFormats"; private static final String INPUT_FORMATS_SUFFIX = "inputFormats";
private boolean help; /**
private boolean isVerbose = false; * Default constructor
private boolean isQuiet = false; */
private boolean isForce = false; // default to not forced private MediaFilterCLITool() { }
private String identifier = null; // object scope limiter
private int max2Process = Integer.MAX_VALUE;
private String[] filterNames;
private String[] skipIds = null;
private Map<String, List<String>> filterFormats = new HashMap<>();
public MediaFilterScriptConfiguration getScriptConfiguration() {
return new DSpace().getServiceManager()
.getServiceByName("filter-media", MediaFilterScriptConfiguration.class);
}
public void setup() throws ParseException {
public static void main(String[] argv) throws Exception {
// set headless for non-gui workstations // set headless for non-gui workstations
System.setProperty("java.awt.headless", "true"); System.setProperty("java.awt.headless", "true");
// create an options object and populate it
CommandLineParser parser = new PosixParser();
help = commandLine.hasOption('h'); int status = 0;
if (commandLine.hasOption('v')) { Options options = new Options();
options.addOption("v", "verbose", false,
"print all extracted text and other details to STDOUT");
options.addOption("q", "quiet", false,
"do not print anything except in the event of errors.");
options.addOption("f", "force", false,
"force all bitstreams to be processed");
options.addOption("i", "identifier", true,
"ONLY process bitstreams belonging to identifier");
options.addOption("m", "maximum", true,
"process no more than maximum items");
options.addOption("h", "help", false, "help");
//create a "plugin" option (to specify specific MediaFilter plugins to run)
OptionBuilder.withLongOpt("plugins");
OptionBuilder.withValueSeparator(',');
OptionBuilder.withDescription(
"ONLY run the specified Media Filter plugin(s)\n" +
"listed from '" + MEDIA_FILTER_PLUGINS_KEY + "' in dspace.cfg.\n" +
"Separate multiple with a comma (,)\n" +
"(e.g. MediaFilterManager -p \n\"Word Text Extractor\",\"PDF Text Extractor\")");
Option pluginOption = OptionBuilder.create('p');
pluginOption.setArgs(Option.UNLIMITED_VALUES); //unlimited number of args
options.addOption(pluginOption);
//create a "skip" option (to specify communities/collections/items to skip)
OptionBuilder.withLongOpt("skip");
OptionBuilder.withValueSeparator(',');
OptionBuilder.withDescription(
"SKIP the bitstreams belonging to identifier\n" +
"Separate multiple identifiers with a comma (,)\n" +
"(e.g. MediaFilterManager -s \n 123456789/34,123456789/323)");
Option skipOption = OptionBuilder.create('s');
skipOption.setArgs(Option.UNLIMITED_VALUES); //unlimited number of args
options.addOption(skipOption);
boolean isVerbose = false;
boolean isQuiet = false;
boolean isForce = false; // default to not forced
String identifier = null; // object scope limiter
int max2Process = Integer.MAX_VALUE;
Map<String, List<String>> filterFormats = new HashMap<>();
CommandLine line = null;
try {
line = parser.parse(options, argv);
} catch (MissingArgumentException e) {
System.out.println("ERROR: " + e.getMessage());
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MediaFilterManager\n", options);
System.exit(1);
}
if (line.hasOption('h')) {
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MediaFilterManager\n", options);
System.exit(0);
}
if (line.hasOption('v')) {
isVerbose = true; isVerbose = true;
} }
isQuiet = commandLine.hasOption('q'); isQuiet = line.hasOption('q');
if (commandLine.hasOption('f')) { if (line.hasOption('f')) {
isForce = true; isForce = true;
} }
if (commandLine.hasOption('i')) { if (line.hasOption('i')) {
identifier = commandLine.getOptionValue('i'); identifier = line.getOptionValue('i');
} }
if (commandLine.hasOption('m')) { if (line.hasOption('m')) {
max2Process = Integer.parseInt(commandLine.getOptionValue('m')); max2Process = Integer.parseInt(line.getOptionValue('m'));
if (max2Process <= 1) { if (max2Process <= 1) {
handler.logWarning("Invalid maximum value '" + System.out.println("Invalid maximum value '" +
commandLine.getOptionValue('m') + "' - ignoring"); line.getOptionValue('m') + "' - ignoring");
max2Process = Integer.MAX_VALUE; max2Process = Integer.MAX_VALUE;
} }
} }
if (commandLine.hasOption('p')) { String filterNames[] = null;
if (line.hasOption('p')) {
//specified which media filter plugins we are using //specified which media filter plugins we are using
filterNames = commandLine.getOptionValues('p'); filterNames = line.getOptionValues('p');
if (filterNames == null || filterNames.length == 0) { //display error, since no plugins specified
System.err.println("\nERROR: -p (-plugin) option requires at least one plugin to be specified.\n" +
"(e.g. MediaFilterManager -p \"Word Text Extractor\",\"PDF Text Extractor\")\n");
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MediaFilterManager\n", options);
System.exit(1);
}
} else { } else {
//retrieve list of all enabled media filter plugins! //retrieve list of all enabled media filter plugins!
filterNames = DSpaceServicesFactory.getInstance().getConfigurationService() filterNames = DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty(MEDIA_FILTER_PLUGINS_KEY); .getArrayProperty(MEDIA_FILTER_PLUGINS_KEY);
} }
//save to a global skip list
if (commandLine.hasOption('s')) {
//specified which identifiers to skip when processing
skipIds = commandLine.getOptionValues('s');
}
}
public void internalRun() throws Exception {
if (help) {
printHelp();
return;
}
MediaFilterService mediaFilterService = MediaFilterServiceFactory.getInstance().getMediaFilterService(); MediaFilterService mediaFilterService = MediaFilterServiceFactory.getInstance().getMediaFilterService();
mediaFilterService.setLogHandler(handler);
mediaFilterService.setForce(isForce); mediaFilterService.setForce(isForce);
mediaFilterService.setQuiet(isQuiet); mediaFilterService.setQuiet(isQuiet);
mediaFilterService.setVerbose(isVerbose); mediaFilterService.setVerbose(isVerbose);
mediaFilterService.setMax2Process(max2Process); mediaFilterService.setMax2Process(max2Process);
//initialize an array of our enabled filters //initialize an array of our enabled filters
List<FormatFilter> filterList = new ArrayList<>(); List<FormatFilter> filterList = new ArrayList<FormatFilter>();
//set up each filter //set up each filter
for (int i = 0; i < filterNames.length; i++) { for (int i = 0; i < filterNames.length; i++) {
@@ -138,10 +187,10 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
FormatFilter filter = (FormatFilter) CoreServiceFactory.getInstance().getPluginService() FormatFilter filter = (FormatFilter) CoreServiceFactory.getInstance().getPluginService()
.getNamedPlugin(FormatFilter.class, filterNames[i]); .getNamedPlugin(FormatFilter.class, filterNames[i]);
if (filter == null) { if (filter == null) {
handler.handleException("ERROR: Unknown MediaFilter specified (either from command-line or in " + System.err.println(
"dspace.cfg): '" + filterNames[i] + "'"); "\nERROR: Unknown MediaFilter specified (either from command-line or in dspace.cfg): '" +
handler.logError("ERROR: Unknown MediaFilter specified (either from command-line or in " + filterNames[i] + "'");
"dspace.cfg): '" + filterNames[i] + "'"); System.exit(1);
} else { } else {
filterList.add(filter); filterList.add(filter);
@@ -187,11 +236,11 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
//If verbose, print out loaded mediafilter info //If verbose, print out loaded mediafilter info
if (isVerbose) { if (isVerbose) {
handler.logInfo("The following MediaFilters are enabled: "); System.out.println("The following MediaFilters are enabled: ");
Iterator<String> i = filterFormats.keySet().iterator(); Iterator<String> i = filterFormats.keySet().iterator();
while (i.hasNext()) { while (i.hasNext()) {
String filterName = i.next(); String filterName = i.next();
handler.logInfo("Full Filter Name: " + filterName); System.out.println("Full Filter Name: " + filterName);
String pluginName = null; String pluginName = null;
if (filterName.contains(MediaFilterService.FILTER_PLUGIN_SEPARATOR)) { if (filterName.contains(MediaFilterService.FILTER_PLUGIN_SEPARATOR)) {
String[] fields = filterName.split(MediaFilterService.FILTER_PLUGIN_SEPARATOR); String[] fields = filterName.split(MediaFilterService.FILTER_PLUGIN_SEPARATOR);
@@ -199,7 +248,8 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
pluginName = fields[1]; pluginName = fields[1];
} }
handler.logInfo(filterName + (pluginName != null ? " (Plugin: " + pluginName + ")" : "")); System.out.println(filterName +
(pluginName != null ? " (Plugin: " + pluginName + ")" : ""));
} }
} }
@@ -209,8 +259,20 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
//Retrieve list of identifiers to skip (if any) //Retrieve list of identifiers to skip (if any)
String skipIds[] = null;
if (line.hasOption('s')) {
//specified which identifiers to skip when processing
skipIds = line.getOptionValues('s');
if (skipIds == null || skipIds.length == 0) { //display error, since no identifiers specified to skip
System.err.println("\nERROR: -s (-skip) option requires at least one identifier to SKIP.\n" +
"Make sure to separate multiple identifiers with a comma!\n" +
"(e.g. MediaFilterManager -s 123456789/34,123456789/323)\n");
HelpFormatter myhelp = new HelpFormatter();
myhelp.printHelp("MediaFilterManager\n", options);
System.exit(0);
}
if (skipIds != null && skipIds.length > 0) {
//save to a global skip list //save to a global skip list
mediaFilterService.setSkipList(Arrays.asList(skipIds)); mediaFilterService.setSkipList(Arrays.asList(skipIds));
} }
@@ -252,11 +314,12 @@ public class MediaFilterScript extends DSpaceRunnable<MediaFilterScriptConfigura
c.complete(); c.complete();
c = null; c = null;
} catch (Exception e) { } catch (Exception e) {
handler.handleException(e); status = 1;
} finally { } finally {
if (c != null) { if (c != null) {
c.abort(); c.abort();
} }
} }
System.exit(status);
} }
} }

View File

@@ -1,91 +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.mediafilter;
import java.sql.SQLException;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
public class MediaFilterScriptConfiguration<T extends MediaFilterScript> extends ScriptConfiguration<T> {
@Autowired
private AuthorizeService authorizeService;
private Class<T> dspaceRunnableClass;
private static final String MEDIA_FILTER_PLUGINS_KEY = "filter.plugins";
@Override
public Class<T> getDspaceRunnableClass() {
return dspaceRunnableClass;
}
@Override
public void setDspaceRunnableClass(Class<T> dspaceRunnableClass) {
this.dspaceRunnableClass = dspaceRunnableClass;
}
@Override
public boolean isAllowedToExecute(final 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() {
Options options = new Options();
options.addOption("v", "verbose", false, "print all extracted text and other details to STDOUT");
options.getOption("v").setType(boolean.class);
options.addOption("q", "quiet", false, "do not print anything except in the event of errors.");
options.getOption("q").setType(boolean.class);
options.addOption("f", "force", false, "force all bitstreams to be processed");
options.getOption("f").setType(boolean.class);
options.addOption("i", "identifier", true, "ONLY process bitstreams belonging to identifier");
options.addOption("m", "maximum", true, "process no more than maximum items");
options.addOption("h", "help", false, "help");
options.getOption("h").setType(boolean.class);
Option pluginOption = Option.builder("p")
.longOpt("plugins")
.hasArg()
.hasArgs()
.valueSeparator(',')
.desc(
"ONLY run the specified Media Filter plugin(s)\n" +
"listed from '" + MEDIA_FILTER_PLUGINS_KEY + "' in dspace.cfg.\n" +
"Separate multiple with a comma (,)\n" +
"(e.g. MediaFilterManager -p \n\"Word Text Extractor\",\"PDF Text" +
" Extractor\")")
.build();
options.addOption(pluginOption);
Option skipOption = Option.builder("s")
.longOpt("skip")
.hasArg()
.hasArgs()
.valueSeparator(',')
.desc(
"SKIP the bitstreams belonging to identifier\n" +
"Separate multiple identifiers with a comma (,)\n" +
"(e.g. MediaFilterManager -s \n 123456789/34,123456789/323)")
.build();
options.addOption(skipOption);
return options;
}
}

View File

@@ -34,7 +34,6 @@ import org.dspace.core.Context;
import org.dspace.core.SelfNamedPlugin; import org.dspace.core.SelfNamedPlugin;
import org.dspace.eperson.Group; import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService; import org.dspace.eperson.service.GroupService;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.services.ConfigurationService; import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -68,8 +67,6 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
@Autowired(required = true) @Autowired(required = true)
protected ConfigurationService configurationService; protected ConfigurationService configurationService;
protected DSpaceRunnableHandler handler;
protected int max2Process = Integer.MAX_VALUE; // maximum number items to process protected int max2Process = Integer.MAX_VALUE; // maximum number items to process
protected int processed = 0; // number items processed protected int processed = 0; // number items processed
@@ -223,21 +220,21 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
} catch (Exception e) { } catch (Exception e) {
String handle = myItem.getHandle(); String handle = myItem.getHandle();
List<Bundle> bundles = myBitstream.getBundles(); List<Bundle> bundles = myBitstream.getBundles();
long size = myBitstream.getSizeBytes(); long size = myBitstream.getSize();
String checksum = myBitstream.getChecksum() + " (" + myBitstream.getChecksumAlgorithm() + ")"; String checksum = myBitstream.getChecksum() + " (" + myBitstream.getChecksumAlgorithm() + ")";
int assetstore = myBitstream.getStoreNumber(); int assetstore = myBitstream.getStoreNumber();
// Printout helpful information to find the errored bitstream. // Printout helpful information to find the errored bitstream.
StringBuilder sb = new StringBuilder("ERROR filtering, skipping bitstream:\n"); System.out.println("ERROR filtering, skipping bitstream:\n");
sb.append("\tItem Handle: ").append(handle); System.out.println("\tItem Handle: " + handle);
for (Bundle bundle : bundles) { for (Bundle bundle : bundles) {
sb.append("\tBundle Name: ").append(bundle.getName()); System.out.println("\tBundle Name: " + bundle.getName());
} }
sb.append("\tFile Size: ").append(size); System.out.println("\tFile Size: " + size);
sb.append("\tChecksum: ").append(checksum); System.out.println("\tChecksum: " + checksum);
sb.append("\tAsset Store: ").append(assetstore); System.out.println("\tAsset Store: " + assetstore);
logError(sb.toString()); System.out.println(e);
logError(e.getMessage(), e); e.printStackTrace();
} }
} else if (filterClass instanceof SelfRegisterInputFormats) { } else if (filterClass instanceof SelfRegisterInputFormats) {
// Filter implements self registration, so check to see if it should be applied // Filter implements self registration, so check to see if it should be applied
@@ -290,7 +287,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
filtered = true; filtered = true;
} }
} catch (Exception e) { } catch (Exception e) {
logError("ERROR filtering, skipping bitstream #" System.out.println("ERROR filtering, skipping bitstream #"
+ myBitstream.getID() + " " + e); + myBitstream.getID() + " " + e);
e.printStackTrace(); e.printStackTrace();
} }
@@ -313,11 +310,12 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
// get bitstream filename, calculate destination filename // get bitstream filename, calculate destination filename
String newName = formatFilter.getFilteredName(source.getName()); String newName = formatFilter.getFilteredName(source.getName());
// check if destination bitstream exists Bitstream existingBitstream = null; // is there an existing rendition?
Bundle existingBundle = null; Bundle targetBundle = null; // bundle we're modifying
Bitstream existingBitstream = null;
List<Bundle> bundles = itemService.getBundles(item, formatFilter.getBundleName()); List<Bundle> bundles = itemService.getBundles(item, formatFilter.getBundleName());
// check if destination bitstream exists
if (bundles.size() > 0) { if (bundles.size() > 0) {
// only finds the last match (FIXME?) // only finds the last match (FIXME?)
for (Bundle bundle : bundles) { for (Bundle bundle : bundles) {
@@ -325,7 +323,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
for (Bitstream bitstream : bitstreams) { for (Bitstream bitstream : bitstreams) {
if (bitstream.getName().trim().equals(newName.trim())) { if (bitstream.getName().trim().equals(newName.trim())) {
existingBundle = bundle; targetBundle = bundle;
existingBitstream = bitstream; existingBitstream = bitstream;
} }
} }
@@ -335,7 +333,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
// if exists and overwrite = false, exit // if exists and overwrite = false, exit
if (!overWrite && (existingBitstream != null)) { if (!overWrite && (existingBitstream != null)) {
if (!isQuiet) { if (!isQuiet) {
logInfo("SKIPPED: bitstream " + source.getID() System.out.println("SKIPPED: bitstream " + source.getID()
+ " (item: " + item.getHandle() + ") because '" + newName + "' already exists"); + " (item: " + item.getHandle() + ") because '" + newName + "' already exists");
} }
@@ -343,45 +341,44 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
} }
if (isVerbose) { if (isVerbose) {
logInfo("PROCESSING: bitstream " + source.getID() System.out.println("PROCESSING: bitstream " + source.getID()
+ " (item: " + item.getHandle() + ")"); + " (item: " + item.getHandle() + ")");
} }
logInfo("File: " + newName); InputStream destStream;
try {
// start filtering of the bitstream, using try with resource to close all InputStreams properly System.out.println("File: " + newName);
try ( destStream = formatFilter.getDestinationStream(item, bitstreamService.retrieve(context, source), isVerbose);
// get the source stream
InputStream srcStream = bitstreamService.retrieve(context, source);
// filter the source stream to produce the destination stream
// this is the hard work, check for OutOfMemoryErrors at the end of the try clause.
InputStream destStream = formatFilter.getDestinationStream(item, srcStream, isVerbose);
) {
if (destStream == null) { if (destStream == null) {
if (!isQuiet) { if (!isQuiet) {
logInfo("SKIPPED: bitstream " + source.getID() System.out.println("SKIPPED: bitstream " + source.getID()
+ " (item: " + item.getHandle() + ") because filtering was unsuccessful"); + " (item: " + item.getHandle() + ") because filtering was unsuccessful");
} }
return false;
}
} catch (OutOfMemoryError oome) {
System.out.println("!!! OutOfMemoryError !!!");
return false; return false;
} }
Bundle targetBundle; // bundle we're modifying
if (bundles.size() < 1) {
// create new bundle if needed // create new bundle if needed
if (bundles.size() < 1) {
targetBundle = bundleService.create(context, item, formatFilter.getBundleName()); targetBundle = bundleService.create(context, item, formatFilter.getBundleName());
} else { } else {
// take the first match as we already looked out for the correct bundle name // take the first match
targetBundle = bundles.get(0); targetBundle = bundles.get(0);
} }
// create bitstream to store the filter result
Bitstream b = bitstreamService.create(context, targetBundle, destStream); Bitstream b = bitstreamService.create(context, targetBundle, destStream);
// set the name, source and description of the bitstream
// Now set the format and name of the bitstream
b.setName(context, newName); b.setName(context, newName);
b.setSource(context, "Written by FormatFilter " + formatFilter.getClass().getName() + b.setSource(context, "Written by FormatFilter " + formatFilter.getClass().getName() +
" on " + DCDate.getCurrent() + " (GMT)."); " on " + DCDate.getCurrent() + " (GMT).");
b.setDescription(context, formatFilter.getDescription()); b.setDescription(context, formatFilter.getDescription());
// Set the format of the bitstream
// Find the proper format
BitstreamFormat bf = bitstreamFormatService.findByShortDescription(context, BitstreamFormat bf = bitstreamFormatService.findByShortDescription(context,
formatFilter.getFormatString()); formatFilter.getFormatString());
bitstreamService.setFormat(context, b, bf); bitstreamService.setFormat(context, b, bf);
@@ -401,24 +398,20 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
authorizeService.inheritPolicies(context, source, b); authorizeService.inheritPolicies(context, source, b);
} }
//do post-processing of the generated bitstream
formatFilter.postProcessBitstream(context, item, b);
} catch (OutOfMemoryError oome) {
logError("!!! OutOfMemoryError !!!");
}
// fixme - set date? // fixme - set date?
// we are overwriting, so remove old bitstream // we are overwriting, so remove old bitstream
if (existingBitstream != null) { if (existingBitstream != null) {
bundleService.removeBitstream(context, existingBundle, existingBitstream); bundleService.removeBitstream(context, targetBundle, existingBitstream);
} }
if (!isQuiet) { if (!isQuiet) {
logInfo("FILTERED: bitstream " + source.getID() System.out.println("FILTERED: bitstream " + source.getID()
+ " (item: " + item.getHandle() + ") and created '" + newName + "'"); + " (item: " + item.getHandle() + ") and created '" + newName + "'");
} }
//do post-processing of the generated bitstream
formatFilter.postProcessBitstream(context, item, b);
return true; return true;
} }
@@ -431,7 +424,7 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
public boolean inSkipList(String identifier) { public boolean inSkipList(String identifier) {
if (skipList != null && skipList.contains(identifier)) { if (skipList != null && skipList.contains(identifier)) {
if (!isQuiet) { if (!isQuiet) {
logInfo("SKIP-LIST: skipped bitstreams within identifier " + identifier); System.out.println("SKIP-LIST: skipped bitstreams within identifier " + identifier);
} }
return true; return true;
} else { } else {
@@ -439,28 +432,6 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
} }
} }
private void logInfo(String message) {
if (handler != null) {
handler.logInfo(message);
} else {
System.out.println(message);
}
}
private void logError(String message) {
if (handler != null) {
handler.logError(message);
} else {
System.out.println(message);
}
}
private void logError(String message, Exception e) {
if (handler != null) {
handler.logError(message, e);
} else {
System.out.println(message);
}
}
@Override @Override
public void setVerbose(boolean isVerbose) { public void setVerbose(boolean isVerbose) {
this.isVerbose = isVerbose; this.isVerbose = isVerbose;
@@ -495,9 +466,4 @@ public class MediaFilterServiceImpl implements MediaFilterService, InitializingB
public void setFilterFormats(Map<String, List<String>> filterFormats) { public void setFilterFormats(Map<String, List<String>> filterFormats) {
this.filterFormats = filterFormats; this.filterFormats = filterFormats;
} }
@Override
public void setLogHandler(DSpaceRunnableHandler handler) {
this.handler = handler;
}
} }

View File

@@ -9,10 +9,9 @@ package org.dspace.app.mediafilter;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.InputStream; import java.io.InputStream;
import javax.imageio.ImageIO;
import org.apache.logging.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
import org.apache.pdfbox.rendering.PDFRenderer; import org.apache.pdfbox.rendering.PDFRenderer;
import org.dspace.content.Item; import org.dspace.content.Item;
@@ -26,9 +25,7 @@ import org.dspace.content.Item;
* @author Ivan Masár helix84@centrum.sk * @author Ivan Masár helix84@centrum.sk
* @author Jason Sherman jsherman@usao.edu * @author Jason Sherman jsherman@usao.edu
*/ */
public class PDFBoxThumbnail extends MediaFilter { public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFormats {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(PDFBoxThumbnail.class);
@Override @Override
public String getFilteredName(String oldFilename) { public String getFilteredName(String oldFilename) {
return oldFilename + ".jpg"; return oldFilename + ".jpg";
@@ -68,19 +65,30 @@ public class PDFBoxThumbnail extends MediaFilter {
@Override @Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose) public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception { throws Exception {
BufferedImage buf; PDDocument doc = PDDocument.load(source);
// Render the page image.
try ( PDDocument doc = PDDocument.load(source); ) {
PDFRenderer renderer = new PDFRenderer(doc); PDFRenderer renderer = new PDFRenderer(doc);
buf = renderer.renderImage(0); BufferedImage buf = renderer.renderImage(0);
} catch (InvalidPasswordException ex) { // ImageIO.write(buf, "PNG", new File("custom-render.png"));
log.error("PDF is encrypted. Cannot create thumbnail (item: {})", currentItem::getHandle); doc.close();
return null;
}
// Generate thumbnail derivative and return as IO stream.
JPEGFilter jpegFilter = new JPEGFilter(); JPEGFilter jpegFilter = new JPEGFilter();
return jpegFilter.getThumb(currentItem, buf, verbose); return jpegFilter.getThumb(currentItem, buf, verbose);
} }
@Override
public String[] getInputMIMETypes() {
return ImageIO.getReaderMIMETypes();
}
@Override
public String[] getInputDescriptions() {
return null;
}
@Override
public String[] getInputExtensions() {
// Temporarily disabled as JDK 1.6 only
// return ImageIO.getReaderFileSuffixes();
return null;
}
} }

View File

@@ -16,13 +16,11 @@ import java.io.InputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
import org.apache.pdfbox.text.PDFTextStripper; import org.apache.pdfbox.text.PDFTextStripper;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.services.ConfigurationService; import org.dspace.core.ConfigurationManager;
import org.dspace.services.factory.DSpaceServicesFactory;
/* /*
* *
@@ -32,7 +30,7 @@ import org.dspace.services.factory.DSpaceServicesFactory;
*/ */
public class PDFFilter extends MediaFilter { public class PDFFilter extends MediaFilter {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(PDFFilter.class); private static Logger log = Logger.getLogger(PDFFilter.class);
@Override @Override
public String getFilteredName(String oldFilename) { public String getFilteredName(String oldFilename) {
@@ -73,10 +71,8 @@ public class PDFFilter extends MediaFilter {
@Override @Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose) public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception { throws Exception {
ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
try { try {
boolean useTemporaryFile = configurationService.getBooleanProperty("pdffilter.largepdfs", false); boolean useTemporaryFile = ConfigurationManager.getBooleanProperty("pdffilter.largepdfs", false);
// get input stream from bitstream // get input stream from bitstream
// pass to filter, get string back // pass to filter, get string back
@@ -99,10 +95,6 @@ public class PDFFilter extends MediaFilter {
try { try {
pdfDoc = PDDocument.load(source); pdfDoc = PDDocument.load(source);
pts.writeText(pdfDoc, writer); pts.writeText(pdfDoc, writer);
} catch (InvalidPasswordException ex) {
log.error("PDF is encrypted. Cannot extract text (item: {})",
() -> currentItem.getHandle());
return null;
} finally { } finally {
try { try {
if (pdfDoc != null) { if (pdfDoc != null) {
@@ -127,7 +119,7 @@ public class PDFFilter extends MediaFilter {
} }
} catch (OutOfMemoryError oome) { } catch (OutOfMemoryError oome) {
log.error("Error parsing PDF document " + oome.getMessage(), oome); log.error("Error parsing PDF document " + oome.getMessage(), oome);
if (!configurationService.getBooleanProperty("pdffilter.skiponmemoryexception", false)) { if (!ConfigurationManager.getBooleanProperty("pdffilter.skiponmemoryexception", false)) {
throw oome; throw oome;
} }
} }

View File

@@ -10,7 +10,6 @@ package org.dspace.app.mediafilter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.apache.poi.POITextExtractor; import org.apache.poi.POITextExtractor;
import org.apache.poi.extractor.ExtractorFactory; import org.apache.poi.extractor.ExtractorFactory;
@@ -67,6 +66,6 @@ public class PoiWordFilter
} }
// return the extracted text as a stream. // return the extracted text as a stream.
return new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)); return new ByteArrayInputStream(text.getBytes());
} }
} }

View File

@@ -10,7 +10,7 @@ package org.dspace.app.mediafilter;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.InputStream; import java.io.InputStream;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.poi.POITextExtractor; import org.apache.poi.POITextExtractor;
import org.apache.poi.extractor.ExtractorFactory; import org.apache.poi.extractor.ExtractorFactory;
import org.apache.poi.hslf.extractor.PowerPointExtractor; import org.apache.poi.hslf.extractor.PowerPointExtractor;
@@ -23,7 +23,7 @@ import org.dspace.content.Item;
*/ */
public class PowerPointFilter extends MediaFilter { public class PowerPointFilter extends MediaFilter {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(PowerPointFilter.class); private static Logger log = Logger.getLogger(PowerPointFilter.class);
@Override @Override
public String getFilteredName(String oldFilename) { public String getFilteredName(String oldFilename) {

View File

@@ -0,0 +1,93 @@
/**
* 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.mediafilter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.log4j.Logger;
import org.dspace.content.Item;
import org.textmining.extraction.TextExtractor;
import org.textmining.extraction.word.WordTextExtractorFactory;
/*
*
* to do: helpful error messages - can't find mediafilter.cfg - can't
* instantiate filter - bitstream format doesn't exist.
*
*/
public class WordFilter extends MediaFilter {
private static Logger log = Logger.getLogger(WordFilter.class);
@Override
public String getFilteredName(String oldFilename) {
return oldFilename + ".txt";
}
/**
* @return String bundle name
*/
@Override
public String getBundleName() {
return "TEXT";
}
/**
* @return String bitstreamformat
*/
@Override
public String getFormatString() {
return "Text";
}
/**
* @return String description
*/
@Override
public String getDescription() {
return "Extracted text";
}
/**
* @param currentItem item
* @param source source input stream
* @param verbose verbose mode
* @return InputStream the resulting input stream
* @throws Exception if error
*/
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
// get input stream from bitstream
// pass to filter, get string back
try {
WordTextExtractorFactory factory = new WordTextExtractorFactory();
TextExtractor e = factory.textExtractor(source);
String extractedText = e.getText();
// if verbose flag is set, print out extracted text
// to STDOUT
if (verbose) {
System.out.println(extractedText);
}
// generate an input stream with the extracted text
byte[] textBytes = extractedText.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(textBytes);
return bais; // will this work? or will the byte array be out of scope?
} catch (IOException ioe) {
System.out.println("Invalid Word Format");
log.error("Error detected - Word File format not recognized: "
+ ioe.getMessage(), ioe);
throw ioe;
}
}
}

View File

@@ -16,7 +16,6 @@ import org.dspace.content.Collection;
import org.dspace.content.Community; import org.dspace.content.Community;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/** /**
* MediaFilterManager is the class that invokes the media/format filters over the * MediaFilterManager is the class that invokes the media/format filters over the
@@ -125,10 +124,4 @@ public interface MediaFilterService {
public void setSkipList(List<String> skipList); public void setSkipList(List<String> skipList);
public void setFilterFormats(Map<String, List<String>> filterFormats); public void setFilterFormats(Map<String, List<String>> filterFormats);
/**
* Set the log handler used in the DSpace scripts and processes framework
* @param handler
*/
public void setLogHandler(DSpaceRunnableHandler handler);
} }

View File

@@ -17,9 +17,9 @@ import java.util.List;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
import org.apache.commons.cli.PosixParser;
import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject; import org.dspace.content.DSpaceObject;
import org.dspace.content.crosswalk.CrosswalkException; import org.dspace.content.crosswalk.CrosswalkException;
@@ -175,7 +175,7 @@ public class Packager {
"flag can be used if you want to save (pipe) a report of all changes to a file, and " + "flag can be used if you want to save (pipe) a report of all changes to a file, and " +
"therefore need to bypass all user interaction."); "therefore need to bypass all user interaction.");
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new PosixParser();
CommandLine line = parser.parse(options, argv); CommandLine line = parser.parse(options, argv);
String sourceFile = null; String sourceFile = null;

View File

@@ -33,6 +33,7 @@ import org.dspace.core.ReloadableEntity;
@Table(name = "requestitem") @Table(name = "requestitem")
public class RequestItem implements ReloadableEntity<Integer> { public class RequestItem implements ReloadableEntity<Integer> {
@Id @Id
@Column(name = "requestitem_id") @Column(name = "requestitem_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "requestitem_seq") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "requestitem_seq")
@@ -53,6 +54,8 @@ public class RequestItem implements ReloadableEntity<Integer> {
@Column(name = "request_name", length = 64) @Column(name = "request_name", length = 64)
private String reqName; private String reqName;
// @Column(name = "request_message")
// @Lob
@Column(name = "request_message", columnDefinition = "text") @Column(name = "request_message", columnDefinition = "text")
private String reqMessage; private String reqMessage;
@@ -75,17 +78,16 @@ public class RequestItem implements ReloadableEntity<Integer> {
private Date request_date = null; private Date request_date = null;
@Column(name = "accept_request") @Column(name = "accept_request")
private boolean accept_request; private Boolean accept_request = null;
/** /**
* Protected constructor, create object using: * Protected constructor, create object using:
* {@link org.dspace.app.requestitem.service.RequestItemService#createRequest( * {@link org.dspace.app.requestitem.service.RequestItemService#createRequest(Context, Bitstream, Item,
* Context, Bitstream, Item, boolean, String, String, String)} * boolean, String, String, String)}
*/ */
protected RequestItem() { protected RequestItem() {
} }
@Override
public Integer getID() { public Integer getID() {
return requestitem_id; return requestitem_id;
} }

View File

@@ -19,15 +19,6 @@ import org.dspace.core.Context;
* @author Andrea Bollini * @author Andrea Bollini
*/ */
public interface RequestItemAuthorExtractor { public interface RequestItemAuthorExtractor {
public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
/** throws SQLException;
* Retrieve the auhtor to contact for a request copy of the give item.
*
* @param context DSpace context object
* @param item item to request
* @return An object containing name an email address to send the request to
* or null if no valid email address was found.
* @throws SQLException if database error
*/
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException;
} }

View File

@@ -1,228 +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.requestitem;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
import javax.mail.MessagingException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.requestitem.factory.RequestItemServiceFactory;
import org.dspace.app.requestitem.service.RequestItemService;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.core.Context;
import org.dspace.core.Email;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogHelper;
import org.dspace.eperson.EPerson;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Send item requests and responses by email.
*
* @author Mark H. Wood <mwood@iupui.edu>
*/
public class RequestItemEmailNotifier {
private static final Logger LOG = LogManager.getLogger();
private static final BitstreamService bitstreamService
= ContentServiceFactory.getInstance().getBitstreamService();
private static final ConfigurationService configurationService
= DSpaceServicesFactory.getInstance().getConfigurationService();
private static final HandleService handleService
= HandleServiceFactory.getInstance().getHandleService();
private static final RequestItemService requestItemService
= RequestItemServiceFactory.getInstance().getRequestItemService();
private static final RequestItemAuthorExtractor requestItemAuthorExtractor
= DSpaceServicesFactory.getInstance()
.getServiceManager()
.getServiceByName(null, RequestItemAuthorExtractor.class);
private RequestItemEmailNotifier() {}
/**
* Send the request to the approver(s).
*
* @param context current DSpace session.
* @param ri the request.
* @param responseLink link back to DSpace to send the response.
* @throws IOException passed through.
* @throws SQLException if the message was not sent.
*/
static public void sendRequest(Context context, RequestItem ri, String responseLink)
throws IOException, SQLException {
// Who is making this request?
RequestItemAuthor author = requestItemAuthorExtractor
.getRequestItemAuthor(context, ri.getItem());
String authorEmail = author.getEmail();
String authorName = author.getFullName();
// Build an email to the approver.
Email email = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
"request_item.author"));
email.addRecipient(authorEmail);
email.setReplyTo(ri.getReqEmail()); // Requester's address
email.addArgument(ri.getReqName()); // {0} Requester's name
email.addArgument(ri.getReqEmail()); // {1} Requester's address
email.addArgument(ri.isAllfiles() // {2} All bitstreams or just one?
? I18nUtil.getMessage("itemRequest.all") : ri.getBitstream().getName());
email.addArgument(handleService.getCanonicalForm(ri.getItem().getHandle()));
email.addArgument(ri.getItem().getName()); // {4} requested item's title
email.addArgument(ri.getReqMessage()); // {5} message from requester
email.addArgument(responseLink); // {6} Link back to DSpace for action
email.addArgument(authorName); // {7} corresponding author name
email.addArgument(authorEmail); // {8} corresponding author email
email.addArgument(configurationService.getProperty("dspace.name"));
email.addArgument(configurationService.getProperty("mail.helpdesk"));
// Send the email.
try {
email.send();
Bitstream bitstream = ri.getBitstream();
String bitstreamID;
if (null == bitstream) {
bitstreamID = "null";
} else {
bitstreamID = ri.getBitstream().getID().toString();
}
LOG.info(LogHelper.getHeader(context,
"sent_email_requestItem",
"submitter_id={},bitstream_id={},requestEmail={}"),
ri.getReqEmail(), bitstreamID, ri.getReqEmail());
} catch (MessagingException e) {
LOG.warn(LogHelper.getHeader(context,
"error_mailing_requestItem", e.getMessage()));
throw new IOException("Request not sent: " + e.getMessage());
}
}
/**
* Send the approver's response back to the requester, with files attached
* if approved.
*
* @param context current DSpace session.
* @param ri the request.
* @param subject email subject header value.
* @param message email body (may be empty).
* @throws IOException if sending failed.
*/
static public void sendResponse(Context context, RequestItem ri, String subject,
String message)
throws IOException {
// Build an email back to the requester.
Email email = new Email();
email.setContent("body", message);
email.setSubject(subject);
email.addRecipient(ri.getReqEmail());
if (ri.isAccept_request()) {
// Attach bitstreams.
try {
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)) {
email.addAttachment(bitstreamService.retrieve(context,
bitstream), bitstream.getName(),
bitstream.getFormat(context).getMIMEType());
}
}
}
} else {
Bitstream bitstream = ri.getBitstream();
email.addAttachment(bitstreamService.retrieve(context, bitstream),
bitstream.getName(),
bitstream.getFormat(context).getMIMEType());
}
email.send();
} catch (MessagingException | IOException | SQLException | AuthorizeException e) {
LOG.warn(LogHelper.getHeader(context,
"error_mailing_requestItem", e.getMessage()));
throw new IOException("Reply not sent: " + e.getMessage());
}
}
LOG.info(LogHelper.getHeader(context,
"sent_attach_requestItem", "token={}"), ri.getToken());
}
/**
* Send, to a repository administrator, a request to open access to a
* requested object.
*
* @param context current DSpace session
* @param ri the item request that the approver is handling
* @throws IOException if the message body cannot be loaded or the message
* cannot be sent.
*/
static public void requestOpenAccess(Context context, RequestItem ri)
throws IOException {
Email message = Email.getEmail(I18nUtil.getEmailFilename(context.getCurrentLocale(),
"request_item.admin"));
// Which Bitstream(s) requested?
Bitstream bitstream = ri.getBitstream();
String bitstreamName;
if (bitstream != null) {
bitstreamName = bitstream.getName();
} else {
bitstreamName = "all"; // TODO localize
}
// Which Item?
Item item = ri.getItem();
// Fill the message's placeholders.
EPerson approver = context.getCurrentUser();
message.addArgument(bitstreamName); // {0} bitstream name or "all"
message.addArgument(item.getHandle()); // {1} Item handle
message.addArgument(ri.getToken()); // {2} Request token
message.addArgument(approver.getFullName()); // {3} Approver's name
message.addArgument(approver.getEmail()); // {4} Approver's address
// Who gets this message?
String recipient;
EPerson submitter = item.getSubmitter();
if (submitter != null) {
recipient = submitter.getEmail();
} else {
recipient = configurationService.getProperty("mail.helpdesk");
}
if (null == recipient) {
recipient = configurationService.getProperty("mail.admin");
}
message.addRecipient(recipient);
// Send the message.
try {
message.send();
} catch (MessagingException ex) {
LOG.warn(LogHelper.getHeader(context, "error_mailing_requestItem",
ex.getMessage()));
throw new IOException("Open Access request not sent: " + ex.getMessage());
}
}
}

View File

@@ -9,14 +9,14 @@ package org.dspace.app.requestitem;
import java.sql.SQLException; import java.sql.SQLException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.I18nUtil; import org.dspace.core.I18nUtil;
import org.dspace.eperson.EPerson; import org.dspace.eperson.EPerson;
import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.EPersonService;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -30,6 +30,9 @@ import org.springframework.beans.factory.annotation.Autowired;
* @author Peter Dietz * @author Peter Dietz
*/ */
public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy { public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy {
private Logger log = Logger.getLogger(RequestItemHelpdeskStrategy.class);
@Autowired(required = true) @Autowired(required = true)
protected EPersonService ePersonService; protected EPersonService ePersonService;
@@ -38,11 +41,9 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy {
@Override @Override
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException { public RequestItemAuthor getRequestItemAuthor(Context context, Item item) throws SQLException {
ConfigurationService configurationService boolean helpdeskOverridesSubmitter = ConfigurationManager
= DSpaceServicesFactory.getInstance().getConfigurationService();
boolean helpdeskOverridesSubmitter = configurationService
.getBooleanProperty("request.item.helpdesk.override", false); .getBooleanProperty("request.item.helpdesk.override", false);
String helpDeskEmail = configurationService.getProperty("mail.helpdesk"); String helpDeskEmail = ConfigurationManager.getProperty("mail.helpdesk");
if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) { if (helpdeskOverridesSubmitter && StringUtils.isNotBlank(helpDeskEmail)) {
return getHelpDeskPerson(context, helpDeskEmail); return getHelpDeskPerson(context, helpDeskEmail);
@@ -63,8 +64,10 @@ public class RequestItemHelpdeskStrategy extends RequestItemSubmitterStrategy {
* @throws SQLException if database error * @throws SQLException if database error
*/ */
public RequestItemAuthor getHelpDeskPerson(Context context, String helpDeskEmail) throws SQLException { public RequestItemAuthor getHelpDeskPerson(Context context, String helpDeskEmail) throws SQLException {
EPerson helpdeskEPerson = null;
context.turnOffAuthorisationSystem(); context.turnOffAuthorisationSystem();
EPerson helpdeskEPerson = ePersonService.findByEmail(context, helpDeskEmail); helpdeskEPerson = ePersonService.findByEmail(context, helpDeskEmail);
context.restoreAuthSystemState(); context.restoreAuthSystemState();
if (helpdeskEPerson != null) { if (helpdeskEPerson != null) {

View File

@@ -10,13 +10,12 @@ package org.dspace.app.requestitem;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.content.MetadataValue; import org.dspace.content.MetadataValue;
import org.dspace.content.service.ItemService; import org.dspace.content.service.ItemService;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.I18nUtil; import org.dspace.core.I18nUtil;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
@@ -39,7 +38,6 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
@Override @Override
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
throws SQLException { throws SQLException {
RequestItemAuthor author = null;
if (emailMetadata != null) { if (emailMetadata != null) {
List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, emailMetadata); List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, emailMetadata);
if (vals.size() > 0) { if (vals.size() > 0) {
@@ -51,38 +49,19 @@ public class RequestItemMetadataStrategy extends RequestItemSubmitterStrategy {
fullname = nameVals.iterator().next().getValue(); fullname = nameVals.iterator().next().getValue();
} }
} }
if (StringUtils.isBlank(fullname)) { if (StringUtils.isBlank(fullname)) {
fullname = I18nUtil fullname = I18nUtil
.getMessage( .getMessage(
"org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed", "org.dspace.app.requestitem.RequestItemMetadataStrategy.unnamed",
context); context);
} }
author = new RequestItemAuthor(fullname, email); RequestItemAuthor author = new RequestItemAuthor(
fullname, email);
return author; return author;
} }
} else {
// Uses the basic strategy to look for the original submitter
author = super.getRequestItemAuthor(context, item);
// Is the author or his email null, so get the help desk or admin name and email
if (null == author || null == author.getEmail()) {
String email = null;
String name = null;
//First get help desk name and email
email = DSpaceServicesFactory.getInstance()
.getConfigurationService().getProperty("mail.helpdesk");
name = DSpaceServicesFactory.getInstance()
.getConfigurationService().getProperty("mail.helpdesk.name");
// If help desk mail is null get the mail and name of admin
if (email == null) {
email = DSpaceServicesFactory.getInstance()
.getConfigurationService().getProperty("mail.admin");
name = DSpaceServicesFactory.getInstance()
.getConfigurationService().getProperty("mail.admin.name");
} }
author = new RequestItemAuthor(name, email); return super.getRequestItemAuthor(context, item);
}
}
return author;
} }
public void setEmailMetadata(String emailMetadata) { public void setEmailMetadata(String emailMetadata) {

View File

@@ -9,53 +9,37 @@ package org.dspace.app.requestitem;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.apache.logging.log4j.LogManager; import org.apache.log4j.Logger;
import org.apache.logging.log4j.Logger;
import org.dspace.app.requestitem.dao.RequestItemDAO; import org.dspace.app.requestitem.dao.RequestItemDAO;
import org.dspace.app.requestitem.service.RequestItemService; import org.dspace.app.requestitem.service.RequestItemService;
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.Bitstream;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Constants;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.dspace.core.LogHelper;
import org.dspace.core.Utils; import org.dspace.core.Utils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
* Service implementation for the RequestItem object. * Service implementation for the RequestItem object.
* This class is responsible for all business logic calls for the RequestItem * This class is responsible for all business logic calls for the RequestItem object and is autowired by spring.
* object and is autowired by Spring.
* This class should never be accessed directly. * This class should never be accessed directly.
* *
* @author kevinvandevelde at atmire.com * @author kevinvandevelde at atmire.com
*/ */
public class RequestItemServiceImpl implements RequestItemService { public class RequestItemServiceImpl implements RequestItemService {
private final Logger log = LogManager.getLogger(); private final Logger log = Logger.getLogger(RequestItemServiceImpl.class);
@Autowired(required = true) @Autowired(required = true)
protected RequestItemDAO requestItemDAO; protected RequestItemDAO requestItemDAO;
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Autowired(required = true)
protected ResourcePolicyService resourcePolicyService;
protected RequestItemServiceImpl() { protected RequestItemServiceImpl() {
} }
@Override @Override
public String createRequest(Context context, Bitstream bitstream, Item item, public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail,
boolean allFiles, String reqEmail, String reqName, String reqMessage) String reqName, String reqMessage) throws SQLException {
throws SQLException {
RequestItem requestItem = requestItemDAO.create(context, new RequestItem()); RequestItem requestItem = requestItemDAO.create(context, new RequestItem());
requestItem.setToken(Utils.generateHexKey()); requestItem.setToken(Utils.generateHexKey());
@@ -69,15 +53,11 @@ public class RequestItemServiceImpl implements RequestItemService {
requestItemDAO.save(context, requestItem); requestItemDAO.save(context, requestItem);
log.debug("Created RequestItem with ID {} and token {}", if (log.isDebugEnabled()) {
requestItem::getID, requestItem::getToken); log.debug("Created requestitem_token " + requestItem.getID()
return requestItem.getToken(); + " with token " + requestItem.getToken() + "\"");
} }
return requestItem.getToken();
@Override
public List<RequestItem> findAll(Context context)
throws SQLException {
return requestItemDAO.findAll(context, RequestItem.class);
} }
@Override @Override
@@ -98,28 +78,4 @@ public class RequestItemServiceImpl implements RequestItemService {
log.error(e.getMessage()); log.error(e.getMessage());
} }
} }
@Override
public void delete(Context context, RequestItem requestItem) {
log.debug(LogHelper.getHeader(context, "delete_itemrequest", "request_id={}"),
requestItem.getID());
try {
requestItemDAO.delete(context, requestItem);
} catch (SQLException e) {
log.error(e.getMessage());
}
}
@Override
public boolean isRestricted(Context context, DSpaceObject o)
throws SQLException {
List<ResourcePolicy> policies = authorizeService
.getPoliciesActionFilter(context, o, Constants.READ);
for (ResourcePolicy rp : policies) {
if (resourcePolicyService.isDateValid(rp)) {
return false;
}
}
return true;
}
} }

View File

@@ -23,22 +23,13 @@ public class RequestItemSubmitterStrategy implements RequestItemAuthorExtractor
public RequestItemSubmitterStrategy() { public RequestItemSubmitterStrategy() {
} }
/**
* Returns the submitter of an Item as RequestItemAuthor or null if the
* Submitter is deleted.
*
* @return The submitter of the item or null if the submitter is deleted
* @throws SQLException if database error
*/
@Override @Override
public RequestItemAuthor getRequestItemAuthor(Context context, Item item) public RequestItemAuthor getRequestItemAuthor(Context context, Item item)
throws SQLException { throws SQLException {
EPerson submitter = item.getSubmitter(); EPerson submitter = item.getSubmitter();
RequestItemAuthor author = null; RequestItemAuthor author = new RequestItemAuthor(
if (null != submitter) {
author = new RequestItemAuthor(
submitter.getFullName(), submitter.getEmail()); submitter.getFullName(), submitter.getEmail());
}
return author; return author;
} }
} }

View File

@@ -15,21 +15,13 @@ import org.dspace.core.GenericDAO;
/** /**
* Database Access Object interface class for the RequestItem object. * Database Access Object interface class for the RequestItem object.
* The implementation of this class is responsible for all database calls for * The implementation of this class is responsible for all database calls for the RequestItem object and is autowired
* the RequestItem object and is autowired by Spring. * by spring
* This class should only be accessed from a single service and should never be * This class should only be accessed from a single service and should never be exposed outside of the API
* exposed outside of the API.
* *
* @author kevinvandevelde at atmire.com * @author kevinvandevelde at atmire.com
*/ */
public interface RequestItemDAO extends GenericDAO<RequestItem> { public interface RequestItemDAO extends GenericDAO<RequestItem> {
/**
* Fetch a request named by its unique token (passed in emails).
*
* @param context the current DSpace context.
* @param token uniquely identifies the request.
* @return the found request (or {@code null}?)
* @throws SQLException passed through.
*/
public RequestItem findByToken(Context context, String token) throws SQLException; public RequestItem findByToken(Context context, String token) throws SQLException;
} }

View File

@@ -8,19 +8,17 @@
package org.dspace.app.requestitem.dao.impl; package org.dspace.app.requestitem.dao.impl;
import java.sql.SQLException; import java.sql.SQLException;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.app.requestitem.RequestItem; import org.dspace.app.requestitem.RequestItem;
import org.dspace.app.requestitem.RequestItem_;
import org.dspace.app.requestitem.dao.RequestItemDAO; import org.dspace.app.requestitem.dao.RequestItemDAO;
import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context; import org.dspace.core.Context;
import org.hibernate.Criteria;
import org.hibernate.criterion.Restrictions;
/** /**
* Hibernate implementation of the Database Access Object interface class for the RequestItem object. * Hibernate implementation of the Database Access Object interface class for the RequestItem object.
* This class is responsible for all database calls for the RequestItem object and is autowired by Spring. * This class is responsible for all database calls for the RequestItem object and is autowired by spring
* This class should never be accessed directly. * This class should never be accessed directly.
* *
* @author kevinvandevelde at atmire.com * @author kevinvandevelde at atmire.com
@@ -32,11 +30,10 @@ public class RequestItemDAOImpl extends AbstractHibernateDAO<RequestItem> implem
@Override @Override
public RequestItem findByToken(Context context, String token) throws SQLException { public RequestItem findByToken(Context context, String token) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); Criteria criteria = createCriteria(context, RequestItem.class);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RequestItem.class); criteria.add(Restrictions.eq("token", token));
Root<RequestItem> requestItemRoot = criteriaQuery.from(RequestItem.class); return uniqueResult(criteria);
criteriaQuery.select(requestItemRoot);
criteriaQuery.where(criteriaBuilder.equal(requestItemRoot.get(RequestItem_.token), token));
return uniqueResult(context, criteriaQuery, false, RequestItem.class);
} }
} }

View File

@@ -1,21 +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/
*/
/**
* 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".
*
* <p>This package includes several "strategy" classes which discover responsible
* parties in various ways. See {@link RequestItemSubmitterStrategy} and the
* classes which extend it. A strategy class must be configured and identified
* as {@link RequestItemAuthorExtractor} for injection into code which requires
* Request a Copy services.
*/
package org.dspace.app.requestitem;

View File

@@ -8,18 +8,16 @@
package org.dspace.app.requestitem.service; package org.dspace.app.requestitem.service;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List;
import org.dspace.app.requestitem.RequestItem; import org.dspace.app.requestitem.RequestItem;
import org.dspace.content.Bitstream; import org.dspace.content.Bitstream;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item; import org.dspace.content.Item;
import org.dspace.core.Context; import org.dspace.core.Context;
/** /**
* Service interface class for the RequestItem object. * Service interface class for the RequestItem object.
* The implementation of this class is responsible for all business logic calls * The implementation of this class is responsible for all business logic calls for the RequestItem object and is
* for the RequestItem object and is autowired by Spring. * autowired by spring
* *
* @author kevinvandevelde at atmire.com * @author kevinvandevelde at atmire.com
*/ */
@@ -39,27 +37,10 @@ public interface RequestItemService {
* @return the token of the request item * @return the token of the request item
* @throws SQLException if database error * @throws SQLException if database error
*/ */
public String createRequest(Context context, Bitstream bitstream, Item item, public String createRequest(Context context, Bitstream bitstream, Item item, boolean allFiles, String reqEmail,
boolean allFiles, String reqEmail, String reqName, String reqMessage) String reqName, String reqMessage)
throws SQLException; throws SQLException;
/**
* Fetch all item requests.
*
* @param context current DSpace session.
* @return all item requests.
* @throws java.sql.SQLException passed through.
*/
public List<RequestItem> findAll(Context context)
throws SQLException;
/**
* Retrieve a request by its token.
*
* @param context current DSpace session.
* @param token the token identifying the request.
* @return the matching request, or null if not found.
*/
public RequestItem findByToken(Context context, String token); public RequestItem findByToken(Context context, String token);
/** /**
@@ -70,21 +51,5 @@ public interface RequestItemService {
*/ */
public void update(Context context, RequestItem requestItem); public void update(Context context, RequestItem requestItem);
/**
* Remove the record from the database.
*
* @param context current DSpace context.
* @param request record to be removed.
*/
public void delete(Context context, RequestItem request);
/**
* Is there at least one valid READ resource policy for this object?
* @param context current DSpace session.
* @param o the object.
* @return true if a READ policy applies.
* @throws SQLException passed through.
*/
public boolean isRestricted(Context context, DSpaceObject o)
throws SQLException;
} }

View File

@@ -15,8 +15,8 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.Logger; import org.apache.log4j.Logger;
import org.dspace.app.sfx.service.SFXFileReaderService; import org.dspace.app.sfx.service.SFXFileReaderService;
import org.dspace.content.DCPersonName; import org.dspace.content.DCPersonName;
import org.dspace.content.Item; import org.dspace.content.Item;
@@ -58,7 +58,7 @@ public class SFXFileReaderServiceImpl implements SFXFileReaderService {
/** /**
* log4j logger * log4j logger
*/ */
private final Logger log = org.apache.logging.log4j.LogManager.getLogger(SFXFileReaderServiceImpl.class); private final Logger log = Logger.getLogger(SFXFileReaderServiceImpl.class);
protected SFXFileReaderServiceImpl() { protected SFXFileReaderServiceImpl() {
} }

View File

@@ -9,6 +9,8 @@
/** /**
* <p>SFX/OpenURL link server support.</p> * <p>SFX/OpenURL link server support.</p>
* *
* @see org.dspace.app.webui.jsptag.SFXLinkTag
* @see org.dspace.app.xmlui.aspect.artifactbrowser.ItemViewer
*/ */
package org.dspace.app.sfx; package org.dspace.app.sfx;

View File

@@ -0,0 +1,49 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.sherpa;
/**
* POJO representation for a SHERPA journal
*
* @author Andrea Bollini
*/
public class SHERPAJournal {
private String title;
private String issn;
private String zetopub;
private String romeopub;
public SHERPAJournal(String title, String issn, String zetopub,
String romeopub) {
super();
this.title = title;
this.issn = issn;
this.zetopub = zetopub;
this.romeopub = romeopub;
}
public String getTitle() {
return title;
}
public String getIssn() {
return issn;
}
public String getZetopub() {
return zetopub;
}
public String getRomeopub() {
return romeopub;
}
}

View File

@@ -0,0 +1,163 @@
/**
* 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.sherpa;
import java.util.List;
/**
* POJO representation for a SHERPA Publisher record
*
* @author Andrea Bollini
*/
public class SHERPAPublisher {
private String name;
private String alias;
private String homeurl;
private String prearchiving;
private List<String> prerestriction;
private String postarchiving;
private List<String> postrestriction;
private String pubarchiving;
private List<String> pubrestriction;
private List<String> condition;
private String paidaccessurl;
private String paidaccessname;
private String paidaccessnotes;
private List<String[]> copyright;
private String romeocolour;
private String dateadded;
private String dateupdated;
public SHERPAPublisher(String name, String alias, String homeurl,
String prearchiving, List<String> prerestriction,
String postarchiving, List<String> postrestriction,
String pubarchiving, List<String> pubrestriction,
List<String> condition, String paidaccessurl,
String paidaccessname, String paidaccessnotes,
List<String[]> copyright, String romeocolour, String datedded,
String dateupdated) {
this.name = name;
this.alias = alias;
this.homeurl = homeurl;
this.prearchiving = prearchiving;
this.prerestriction = prerestriction;
this.postarchiving = postarchiving;
this.postrestriction = postrestriction;
this.pubarchiving = pubarchiving;
this.pubrestriction = pubrestriction;
this.condition = condition;
this.paidaccessurl = paidaccessurl;
this.paidaccessname = paidaccessname;
this.paidaccessnotes = paidaccessnotes;
this.copyright = copyright;
this.romeocolour = romeocolour;
this.dateadded = datedded;
this.dateupdated = dateupdated;
}
public String getName() {
return name;
}
public String getAlias() {
return alias;
}
public String getHomeurl() {
return homeurl;
}
public String getPrearchiving() {
return prearchiving;
}
public List<String> getPrerestriction() {
return prerestriction;
}
public String getPostarchiving() {
return postarchiving;
}
public List<String> getPostrestriction() {
return postrestriction;
}
public String getPubarchiving() {
return pubarchiving;
}
public List<String> getPubrestriction() {
return pubrestriction;
}
public List<String> getCondition() {
return condition;
}
public String getPaidaccessurl() {
return paidaccessurl;
}
public String getPaidaccessname() {
return paidaccessname;
}
public String getPaidaccessnotes() {
return paidaccessnotes;
}
public List<String[]> getCopyright() {
return copyright;
}
public String getRomeocolour() {
return romeocolour;
}
public String getDatedded() {
return dateadded;
}
public String getDateupdated() {
return dateupdated;
}
}

View File

@@ -0,0 +1,201 @@
/**
* 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.sherpa;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.lang.StringUtils;
import org.dspace.app.util.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* JAVA representation for a SHERPA API Response
*
* @author Andrea Bollini
*/
public class SHERPAResponse {
private boolean error;
private String message;
private String license;
private String licenseURL;
private String disclaimer;
private List<SHERPAJournal> journals;
private List<SHERPAPublisher> publishers;
public SHERPAResponse(InputStream xmlData) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setValidating(false);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder db = factory.newDocumentBuilder();
Document inDoc = db.parse(xmlData);
Element xmlRoot = inDoc.getDocumentElement();
Element headersElement = XMLUtils.getSingleElement(xmlRoot,
"header");
Element journalsElement = XMLUtils.getSingleElement(xmlRoot,
"journals");
Element publishersElement = XMLUtils.getSingleElement(xmlRoot,
"publishers");
message = XMLUtils.getElementValue(headersElement, "message");
if (StringUtils.isNotBlank(message)) {
error = true;
return;
}
license = XMLUtils.getElementValue(headersElement, "license");
licenseURL = XMLUtils.getElementValue(headersElement, "licenseurl");
disclaimer = XMLUtils.getElementValue(headersElement, "disclaimer");
List<Element> journalsList = XMLUtils.getElementList(
journalsElement, "journal");
List<Element> publishersList = XMLUtils.getElementList(
publishersElement, "publisher");
if (journalsList != null) {
journals = new LinkedList<SHERPAJournal>();
for (Element journalElement : journalsList) {
journals.add(new SHERPAJournal(
XMLUtils.getElementValue(journalElement, "jtitle"),
XMLUtils.getElementValue(journalElement, "issn"),
XMLUtils.getElementValue(journalElement, "zetopub"),
XMLUtils.getElementValue(journalElement, "romeopub")));
}
}
if (publishersList != null) {
publishers = new LinkedList<SHERPAPublisher>();
for (Element publisherElement : publishersList) {
Element preprintsElement = XMLUtils.getSingleElement(
publisherElement, "preprints");
Element preprintsRestrictionElement = XMLUtils
.getSingleElement(publisherElement,
"prerestrictions");
Element postprintsElement = XMLUtils.getSingleElement(
publisherElement, "postprints");
Element postprintsRestrictionElement = XMLUtils
.getSingleElement(publisherElement,
"postrestrictions");
Element pdfversionElement = XMLUtils.getSingleElement(
publisherElement, "pdfversion");
Element pdfversionRestrictionElement = XMLUtils
.getSingleElement(publisherElement,
"pdfrestrictions");
Element conditionsElement = XMLUtils.getSingleElement(
publisherElement, "conditions");
Element paidaccessElement = XMLUtils.getSingleElement(
publisherElement, "paidaccess");
Element copyrightlinksElement = XMLUtils.getSingleElement(
publisherElement, "copyrightlinks");
publishers
.add(new SHERPAPublisher(XMLUtils.getElementValue(
publisherElement, "name"),
XMLUtils.getElementValue(publisherElement,
"alias"), XMLUtils.getElementValue(
publisherElement, "homeurl"),
XMLUtils.getElementValue(preprintsElement,
"prearchiving"),
XMLUtils.getElementValueList(
preprintsRestrictionElement,
"prerestriction"),
XMLUtils.getElementValue(postprintsElement,
"postarchiving"),
XMLUtils.getElementValueList(
postprintsRestrictionElement,
"postrestriction"),
XMLUtils.getElementValue(pdfversionElement,
"pdfarchiving"),
XMLUtils.getElementValueList(
pdfversionRestrictionElement,
"pdfrestriction"),
XMLUtils
.getElementValueList(
conditionsElement,
"condition"), XMLUtils
.getElementValue(paidaccessElement,
"paidaccessurl"), XMLUtils
.getElementValue(paidaccessElement,
"paidaccessname"), XMLUtils
.getElementValue(paidaccessElement,
"paidaccessnotes"),
XMLUtils.getElementValueArrayList(
copyrightlinksElement,
"copyrightlink",
"copyrightlinktext",
"copyrightlinkurl"), XMLUtils
.getElementValue(publisherElement,
"romeocolour"), XMLUtils
.getElementValue(publisherElement,
"dateadded"), XMLUtils
.getElementValue(publisherElement,
"dateupdated")));
}
}
} catch (Exception e) {
error = true;
}
}
public SHERPAResponse(String message) {
this.message = message;
this.error = true;
}
public boolean isError() {
return error;
}
public String getMessage() {
return message;
}
public String getLicense() {
return license;
}
public String getLicenseURL() {
return licenseURL;
}
public String getDisclaimer() {
return disclaimer;
}
public List<SHERPAJournal> getJournals() {
return journals;
}
public List<SHERPAPublisher> getPublishers() {
return publishers;
}
}

View File

@@ -7,15 +7,7 @@
*/ */
package org.dspace.app.sherpa; package org.dspace.app.sherpa;
import java.io.IOException; import org.apache.commons.lang.StringUtils;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import javax.annotation.PostConstruct;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
@@ -24,42 +16,21 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager; import org.apache.log4j.Logger;
import org.apache.logging.log4j.Logger; import org.dspace.core.ConfigurationManager;
import org.dspace.app.sherpa.v2.SHERPAPublisherResponse;
import org.dspace.app.sherpa.v2.SHERPAResponse;
import org.dspace.app.sherpa.v2.SHERPAUtils;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
/**
* SHERPAService is responsible for making the HTTP call to the SHERPA v2 API
* for SHERPASubmitService.
* Note, this service is ported from DSpace 6 for the ability to search policies by ISSN
* There are also new DataProvider implementations provided for use as 'external sources'
* of journal and publisher data
* @see org.dspace.external.provider.impl.SHERPAv2JournalDataProvider
* @see org.dspace.external.provider.impl.SHERPAv2PublisherDataProvider
* @author Kim Shepherd
*/
public class SHERPAService { public class SHERPAService {
private CloseableHttpClient client = null; private CloseableHttpClient client = null;
private int maxNumberOfTries; private int maxNumberOfTries;
private long sleepBetweenTimeouts; private long sleepBetweenTimeouts;
private int timeout = 5000; private int timeout = 5000;
private String endpoint = null;
private String apiKey = null;
/** log4j category */
private static final Logger log = LogManager.getLogger(SHERPAService.class);
@Autowired
ConfigurationService configurationService;
/** /**
* Create a new HTTP builder with sensible defaults in constructor * log4j category
*/ */
private static final Logger log = Logger.getLogger(SHERPAService.class);
public SHERPAService() { public SHERPAService() {
HttpClientBuilder builder = HttpClientBuilder.create(); HttpClientBuilder builder = HttpClientBuilder.create();
// httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as // httpclient 4.3+ doesn't appear to have any sensible defaults any more. Setting conservative defaults as
@@ -70,153 +41,10 @@ public class SHERPAService {
.build(); .build();
} }
/**
* Complete initialization of the Bean.
*/
@SuppressWarnings("unused")
@PostConstruct
private void init() {
// Get endoint and API key from configuration
endpoint = configurationService.getProperty("sherpa.romeo.url",
"https://v2.sherpa.ac.uk/cgi/retrieve");
apiKey = configurationService.getProperty("sherpa.romeo.apikey");
}
/**
* Search the SHERPA v2 API for a journal policy data using the supplied ISSN.
* If the API key is missing, or the HTTP response is non-OK or does not complete
* successfully, a simple error response will be returned.
* Otherwise, the response body will be passed to SHERPAResponse for parsing as JSON
* and the final result returned to the calling method
* @param query ISSN string to pass in an "issn equals" API query
* @return SHERPAResponse containing an error or journal policies
*/
public SHERPAResponse searchByJournalISSN(String query) { public SHERPAResponse searchByJournalISSN(String query) {
return performRequest("publication", "issn", "equals", query, 0, 1); String endpoint = ConfigurationManager.getProperty("sherpa.romeo.url");
} String apiKey = ConfigurationManager.getProperty("sherpa.romeo.apikey");
/**
* Perform an API request to the SHERPA v2 API - this could be a search or a get for any entity type
* but the return object here must be a SHERPAPublisherResponse not the journal-centric SHERPAResponse
* For more information about the type, field and predicate arguments, see the SHERPA v2 API documentation
* @param type entity type eg "publisher"
* @param field field eg "issn" or "title"
* @param predicate predicate eg "equals" or "contains-word"
* @param value the actual value to search for (eg an ISSN or partial title)
* @param start start / offset of search results
* @param limit maximum search results to return
* @return SHERPAPublisherResponse object
*/
public SHERPAPublisherResponse performPublisherRequest(String type, String field, String predicate, String value,
int start, int limit) {
// API Key is *required* for v2 API calls
if (null == apiKey) {
log.error("SHERPA ROMeO API Key missing: please register for an API key and set sherpa.romeo.apikey");
return new SHERPAPublisherResponse("SHERPA/RoMEO configuration invalid or missing");
}
HttpGet method = null;
SHERPAPublisherResponse sherpaResponse = null;
int numberOfTries = 0;
while (numberOfTries < maxNumberOfTries && sherpaResponse == null) {
numberOfTries++;
log.debug(String.format(
"Trying to contact SHERPA/RoMEO - attempt %d of %d; timeout is %d; sleep between timeouts is %d",
numberOfTries,
maxNumberOfTries,
timeout,
sleepBetweenTimeouts));
try {
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();
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 resonse 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");
}
} catch (URISyntaxException e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAPublisherResponse(errorMessage);
} catch (IOException e) {
String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAPublisherResponse(errorMessage);
} catch (InterruptedException e) {
String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAPublisherResponse(errorMessage);
} finally {
if (method != null) {
method.releaseConnection();
}
}
}
if (sherpaResponse == null) {
log.debug("SHERPA response is still null");
sherpaResponse = new SHERPAPublisherResponse(
"Error processing the SHERPA/RoMEO answer");
}
// Return the final response
return sherpaResponse;
}
/**
* Perform an API request to the SHERPA v2 API - this could be a search or a get for any entity type
* For more information about the type, field and predicate arguments, see the SHERPA v2 API documentation
* @param type entity type eg "publication" or "publisher"
* @param field field eg "issn" or "title"
* @param predicate predicate eg "equals" or "contains-word"
* @param value the actual value to search for (eg an ISSN or partial title)
* @param start start / offset of search results
* @param limit maximum search results to return
* @return SHERPAResponse object
*/
public SHERPAResponse performRequest(String type, String field, String predicate, String value,
int start, int limit) {
// API Key is *required* for v2 API calls
if (null == apiKey) {
log.error("SHERPA ROMeO API Key missing: please register for an API key and set sherpa.romeo.apikey");
return new SHERPAResponse("SHERPA/RoMEO configuration invalid or missing");
}
HttpGet method = null; HttpGet method = null;
SHERPAResponse sherpaResponse = null; SHERPAResponse sherpaResponse = null;
@@ -225,65 +53,50 @@ public class SHERPAService {
while (numberOfTries < maxNumberOfTries && sherpaResponse == null) { while (numberOfTries < maxNumberOfTries && sherpaResponse == null) {
numberOfTries++; numberOfTries++;
if (log.isDebugEnabled()) {
log.debug(String.format( log.debug(String.format(
"Trying to contact SHERPA/RoMEO - attempt %d of %d; timeout is %d; sleep between timeouts is %d", "Trying to contact SHERPA/RoMEO - attempt %d of %d; timeout is %d; sleep between timeouts is %d",
numberOfTries, numberOfTries,
maxNumberOfTries, maxNumberOfTries,
timeout, timeout,
sleepBetweenTimeouts)); sleepBetweenTimeouts));
}
try { try {
Thread.sleep(sleepBetweenTimeouts); Thread.sleep(sleepBetweenTimeouts);
// Construct a default HTTP method (first result) URIBuilder uriBuilder = new URIBuilder(endpoint);
method = constructHttpGet(type, field, predicate, value, start, limit); uriBuilder.addParameter("issn", query);
uriBuilder.addParameter("versions", "all");
if (StringUtils.isNotBlank(apiKey)) {
uriBuilder.addParameter("ak", apiKey);
}
method = new HttpGet(uriBuilder.build());
method.setConfig(RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build());
// Execute the method.
// Execute the method
HttpResponse response = client.execute(method); HttpResponse response = client.execute(method);
int statusCode = response.getStatusLine().getStatusCode(); int statusCode = response.getStatusLine().getStatusCode();
log.debug(response.getStatusLine().getStatusCode() + ": "
+ response.getStatusLine().getReasonPhrase());
if (statusCode != HttpStatus.SC_OK) { if (statusCode != HttpStatus.SC_OK) {
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: " sherpaResponse = new SHERPAResponse("SHERPA/RoMEO return not OK status: "
+ statusCode); + statusCode);
String errorBody = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
log.error("Error from SHERPA HTTP request: " + errorBody);
} }
HttpEntity responseBody = response.getEntity(); HttpEntity responseBody = response.getEntity();
// If the response body is valid, pass to SHERPAResponse for parsing as JSON
if (null != responseBody) { if (null != responseBody) {
log.debug("Non-null SHERPA resonse received for query of " + value); sherpaResponse = new SHERPAResponse(responseBody.getContent());
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 { } else {
log.debug("Empty SHERPA response body for query on " + value);
sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response"); sherpaResponse = new SHERPAResponse("SHERPA/RoMEO returned no response");
} }
} catch (URISyntaxException e) { } catch (Exception e) {
String errorMessage = "Error building SHERPA v2 API URI: " + e.getMessage(); log.warn("Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage(), e);
log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage);
} catch (IOException e) {
String errorMessage = "Encountered exception while contacting SHERPA/RoMEO: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage);
} catch (InterruptedException e) {
String errorMessage = "Encountered exception while sleeping thread: " + e.getMessage();
log.error(errorMessage, e);
sherpaResponse = new SHERPAResponse(errorMessage);
} finally { } finally {
if (method != null) { if (method != null) {
method.releaseConnection(); method.releaseConnection();
@@ -292,116 +105,13 @@ public class SHERPAService {
} }
if (sherpaResponse == null) { if (sherpaResponse == null) {
log.debug("SHERPA response is still null");
sherpaResponse = new SHERPAResponse( sherpaResponse = new SHERPAResponse(
"Error processing the SHERPA/RoMEO answer"); "Error processing the SHERPA/RoMEO answer");
} }
// Return the final response
return sherpaResponse; return sherpaResponse;
} }
/**
* Construct HTTP GET object for a "field,predicate,value" query with default start, limit
* eg. "title","contains-word","Lancet" or "issn","equals","1234-1234"
* @param field the field (issn, title, etc)
* @param predicate the predicate (contains-word, equals, etc - see API docs)
* @param value the query value itself
* @return HttpGet method which can then be executed by the client
* @throws URISyntaxException if the URL build fails
*/
public HttpGet constructHttpGet(String type, String field, String predicate, String value)
throws URISyntaxException {
return constructHttpGet(type, field, predicate, value, 0, 1);
}
/**
* Construct HTTP GET object for a "field,predicate,value" query
* eg. "title","contains-word","Lancet" or "issn","equals","1234-1234"
* @param field the field (issn, title, etc)
* @param predicate the predicate (contains-word, equals, etc - see API docs)
* @param value the query value itself
* @param start row offset
* @param limit number of results to return
* @return HttpGet object to be executed by the client
* @throws URISyntaxException
*/
public HttpGet constructHttpGet(String type, String field, String predicate, String value, int start, int limit)
throws URISyntaxException {
// Sanitise query string (strip some characters) field, predicate and value
if (null == type) {
type = "publication";
}
field = SHERPAUtils.sanitiseQuery(field);
predicate = SHERPAUtils.sanitiseQuery(predicate);
value = SHERPAUtils.sanitiseQuery(value);
type = SHERPAUtils.sanitiseQuery(type);
// Build URL based on search query
URIBuilder uriBuilder = new URIBuilder(endpoint);
uriBuilder.addParameter("item-type", type);
uriBuilder.addParameter("filter", "[[\"" + field + "\",\"" + predicate + "\",\"" + value + "\"]]");
uriBuilder.addParameter("format", "Json");
// Set optional start (offset) and limit parameters
if (start >= 0) {
uriBuilder.addParameter("offset", String.valueOf(start));
}
if (limit > 0) {
uriBuilder.addParameter("limit", String.valueOf(limit));
}
if (StringUtils.isNotBlank(apiKey)) {
uriBuilder.addParameter("api-key", apiKey);
}
log.debug("SHERPA API URL: " + uriBuilder.toString());
// Create HTTP GET object
HttpGet method = new HttpGet(uriBuilder.build());
// Set connection parameters
int timeout = 5000;
method.setConfig(RequestConfig.custom()
.setConnectionRequestTimeout(timeout)
.setConnectTimeout(timeout)
.setSocketTimeout(timeout)
.build());
return method;
}
/**
* Prepare the API query for execution by the HTTP client
* @param query ISSN query string
* @param endpoint API endpoint (base URL)
* @param apiKey API key parameter
* @return URI object
* @throws URISyntaxException
*/
public URI prepareQuery(String query, String endpoint, String apiKey) throws URISyntaxException {
// Sanitise query string
query = SHERPAUtils.sanitiseQuery(query);
// Instantiate URI builder
URIBuilder uriBuilder = new URIBuilder(endpoint);
// Build URI parameters from supplied values
uriBuilder.addParameter("item-type", "publication");
// Log warning if no query is supplied
if (null == query) {
log.warn("No ISSN supplied as query string for SHERPA service search");
}
uriBuilder.addParameter("filter", "[[\"issn\",\"equals\",\"" + query + "\"]]");
uriBuilder.addParameter("format", "Json");
if (StringUtils.isNotBlank(apiKey)) {
uriBuilder.addParameter("api-key", apiKey);
}
log.debug("Would search SHERPA endpoint with " + uriBuilder.toString());
// Return final built URI
return uriBuilder.build();
}
public void setMaxNumberOfTries(int maxNumberOfTries) { public void setMaxNumberOfTries(int maxNumberOfTries) {
this.maxNumberOfTries = maxNumberOfTries; this.maxNumberOfTries = maxNumberOfTries;
} }

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