mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge remote-tracking branch 'upstream/main' into w2p-72472_Delete-eperson
This commit is contained in:
29
.codecov.yml
Normal file
29
.codecov.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
# 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
|
||||
|
||||
# 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:
|
||||
# For each PR, make sure the coverage of the new code is within 1% of current overall coverage.
|
||||
# We let 'patch' be more lenient as we only require *project* coverage to not drop significantly.
|
||||
target: auto
|
||||
threshold: 1%
|
||||
|
||||
# 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
|
77
.travis.yml
77
.travis.yml
@@ -1,46 +1,55 @@
|
||||
# DSpace's Travis CI Configuration
|
||||
# Builds: https://travis-ci.com/github/DSpace/DSpace
|
||||
# Travis configuration guide/validation: https://config.travis-ci.com/explore
|
||||
language: java
|
||||
sudo: false
|
||||
# TODO: Upgrade to Bionic
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
# Give Maven 1GB of memory to work with
|
||||
- MAVEN_OPTS=-Xmx1024M
|
||||
os: linux
|
||||
|
||||
jdk:
|
||||
# DS-3384 Oracle JDK has DocLint enabled by default.
|
||||
# Let's use this to catch any newly introduced DocLint issues.
|
||||
- oraclejdk11
|
||||
|
||||
## 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
|
||||
# Define global environment variables (shared across all jobs)
|
||||
env:
|
||||
global:
|
||||
# Suppress all Maven "downloading" messages in Travis logs (see https://stackoverflow.com/a/35653426)
|
||||
# This also slightly speeds builds in Travis, as there is less logging
|
||||
- HIDE_MAVEN_DOWNLOADS="-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
|
||||
# Give Maven 1GB of memory to work with
|
||||
- MAVEN_OPTS="-Xmx1024M $HIDE_MAVEN_DOWNLOADS"
|
||||
# Maven options which will skip ALL code validation checks. Includes skipping:
|
||||
# - 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
|
||||
# (Useful for builds which don't need to repeat code checks)
|
||||
- SKIP_CODE_CHECKS="-Denforcer.skip=true -Dcheckstyle.skip=true -Dlicense.skip=true -Dxml.skip=true"
|
||||
|
||||
before_install:
|
||||
# Remove outdated settings.xml from Travis builds. Workaround for https://github.com/travis-ci/travis-ci/issues/4629
|
||||
- rm ~/.m2/settings.xml
|
||||
# Create two jobs to run Unit & Integration tests in parallel.
|
||||
# These jobs only differ in the TEST_FLAGS defined below,
|
||||
# and otherwise share all the other configs in this file
|
||||
jobs:
|
||||
include:
|
||||
- name: "Run Unit Tests & Check Code"
|
||||
# NOTE: unit tests include deprecated REST API v6 (as it has unit tests)
|
||||
env: TEST_FLAGS="-DskipUnitTests=false -Pdspace-rest"
|
||||
- name: "Run Integration Tests"
|
||||
# NOTE: skips code checks, as they are already done by Unit Test job
|
||||
env: TEST_FLAGS="-DskipIntegrationTests=false $SKIP_CODE_CHECKS"
|
||||
|
||||
# Skip install stage, as we'll do it below
|
||||
install: "echo 'Skipping install stage, dependencies will be downloaded during build and test stages.'"
|
||||
# Skip 'install' process to save time. We build/install/test all at once in "script" below.
|
||||
install: skip
|
||||
|
||||
# Build DSpace and run both Unit and Integration Tests
|
||||
script:
|
||||
# Summary of flags used (below):
|
||||
# license:check => Validate all source code license headers
|
||||
# -DskipTests=false => Enable DSpace Unit Tests
|
||||
# -DskipITs=false => Enable DSpace Integration Tests
|
||||
# -Pdspace-rest => Enable optional dspace-rest module as part of build
|
||||
# -P !assembly => Skip assembly of "dspace-installer" directory (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 -DskipTests=false -DskipITs=false -Pdspace-rest -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"
|
||||
# Build DSpace and run configured tests (see 'jobs' above)
|
||||
# Notes on flags used:
|
||||
# -B => Maven batch/non-interactive mode (recommended for CI)
|
||||
# -V => Display Maven version info before build
|
||||
# -P-assembly => Disable build of dspace-installer in [src]/dspace/, as it can be memory intensive
|
||||
# -Pcoverage-report => Enable aggregate code coverage report (across all modules) via JaCoCo
|
||||
script: mvn install -B -V -P-assembly -Pcoverage-report $TEST_FLAGS
|
||||
|
||||
# After a successful build and test (see 'script'), send code coverage reports to coveralls.io
|
||||
# These code coverage reports are generated by jacoco-maven-plugin (during test process above).
|
||||
after_success:
|
||||
# Run "verify", enabling the "coveralls" profile. This sends our reports to coveralls.io (see coveralls-maven-plugin)
|
||||
- "cd dspace && mvn verify -P coveralls"
|
||||
# After a successful build and test (see 'script'), send aggregate code coverage reports
|
||||
# (generated by -Pcoverage-report above) to CodeCov.io
|
||||
after_success: bash <(curl -s https://codecov.io/bash)
|
||||
|
20
README.md
20
README.md
@@ -90,33 +90,33 @@ run automatically by [Travis CI](https://travis-ci.com/DSpace/DSpace/) for all P
|
||||
|
||||
* How to run both Unit Tests (via `maven-surefire-plugin`) and Integration Tests (via `maven-failsafe-plugin`):
|
||||
```
|
||||
mvn clean test -DskipTests=false -DskipITs=false
|
||||
mvn install -DskipUnitTests=false -DskipIntegrationTests=false
|
||||
```
|
||||
* How to run just Unit Tests:
|
||||
* How to run _only_ Unit Tests:
|
||||
```
|
||||
mvn test -DskipTests=false
|
||||
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 -DskipTests=false -Dtest=[full.package.testClassName] -DfailIfNoTests=false
|
||||
mvn test -DskipUnitTests=false -Dtest=[full.package.testClassName] -DfailIfNoTests=false
|
||||
|
||||
# Run one test method in a specific test class
|
||||
mvn test -DskipTests=false -Dtest=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
|
||||
mvn test -DskipUnitTests=false -Dtest=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
|
||||
```
|
||||
* How to run Integration Tests (requires enabling Unit tests too)
|
||||
* How to run _only_ Integration Tests
|
||||
```
|
||||
mvn verify -DskipTests=false -DskipITs=false
|
||||
mvn install -DskipIntegrationTests=false
|
||||
```
|
||||
* How to run a *single* Integration Test (requires enabling Unit tests too)
|
||||
* 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 test -DskipTests=false -DskipITs=false -Dtest=[full.package.testClassName] -DfailIfNoTests=false
|
||||
mvn install -DskipIntegrationTests=false -Dit.test=[full.package.testClassName] -DfailIfNoTests=false
|
||||
|
||||
# Run one test method in a specific test class
|
||||
mvn test -DskipTests=false -DskipITs=false -Dtest=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
|
||||
mvn install -DskipIntegrationTests=false -Dit.test=[full.package.testClassName]#[testMethodName] -DfailIfNoTests=false
|
||||
```
|
||||
* How to run only tests of a specific DSpace module
|
||||
```
|
||||
|
@@ -127,44 +127,69 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: https://groovy.github.io/gmaven/groovy-maven-plugin/execute.html )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire & Failsafe plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>findbugs</id>
|
||||
<id>spotbugs</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<!-- property>
|
||||
<name>skipTests</name>
|
||||
<value>false</value>
|
||||
</property -->
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<groupId>com.github.spotbugs</groupId>
|
||||
<artifactId>spotbugs-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
||||
See also the 'skiptests' profile in Parent POM. -->
|
||||
<!-- Setup the Unit Test Environment (when -DskipUnitTests=false) -->
|
||||
<profile>
|
||||
<id>test-environment</id>
|
||||
<id>unit-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<name>skipUnitTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Unit/Integration Testing setup: This plugin unzips the
|
||||
<!-- Unit Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
@@ -184,53 +209,16 @@
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupTestEnvironment</id>
|
||||
<id>setupUnitTestEnvironment</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire & Failsafe plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests. -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
@@ -245,8 +233,52 @@
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<!-- Setup the Integration Test Environment (when -DskipIntegrationTests=false) -->
|
||||
<profile>
|
||||
<id>integration-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipIntegrationTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Integration Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests. -->
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
@@ -262,7 +294,6 @@
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
@@ -332,7 +363,7 @@
|
||||
<artifactId>jersey-hk2</artifactId>
|
||||
<version>${jersey.version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-cli</groupId>
|
||||
<artifactId>commons-cli</artifactId>
|
||||
@@ -732,6 +763,7 @@
|
||||
<groupId>com.google.oauth-client</groupId>
|
||||
<artifactId>google-oauth-client</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- FindBugs -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
@@ -741,6 +773,7 @@
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
|
@@ -629,6 +629,10 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
|
||||
case Constants.DELETE:
|
||||
if (AuthorizeConfiguration.canCommunityAdminPerformSubelementDeletion()) {
|
||||
adminObject = getParentObject(context, community);
|
||||
if (adminObject == null) {
|
||||
//top-level community, has to be admin of the current community
|
||||
adminObject = community;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Constants.ADD:
|
||||
|
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
package org.dspace.content;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
@@ -15,6 +16,8 @@ import javax.persistence.Id;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
|
||||
/**
|
||||
@@ -45,7 +48,8 @@ public class EntityType implements ReloadableEntity<Integer> {
|
||||
|
||||
/**
|
||||
* The standard setter for the ID of this EntityType
|
||||
* @param id The ID that this EntityType's ID will be set to
|
||||
*
|
||||
* @param id The ID that this EntityType's ID will be set to
|
||||
*/
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
@@ -53,7 +57,8 @@ public class EntityType implements ReloadableEntity<Integer> {
|
||||
|
||||
/**
|
||||
* The standard getter for the label of this EntityType
|
||||
* @return The label for this EntityType
|
||||
*
|
||||
* @return The label for this EntityType
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
@@ -61,6 +66,7 @@ public class EntityType implements ReloadableEntity<Integer> {
|
||||
|
||||
/**
|
||||
* The standard setter for the label of this EntityType
|
||||
*
|
||||
* @param label The label that this EntityType's label will be set to
|
||||
*/
|
||||
public void setLabel(String label) {
|
||||
@@ -69,9 +75,40 @@ public class EntityType implements ReloadableEntity<Integer> {
|
||||
|
||||
/**
|
||||
* The standard getter for the ID of this EntityType
|
||||
* @return The ID for this EntityType
|
||||
*
|
||||
* @return The ID for this EntityType
|
||||
*/
|
||||
public Integer getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether two entity types are equal based on the id and the label
|
||||
* @param obj object to be compared
|
||||
* @return
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof EntityType)) {
|
||||
return false;
|
||||
}
|
||||
EntityType entityType = (EntityType) obj;
|
||||
|
||||
if (!Objects.equals(this.getID(), entityType.getID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!StringUtils.equals(this.getLabel(), entityType.getLabel())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code value for the object.
|
||||
* @return hash code value
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder().append(getID()).toHashCode();
|
||||
}
|
||||
}
|
||||
|
@@ -1106,19 +1106,7 @@ prevent the generation of resource policy entry values with null dspace_object a
|
||||
}
|
||||
break;
|
||||
case Constants.DELETE:
|
||||
if (item.getOwningCollection() != null) {
|
||||
if (AuthorizeConfiguration.canCollectionAdminPerformItemDeletion()) {
|
||||
adminObject = collection;
|
||||
} else if (AuthorizeConfiguration.canCommunityAdminPerformItemDeletion()) {
|
||||
adminObject = community;
|
||||
}
|
||||
} else {
|
||||
if (AuthorizeConfiguration.canCollectionAdminManageTemplateItem()) {
|
||||
adminObject = collection;
|
||||
} else if (AuthorizeConfiguration.canCommunityAdminManageCollectionTemplateItem()) {
|
||||
adminObject = community;
|
||||
}
|
||||
}
|
||||
adminObject = item;
|
||||
break;
|
||||
case Constants.WRITE:
|
||||
// if it is a template item we need to check the
|
||||
|
@@ -13,6 +13,7 @@ import java.util.List;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.GenericDAO;
|
||||
import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.ProcessQueryParameterContainer;
|
||||
|
||||
/**
|
||||
* This is the Data Access Object for the {@link Process} object
|
||||
@@ -54,4 +55,30 @@ public interface ProcessDAO extends GenericDAO<Process> {
|
||||
*/
|
||||
int countRows(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns a list of all Processes in the database which match the given field requirements. If the
|
||||
* requirements are not null, they will be combined with an AND operation.
|
||||
* @param context The relevant DSpace context
|
||||
* @param processQueryParameterContainer The {@link ProcessQueryParameterContainer} containing all the values
|
||||
* that the returned {@link Process} objects must adhere to
|
||||
* @param limit The limit for the amount of Processes returned
|
||||
* @param offset The offset for the Processes to be returned
|
||||
* @return The list of all Processes which match the metadata requirements
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<Process> search(Context context, ProcessQueryParameterContainer processQueryParameterContainer, int limit,
|
||||
int offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Count all the processes which match the requirements. The requirements are evaluated like the search
|
||||
* method.
|
||||
* @param context The relevant DSpace context
|
||||
* @param processQueryParameterContainer The {@link ProcessQueryParameterContainer} containing all the values
|
||||
* that the returned {@link Process} objects must adhere to
|
||||
* @return The number of results matching the query
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
|
||||
int countTotalWithParameters(Context context, ProcessQueryParameterContainer processQueryParameterContainer)
|
||||
throws SQLException;
|
||||
}
|
||||
|
@@ -8,15 +8,20 @@
|
||||
package org.dspace.content.dao.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.content.dao.ProcessDAO;
|
||||
import org.dspace.core.AbstractHibernateDAO;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.ProcessQueryParameterContainer;
|
||||
import org.dspace.scripts.Process_;
|
||||
|
||||
/**
|
||||
@@ -56,6 +61,7 @@ public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements Pro
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
|
||||
Root<Process> processRoot = criteriaQuery.from(Process.class);
|
||||
criteriaQuery.select(processRoot);
|
||||
criteriaQuery.orderBy(criteriaBuilder.desc(processRoot.get(Process_.processId)));
|
||||
|
||||
return list(context, criteriaQuery, false, Process.class, limit, offset);
|
||||
}
|
||||
@@ -71,6 +77,76 @@ public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements Pro
|
||||
return count(context, criteriaQuery, criteriaBuilder, processRoot);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Process> search(Context context, ProcessQueryParameterContainer processQueryParameterContainer,
|
||||
int limit, int offset) throws SQLException {
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
|
||||
Root<Process> processRoot = criteriaQuery.from(Process.class);
|
||||
criteriaQuery.select(processRoot);
|
||||
|
||||
handleProcessQueryParameters(processQueryParameterContainer, criteriaBuilder, criteriaQuery, processRoot);
|
||||
return list(context, criteriaQuery, false, Process.class, limit, offset);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will ensure that the params contained in the {@link ProcessQueryParameterContainer} are transferred
|
||||
* to the ProcessRoot and that the correct conditions apply to the query
|
||||
* @param processQueryParameterContainer The object containing the conditions that need to be met
|
||||
* @param criteriaBuilder The criteriaBuilder to be used
|
||||
* @param criteriaQuery The criteriaQuery to be used
|
||||
* @param processRoot The processRoot to be used
|
||||
*/
|
||||
private void handleProcessQueryParameters(ProcessQueryParameterContainer processQueryParameterContainer,
|
||||
CriteriaBuilder criteriaBuilder, CriteriaQuery criteriaQuery,
|
||||
Root<Process> processRoot) {
|
||||
addProcessQueryParameters(processQueryParameterContainer, criteriaBuilder, criteriaQuery, processRoot);
|
||||
if (StringUtils.equalsIgnoreCase(processQueryParameterContainer.getSortOrder(), "asc")) {
|
||||
criteriaQuery
|
||||
.orderBy(criteriaBuilder.asc(processRoot.get(processQueryParameterContainer.getSortProperty())));
|
||||
} else if (StringUtils.equalsIgnoreCase(processQueryParameterContainer.getSortOrder(), "desc")) {
|
||||
criteriaQuery
|
||||
.orderBy(criteriaBuilder.desc(processRoot.get(processQueryParameterContainer.getSortProperty())));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will apply the variables in the {@link ProcessQueryParameterContainer} as criteria for the
|
||||
* {@link Process} objects to the given CriteriaQuery.
|
||||
* They'll need to adhere to these variables in order to be eligible for return
|
||||
* @param processQueryParameterContainer The object containing the variables for the {@link Process}
|
||||
* to adhere to
|
||||
* @param criteriaBuilder The current CriteriaBuilder
|
||||
* @param criteriaQuery The current CriteriaQuery
|
||||
* @param processRoot The processRoot
|
||||
*/
|
||||
private void addProcessQueryParameters(ProcessQueryParameterContainer processQueryParameterContainer,
|
||||
CriteriaBuilder criteriaBuilder, CriteriaQuery criteriaQuery,
|
||||
Root<Process> processRoot) {
|
||||
List<Predicate> andPredicates = new LinkedList<>();
|
||||
|
||||
for (Map.Entry<String, Object> entry : processQueryParameterContainer.getQueryParameterMap().entrySet()) {
|
||||
andPredicates.add(criteriaBuilder.equal(processRoot.get(entry.getKey()), entry.getValue()));
|
||||
}
|
||||
criteriaQuery.where(criteriaBuilder.and(andPredicates.toArray(new Predicate[]{})));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countTotalWithParameters(Context context, ProcessQueryParameterContainer processQueryParameterContainer)
|
||||
throws SQLException {
|
||||
|
||||
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
|
||||
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
|
||||
Root<Process> processRoot = criteriaQuery.from(Process.class);
|
||||
criteriaQuery.select(processRoot);
|
||||
|
||||
addProcessQueryParameters(processQueryParameterContainer, criteriaBuilder, criteriaQuery, processRoot);
|
||||
return count(context, criteriaQuery, criteriaBuilder, processRoot);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.discovery.indexobject;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
|
||||
/**
|
||||
* This class exists in order to provide a default implementation for the equals and hashCode methods.
|
||||
* Since IndexableObjects can be made multiple times for the same underlying object, we needed a more finetuned
|
||||
* equals and hashcode methods. We're simply checking that the underlying objects are equal and generating the hashcode
|
||||
* for the underlying object. This way, we'll always get a proper result when calling equals or hashcode on an
|
||||
* IndexableObject because it'll depend on the underlying object
|
||||
* @param <T> Refers to the underlying entity that is linked to this object
|
||||
* @param <PK> The type of ID that this entity uses
|
||||
*/
|
||||
public abstract class AbstractIndexableObject<T extends ReloadableEntity<PK>, PK extends Serializable>
|
||||
implements IndexableObject<T,PK> {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
//Two IndexableObjects of the same DSpaceObject are considered equal
|
||||
if (!(obj instanceof AbstractIndexableObject)) {
|
||||
return false;
|
||||
}
|
||||
IndexableDSpaceObject other = (IndexableDSpaceObject) obj;
|
||||
return other.getIndexedObject().equals(getIndexedObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
//Two IndexableObjects of the same DSpaceObject are considered equal
|
||||
return getIndexedObject().hashCode();
|
||||
}
|
||||
|
||||
}
|
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
package org.dspace.discovery.indexobject;
|
||||
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||
|
||||
/**
|
||||
@@ -15,7 +14,7 @@ import org.dspace.xmlworkflow.storedcomponents.ClaimedTask;
|
||||
*
|
||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
||||
*/
|
||||
public class IndexableClaimedTask implements IndexableObject<ClaimedTask, Integer> {
|
||||
public class IndexableClaimedTask extends AbstractIndexableObject<ClaimedTask, Integer> {
|
||||
|
||||
private ClaimedTask claimedTask;
|
||||
public static final String TYPE = ClaimedTask.class.getSimpleName();
|
||||
|
@@ -10,7 +10,6 @@ package org.dspace.discovery.indexobject;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
|
||||
/**
|
||||
* DSpaceObject implementation for the IndexableObject, contains methods used by all DSpaceObject methods
|
||||
@@ -18,7 +17,7 @@ import org.dspace.discovery.IndexableObject;
|
||||
*
|
||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
||||
*/
|
||||
public abstract class IndexableDSpaceObject<T extends DSpaceObject> implements IndexableObject<T, UUID> {
|
||||
public abstract class IndexableDSpaceObject<T extends DSpaceObject> extends AbstractIndexableObject<T, UUID> {
|
||||
|
||||
private T dso;
|
||||
|
||||
@@ -40,4 +39,6 @@ public abstract class IndexableDSpaceObject<T extends DSpaceObject> implements I
|
||||
public UUID getID() {
|
||||
return dso.getID();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -8,14 +8,13 @@
|
||||
package org.dspace.discovery.indexobject;
|
||||
|
||||
import org.dspace.content.InProgressSubmission;
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
|
||||
/**
|
||||
* InProgressSubmission implementation for the IndexableObject
|
||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
||||
*/
|
||||
public abstract class IndexableInProgressSubmission<T extends InProgressSubmission>
|
||||
implements IndexableObject<T, Integer> {
|
||||
extends AbstractIndexableObject<T, Integer> {
|
||||
|
||||
protected T inProgressSubmission;
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import org.dspace.discovery.IndexableObject;
|
||||
*
|
||||
* @author Maria Verdonck (Atmire) on 14/07/2020
|
||||
*/
|
||||
public class IndexableMetadataField implements IndexableObject<MetadataField, Integer> {
|
||||
public class IndexableMetadataField extends AbstractIndexableObject<MetadataField, Integer> {
|
||||
|
||||
private MetadataField metadataField;
|
||||
public static final String TYPE = MetadataField.class.getSimpleName();
|
||||
|
@@ -7,14 +7,13 @@
|
||||
*/
|
||||
package org.dspace.discovery.indexobject;
|
||||
|
||||
import org.dspace.discovery.IndexableObject;
|
||||
import org.dspace.xmlworkflow.storedcomponents.PoolTask;
|
||||
|
||||
/**
|
||||
* PoolTask implementation for the IndexableObject
|
||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
||||
*/
|
||||
public class IndexablePoolTask implements IndexableObject<PoolTask, Integer> {
|
||||
public class IndexablePoolTask extends AbstractIndexableObject<PoolTask, Integer> {
|
||||
|
||||
public static final String TYPE = PoolTask.class.getSimpleName();
|
||||
|
||||
|
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 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.scripts;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This is a container class in which the variables can be stored that a {@link Process} must adhere to when being
|
||||
* retrieved from the DB through the search methods
|
||||
*/
|
||||
public class ProcessQueryParameterContainer {
|
||||
|
||||
|
||||
private Map<String, Object> queryParameterMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Generic getter for the queryParameterMap
|
||||
* @return the queryParameterMap value of this ProcessQueryParameterContainer
|
||||
*/
|
||||
public Map<String, Object> getQueryParameterMap() {
|
||||
return queryParameterMap;
|
||||
}
|
||||
|
||||
private String sortProperty = "startTime";
|
||||
private String sortOrder = "desc";
|
||||
/**
|
||||
* Generic setter for the queryParameterMap
|
||||
* @param queryParameterMap The queryParameterMap to be set on this ProcessQueryParameterContainer
|
||||
*/
|
||||
public void setQueryParameterMap(Map<String, Object> queryParameterMap) {
|
||||
this.queryParameterMap = queryParameterMap;
|
||||
}
|
||||
|
||||
public void addToQueryParameterMap(String key, Object object) {
|
||||
if (queryParameterMap == null) {
|
||||
queryParameterMap = new HashMap<>();
|
||||
}
|
||||
queryParameterMap.put(key, object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the sortProperty
|
||||
* @return the sortProperty value of this ProcessQueryParameterContainer
|
||||
*/
|
||||
public String getSortProperty() {
|
||||
return sortProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sortProperty
|
||||
* @param sortProperty The sortProperty to be set on this ProcessQueryParameterContainer
|
||||
*/
|
||||
public void setSortProperty(String sortProperty) {
|
||||
this.sortProperty = sortProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic getter for the sortOrder
|
||||
* @return the sortOrder value of this ProcessQueryParameterContainer
|
||||
*/
|
||||
public String getSortOrder() {
|
||||
return sortOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic setter for the sortOrder
|
||||
* @param sortOrder The sortOrder to be set on this ProcessQueryParameterContainer
|
||||
*/
|
||||
public void setSortOrder(String sortOrder) {
|
||||
this.sortOrder = sortOrder;
|
||||
}
|
||||
}
|
@@ -255,6 +255,19 @@ public class ProcessServiceImpl implements ProcessService {
|
||||
return new ArrayList<>(fileTypesSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Process> search(Context context, ProcessQueryParameterContainer processQueryParameterContainer,
|
||||
int limit, int offset) throws SQLException {
|
||||
return processDAO.search(context, processQueryParameterContainer, limit, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int countSearch(Context context, ProcessQueryParameterContainer processQueryParameterContainer)
|
||||
throws SQLException {
|
||||
return processDAO.countTotalWithParameters(context, processQueryParameterContainer);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void appendLog(int processId, String scriptName, String output, ProcessLogLevel processLogLevel)
|
||||
throws IOException {
|
||||
|
@@ -19,6 +19,7 @@ import org.dspace.eperson.EPerson;
|
||||
import org.dspace.scripts.DSpaceCommandLineParameter;
|
||||
import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.ProcessLogLevel;
|
||||
import org.dspace.scripts.ProcessQueryParameterContainer;
|
||||
|
||||
/**
|
||||
* An interface for the ProcessService with methods regarding the Process workload
|
||||
@@ -190,6 +191,30 @@ public interface ProcessService {
|
||||
*/
|
||||
public List<String> getFileTypesForProcessBitstreams(Context context, Process process);
|
||||
|
||||
/**
|
||||
* Returns a list of all Processes in the database which match the given field requirements. If the
|
||||
* requirements are not null, they will be combined with an AND operation.
|
||||
* @param context The relevant DSpace context
|
||||
* @param processQueryParameterContainer The {@link ProcessQueryParameterContainer} containing all the values
|
||||
* that the returned {@link Process} objects must adhere to
|
||||
* @param limit The limit for the amount of Processes returned
|
||||
* @param offset The offset for the Processes to be returned
|
||||
* @return The list of all Processes which match the metadata requirements
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
List<Process> search(Context context, ProcessQueryParameterContainer processQueryParameterContainer, int limit,
|
||||
int offset) throws SQLException;
|
||||
|
||||
/**
|
||||
* Count all the processes which match the requirements. The requirements are evaluated like the search
|
||||
* method.
|
||||
* @param context The relevant DSpace context
|
||||
* @param processQueryParameterContainer The {@link ProcessQueryParameterContainer} containing all the values
|
||||
* that the returned {@link Process} objects must adhere to
|
||||
* @return The number of results matching the query
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
int countSearch(Context context, ProcessQueryParameterContainer processQueryParameterContainer) throws SQLException;
|
||||
/**
|
||||
* This method will append the given output to the {@link Process} its logs
|
||||
* @param processId The ID of the {@link Process} to append the log for
|
||||
|
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.statistics.export;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.statistics.export.dao.OpenURLTrackerDAO;
|
||||
import org.dspace.statistics.export.service.FailedOpenURLTrackerService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation of the service that handles the OpenURLTracker database operations
|
||||
*/
|
||||
public class FailedOpenURLTrackerServiceImpl implements FailedOpenURLTrackerService {
|
||||
|
||||
@Autowired(required = true)
|
||||
protected OpenURLTrackerDAO openURLTrackerDAO;
|
||||
|
||||
/**
|
||||
* Removes an OpenURLTracker from the database
|
||||
* @param context
|
||||
* @param openURLTracker
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public void remove(Context context, OpenURLTracker openURLTracker) throws SQLException {
|
||||
openURLTrackerDAO.delete(context, openURLTracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all OpenURLTrackers from the database
|
||||
* @param context
|
||||
* @return all OpenURLTrackers
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public List<OpenURLTracker> findAll(Context context) throws SQLException {
|
||||
return openURLTrackerDAO.findAll(context, OpenURLTracker.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new OpenURLTracker
|
||||
* @param context
|
||||
* @return the creatred OpenURLTracker
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Override
|
||||
public OpenURLTracker create(Context context) throws SQLException {
|
||||
OpenURLTracker openURLTracker = openURLTrackerDAO.create(context, new OpenURLTracker());
|
||||
return openURLTracker;
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogManager;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.model.Event;
|
||||
import org.dspace.statistics.export.processor.BitstreamEventProcessor;
|
||||
import org.dspace.statistics.export.processor.ItemEventProcessor;
|
||||
import org.dspace.usage.AbstractUsageEventListener;
|
||||
import org.dspace.usage.UsageEvent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Class to receive usage events and send corresponding data to IRUS
|
||||
*/
|
||||
public class IrusExportUsageEventListener extends AbstractUsageEventListener {
|
||||
/* Log4j logger*/
|
||||
private static Logger log = Logger.getLogger(IrusExportUsageEventListener.class);
|
||||
|
||||
@Autowired
|
||||
ConfigurationService configurationService;
|
||||
|
||||
/**
|
||||
* Receives an event and processes to create a URL to send to IRUS when certain conditions are met
|
||||
*
|
||||
* @param event includes all the information related to the event that occurred
|
||||
*/
|
||||
public void receiveEvent(Event event) {
|
||||
if (configurationService.getBooleanProperty("irus.statistics.tracker.enabled", false)) {
|
||||
if (event instanceof UsageEvent) {
|
||||
UsageEvent ue = (UsageEvent) event;
|
||||
Context context = ue.getContext();
|
||||
|
||||
try {
|
||||
//Check for item investigation
|
||||
if (ue.getObject() instanceof Item) {
|
||||
ItemEventProcessor itemEventProcessor = new ItemEventProcessor(context, ue.getRequest(),
|
||||
(Item) ue.getObject());
|
||||
itemEventProcessor.processEvent();
|
||||
} else if (ue.getObject() instanceof Bitstream) {
|
||||
|
||||
BitstreamEventProcessor bitstreamEventProcessor =
|
||||
new BitstreamEventProcessor(context, ue.getRequest(), (Bitstream) ue.getObject());
|
||||
bitstreamEventProcessor.processEvent();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
UUID id;
|
||||
id = ue.getObject().getID();
|
||||
|
||||
int type;
|
||||
try {
|
||||
type = ue.getObject().getType();
|
||||
} catch (Exception e1) {
|
||||
type = -1;
|
||||
}
|
||||
log.error(LogManager.getHeader(ue.getContext(), "Error while processing export of use event",
|
||||
"Id: " + id + " type: " + type), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.dspace.core.ReloadableEntity;
|
||||
import org.hibernate.proxy.HibernateProxyHelper;
|
||||
|
||||
/**
|
||||
* Class that represents an OpenURLTracker which tracks a failed transmission to IRUS
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "OpenUrlTracker")
|
||||
public class OpenURLTracker implements ReloadableEntity<Integer> {
|
||||
|
||||
@Id
|
||||
@Column(name = "tracker_id")
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "openurltracker_seq")
|
||||
@SequenceGenerator(name = "openurltracker_seq", sequenceName = "openurltracker_seq", allocationSize = 1)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "tracker_url", length = 1000)
|
||||
private String url;
|
||||
|
||||
@Column(name = "uploaddate")
|
||||
@Temporal(TemporalType.DATE)
|
||||
private Date uploadDate;
|
||||
|
||||
protected OpenURLTracker() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenURLTracker id
|
||||
* @return the id
|
||||
*/
|
||||
@Override
|
||||
public Integer getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OpenURLTracker url
|
||||
* @return the url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the OpenURLTracker url
|
||||
* @param url
|
||||
*/
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the upload date
|
||||
* @return upload date
|
||||
*/
|
||||
public Date getUploadDate() {
|
||||
return uploadDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upload date
|
||||
* @param uploadDate
|
||||
*/
|
||||
public void setUploadDate(Date uploadDate) {
|
||||
this.uploadDate = uploadDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether two objects of this class are equal by comparing the ID
|
||||
* @param o - object to compare
|
||||
* @return whether the objects are equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
Class<?> objClass = HibernateProxyHelper.getClassWithoutInitializingProxy(o);
|
||||
if (getClass() != objClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final OpenURLTracker that = (OpenURLTracker) o;
|
||||
if (!this.getID().equals(that.getID())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code value for the object
|
||||
* @return hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 8;
|
||||
hash = 74 * hash + this.getID();
|
||||
return hash;
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.statistics.export.factory.OpenURLTrackerLoggerServiceFactory;
|
||||
import org.dspace.statistics.export.service.OpenUrlService;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* Script to retry the failed url transmissions to IRUS
|
||||
* This script also has an option to add new failed urls for testing purposes
|
||||
*/
|
||||
public class RetryFailedOpenUrlTracker extends DSpaceRunnable<RetryFailedOpenUrlTrackerScriptConfiguration> {
|
||||
|
||||
private String lineToAdd = null;
|
||||
private boolean help = false;
|
||||
private boolean retryFailed = false;
|
||||
|
||||
private OpenUrlService openUrlService;
|
||||
|
||||
/**
|
||||
* Run the script
|
||||
* When the -a option is used, a new "failed" url will be added to the database
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void internalRun() throws Exception {
|
||||
if (help) {
|
||||
printHelp();
|
||||
return;
|
||||
}
|
||||
Context context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
if (StringUtils.isNotBlank(lineToAdd)) {
|
||||
openUrlService.logfailed(context, lineToAdd);
|
||||
handler.logInfo("Created dummy entry in OpenUrlTracker with URL: " + lineToAdd);
|
||||
}
|
||||
if (retryFailed) {
|
||||
handler.logInfo("Reprocessing failed URLs stored in the db");
|
||||
openUrlService.reprocessFailedQueue(context);
|
||||
}
|
||||
context.restoreAuthSystemState();
|
||||
context.complete();
|
||||
}
|
||||
|
||||
public RetryFailedOpenUrlTrackerScriptConfiguration getScriptConfiguration() {
|
||||
return new DSpace().getServiceManager().getServiceByName("retry-tracker",
|
||||
RetryFailedOpenUrlTrackerScriptConfiguration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the parameters
|
||||
*
|
||||
* @throws ParseException
|
||||
*/
|
||||
public void setup() throws ParseException {
|
||||
openUrlService = OpenURLTrackerLoggerServiceFactory.getInstance().getOpenUrlService();
|
||||
|
||||
if (!(commandLine.hasOption('a') || commandLine.hasOption('r') || commandLine.hasOption('h'))) {
|
||||
throw new ParseException("At least one of the parameters (-a, -r, -h) is required!");
|
||||
}
|
||||
|
||||
if (commandLine.hasOption('h')) {
|
||||
help = true;
|
||||
}
|
||||
if (commandLine.hasOption('a')) {
|
||||
lineToAdd = commandLine.getOptionValue('a');
|
||||
}
|
||||
if (commandLine.hasOption('r')) {
|
||||
retryFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
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 RetryFailedOpenUrlTracker} script
|
||||
*/
|
||||
public class RetryFailedOpenUrlTrackerScriptConfiguration<T extends RetryFailedOpenUrlTracker>
|
||||
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 RetryFailedOpenUrlTrackerScriptConfiguration
|
||||
*/
|
||||
@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("a", true, "Add a new \"failed\" row to the table with a url (test purposes only)");
|
||||
options.getOption("a").setType(String.class);
|
||||
|
||||
options.addOption("r", false,
|
||||
"Retry sending requests to all urls stored in the table with failed requests. " +
|
||||
"This includes the url that can be added through the -a option.");
|
||||
options.getOption("r").setType(boolean.class);
|
||||
|
||||
options.addOption("h", "help", false, "print this help message");
|
||||
options.getOption("h").setType(boolean.class);
|
||||
|
||||
super.options = options;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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.statistics.export.dao;
|
||||
|
||||
import org.dspace.core.GenericDAO;
|
||||
import org.dspace.statistics.export.OpenURLTracker;
|
||||
|
||||
/**
|
||||
* Database Access Object interface class for the OpenURLTracker object.
|
||||
* The implementation of this class is responsible for all database calls for the OpenURLTracker object and is
|
||||
* autowired by spring
|
||||
* This class should only be accessed from a single service and should never be exposed outside of the API
|
||||
*/
|
||||
public interface OpenURLTrackerDAO extends GenericDAO<OpenURLTracker> {
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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.statistics.export.dao.impl;
|
||||
|
||||
import org.dspace.core.AbstractHibernateDAO;
|
||||
import org.dspace.statistics.export.OpenURLTracker;
|
||||
import org.dspace.statistics.export.dao.OpenURLTrackerDAO;
|
||||
|
||||
/**
|
||||
* Hibernate implementation of the Database Access Object interface class for the OpenURLTracker object.
|
||||
* This class is responsible for all database calls for the OpenURLTracker object and is autowired by spring
|
||||
* This class should never be accessed directly.
|
||||
*
|
||||
*/
|
||||
public class OpenURLTrackerDAOImpl extends AbstractHibernateDAO<OpenURLTracker> implements OpenURLTrackerDAO {
|
||||
|
||||
protected OpenURLTrackerDAOImpl() {
|
||||
super();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.statistics.export.factory;
|
||||
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.statistics.export.service.FailedOpenURLTrackerService;
|
||||
import org.dspace.statistics.export.service.OpenUrlService;
|
||||
|
||||
/**
|
||||
* The service factory for the OpenUrlTracker related services
|
||||
*/
|
||||
public abstract class OpenURLTrackerLoggerServiceFactory {
|
||||
|
||||
/**
|
||||
* Returns the FailedOpenURLTrackerService
|
||||
* @return FailedOpenURLTrackerService instance
|
||||
*/
|
||||
public abstract FailedOpenURLTrackerService getOpenUrlTrackerLoggerService();
|
||||
|
||||
/**
|
||||
* Retrieve the OpenURLTrackerLoggerServiceFactory
|
||||
* @return OpenURLTrackerLoggerServiceFactory instance
|
||||
*/
|
||||
public static OpenURLTrackerLoggerServiceFactory getInstance() {
|
||||
return DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("openURLTrackerLoggerServiceFactory",
|
||||
OpenURLTrackerLoggerServiceFactory.class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OpenUrlService
|
||||
* @return OpenUrlService instance
|
||||
*/
|
||||
public abstract OpenUrlService getOpenUrlService();
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.statistics.export.factory;
|
||||
|
||||
import org.dspace.statistics.export.service.FailedOpenURLTrackerService;
|
||||
import org.dspace.statistics.export.service.OpenUrlService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* The service factory implementation for the OpenUrlTracker related services
|
||||
*/
|
||||
public class OpenURLTrackerLoggerServiceFactoryImpl extends OpenURLTrackerLoggerServiceFactory {
|
||||
|
||||
@Autowired(required = true)
|
||||
private FailedOpenURLTrackerService failedOpenURLTrackerService;
|
||||
|
||||
@Autowired(required = true)
|
||||
private OpenUrlService openUrlService;
|
||||
|
||||
/**
|
||||
* Returns the FailedOpenURLTrackerService
|
||||
* @return FailedOpenURLTrackerService instance
|
||||
*/
|
||||
@Override
|
||||
public FailedOpenURLTrackerService getOpenUrlTrackerLoggerService() {
|
||||
return failedOpenURLTrackerService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the OpenUrlService
|
||||
* @return OpenUrlService instance
|
||||
*/
|
||||
@Override
|
||||
public OpenUrlService getOpenUrlService() {
|
||||
return openUrlService;
|
||||
}
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.sql.SQLException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.statistics.util.SpiderDetector;
|
||||
|
||||
/**
|
||||
* Processor that handles Bitstream events from the IrusExportUsageEventListener
|
||||
*/
|
||||
public class BitstreamEventProcessor extends ExportEventProcessor {
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
|
||||
private Item item;
|
||||
private Bitstream bitstream;
|
||||
|
||||
/**
|
||||
* Creates a new BitstreamEventProcessor that will set the params and obtain the parent item of the bitstream
|
||||
*
|
||||
* @param context
|
||||
* @param request
|
||||
* @param bitstream
|
||||
* @throws SQLException
|
||||
*/
|
||||
public BitstreamEventProcessor(Context context, HttpServletRequest request, Bitstream bitstream)
|
||||
throws SQLException {
|
||||
super(context, request);
|
||||
this.bitstream = bitstream;
|
||||
this.item = getItem(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent item of the bitsream
|
||||
*
|
||||
* @return parent item of the bitstream
|
||||
* @throws SQLException
|
||||
*/
|
||||
private Item getItem(HttpServletRequest request) throws SQLException {
|
||||
if (0 < bitstream.getBundles().size()) {
|
||||
if (!SpiderDetector.isSpider(request)) {
|
||||
Bundle bundle = bitstream.getBundles().get(0);
|
||||
if (bundle.getName() == null || !bundle.getName().equals("ORIGINAL")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (0 < bundle.getItems().size()) {
|
||||
Item item = bundle.getItems().get(0);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the event
|
||||
* Check if the item should be processed
|
||||
* Create the url to be transmitted based on item and bitstream data
|
||||
*
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void processEvent() throws SQLException, IOException {
|
||||
if (shouldProcessItem(item)) {
|
||||
String baseParam = getBaseParameters(item);
|
||||
String fullParam = addObjectSpecificData(baseParam, bitstream);
|
||||
processObject(fullParam);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional item and bitstream data to the url
|
||||
*
|
||||
* @param string to which the additional data needs to be added
|
||||
* @param bitstream
|
||||
* @return the string with additional data
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
protected String addObjectSpecificData(final String string, Bitstream bitstream)
|
||||
throws UnsupportedEncodingException {
|
||||
StringBuilder data = new StringBuilder(string);
|
||||
|
||||
String bitstreamInfo = getBitstreamInfo(bitstream);
|
||||
data.append("&").append(URLEncoder.encode("svc_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(bitstreamInfo, UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("rft_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(BITSTREAM_DOWNLOAD, UTF_8));
|
||||
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Bitstream info used for the url
|
||||
*
|
||||
* @param bitstream
|
||||
* @return bitstream info
|
||||
*/
|
||||
private String getBitstreamInfo(final Bitstream bitstream) {
|
||||
|
||||
String dspaceRestUrl = configurationService.getProperty("dspace.server.url");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(dspaceRestUrl);
|
||||
sb.append("/api/core/bitstreams/");
|
||||
sb.append(bitstream.getID());
|
||||
sb.append("/content");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.Entity;
|
||||
import org.dspace.content.EntityType;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.MetadataValue;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.EntityService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.Utils;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.statistics.export.factory.OpenURLTrackerLoggerServiceFactory;
|
||||
import org.dspace.statistics.export.service.OpenUrlService;
|
||||
|
||||
/**
|
||||
* Abstract export event processor that contains all shared logic to handle both Items and Bitstreams
|
||||
* from the IrusExportUsageEventListener
|
||||
*/
|
||||
public abstract class ExportEventProcessor {
|
||||
|
||||
private static Logger log = Logger.getLogger(ExportEventProcessor.class);
|
||||
|
||||
protected static final String ENTITY_TYPE_DEFAULT = "Publication";
|
||||
|
||||
protected static final String ITEM_VIEW = "Investigation";
|
||||
protected static final String BITSTREAM_DOWNLOAD = "Request";
|
||||
|
||||
protected final static String UTF_8 = CharEncoding.UTF_8;
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
private EntityService entityService = ContentServiceFactory.getInstance().getEntityService();
|
||||
private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
private OpenUrlService openUrlService = OpenURLTrackerLoggerServiceFactory.getInstance().getOpenUrlService();
|
||||
|
||||
|
||||
private Context context;
|
||||
private HttpServletRequest request;
|
||||
|
||||
/**
|
||||
* Creates a new ExportEventProcessor based on the params and initializes the services
|
||||
*
|
||||
* @param context
|
||||
* @param request
|
||||
*/
|
||||
ExportEventProcessor(Context context, HttpServletRequest request) {
|
||||
this.context = context;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the event
|
||||
*
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract void processEvent() throws SQLException, IOException;
|
||||
|
||||
/**
|
||||
* Process the url obtained from the object to be transmitted
|
||||
*
|
||||
* @param urlParameters
|
||||
* @throws IOException
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void processObject(String urlParameters) throws IOException, SQLException {
|
||||
String baseUrl;
|
||||
if (StringUtils.equals(configurationService.getProperty("irus.statistics.tracker.environment"), "production")) {
|
||||
baseUrl = configurationService.getProperty("irus.statistics.tracker.produrl");
|
||||
} else {
|
||||
baseUrl = configurationService.getProperty("irus.statistics.tracker.testurl");
|
||||
}
|
||||
|
||||
openUrlService.processUrl(context, baseUrl + "?" + urlParameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base parameters for the url to be transmitted
|
||||
*
|
||||
* @param item
|
||||
* @return the parameter string to be used in the url
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
protected String getBaseParameters(Item item)
|
||||
throws UnsupportedEncodingException {
|
||||
|
||||
//We have a valid url collect the rest of the data
|
||||
String clientIP = request.getRemoteAddr();
|
||||
if (configurationService.getBooleanProperty("useProxies", false) && request
|
||||
.getHeader("X-Forwarded-For") != null) {
|
||||
/* This header is a comma delimited list */
|
||||
for (String xfip : request.getHeader("X-Forwarded-For").split(",")) {
|
||||
/* proxy itself will sometime populate this header with the same value in
|
||||
remote address. ordering in spec is vague, we'll just take the last
|
||||
not equal to the proxy
|
||||
*/
|
||||
if (!request.getHeader("X-Forwarded-For").contains(clientIP)) {
|
||||
clientIP = xfip.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
String clientUA = StringUtils.defaultIfBlank(request.getHeader("USER-AGENT"), "");
|
||||
String referer = StringUtils.defaultIfBlank(request.getHeader("referer"), "");
|
||||
|
||||
//Start adding our data
|
||||
StringBuilder data = new StringBuilder();
|
||||
data.append(URLEncoder.encode("url_ver", UTF_8) + "=" +
|
||||
URLEncoder.encode(configurationService.getProperty("irus.statistics.tracker.urlversion"), UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("req_id", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(clientIP, UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("req_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(clientUA, UTF_8));
|
||||
|
||||
String hostName = Utils.getHostName(configurationService.getProperty("dspace.ui.url"));
|
||||
|
||||
data.append("&").append(URLEncoder.encode("rft.artnum", UTF_8)).append("=").
|
||||
append(URLEncoder.encode("oai:" + hostName + ":" + item
|
||||
.getHandle(), UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("rfr_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(referer, UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("rfr_id", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(hostName, UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("url_tim", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(getCurrentDateString(), UTF_8));
|
||||
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current date
|
||||
*
|
||||
* @return the current date as a string
|
||||
*/
|
||||
protected String getCurrentDateString() {
|
||||
return new DCDate(new Date()).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an item should be processed
|
||||
*
|
||||
* @param item to be checked
|
||||
* @return whether the item should be processed
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected boolean shouldProcessItem(Item item) throws SQLException {
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
if (!item.isArchived()) {
|
||||
return false;
|
||||
}
|
||||
if (itemService.canEdit(context, item)) {
|
||||
return false;
|
||||
}
|
||||
if (!shouldProcessItemType(item)) {
|
||||
return false;
|
||||
}
|
||||
if (!shouldProcessEntityType(item)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item's entity type should be processed
|
||||
*
|
||||
* @param item to be checked
|
||||
* @return whether the item should be processed
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected boolean shouldProcessEntityType(Item item) throws SQLException {
|
||||
Entity entity = entityService.findByItemId(context, item.getID());
|
||||
EntityType type = entityService.getType(context, entity);
|
||||
|
||||
String[] entityTypeStrings = configurationService.getArrayProperty("irus.statistics.tracker.entity-types");
|
||||
List<String> entityTypes = new ArrayList<>();
|
||||
|
||||
if (entityTypeStrings.length != 0) {
|
||||
entityTypes.addAll(Arrays.asList(entityTypeStrings));
|
||||
} else {
|
||||
entityTypes.add(ENTITY_TYPE_DEFAULT);
|
||||
}
|
||||
|
||||
if (type != null && entityTypes.contains(type.getLabel())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the item should be excluded based on the its type
|
||||
*
|
||||
* @param item to be checked
|
||||
* @return whether the item should be processed
|
||||
*/
|
||||
protected boolean shouldProcessItemType(Item item) {
|
||||
String trackerTypeMetadataField = configurationService.getProperty("irus.statistics.tracker.type-field");
|
||||
String[] metadataValues = configurationService.getArrayProperty("irus.statistics.tracker.type-value");
|
||||
List<String> trackerTypeMetadataValues;
|
||||
if (metadataValues.length > 0) {
|
||||
trackerTypeMetadataValues = new ArrayList<>();
|
||||
for (String metadataValue : metadataValues) {
|
||||
trackerTypeMetadataValues.add(metadataValue.toLowerCase());
|
||||
}
|
||||
} else {
|
||||
trackerTypeMetadataValues = null;
|
||||
}
|
||||
|
||||
if (trackerTypeMetadataField != null && trackerTypeMetadataValues != null) {
|
||||
|
||||
// Contains the schema, element and if present qualifier of the metadataField
|
||||
String[] metadataFieldSplit = trackerTypeMetadataField.split("\\.");
|
||||
|
||||
List<MetadataValue> types = itemService
|
||||
.getMetadata(item, metadataFieldSplit[0], metadataFieldSplit[1],
|
||||
metadataFieldSplit.length == 2 ? null : metadataFieldSplit[2], Item.ANY);
|
||||
|
||||
if (!types.isEmpty()) {
|
||||
//Find out if we have a type that needs to be excluded
|
||||
for (MetadataValue type : types) {
|
||||
if (trackerTypeMetadataValues.contains(type.getValue().toLowerCase())) {
|
||||
//We have found no type so process this item
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// No types in this item, so not excluded
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// No types to be excluded
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.sql.SQLException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Processor that handles Item events from the IrusExportUsageEventListener
|
||||
*/
|
||||
public class ItemEventProcessor extends ExportEventProcessor {
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private Item item;
|
||||
|
||||
/**
|
||||
* Creates a new ItemEventProcessor that will set the params
|
||||
*
|
||||
* @param context
|
||||
* @param request
|
||||
* @param item
|
||||
*/
|
||||
public ItemEventProcessor(Context context, HttpServletRequest request, Item item) {
|
||||
super(context, request);
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the event
|
||||
* Check if the item should be processed
|
||||
* Create the url to be transmitted based on item data
|
||||
*
|
||||
* @throws SQLException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void processEvent() throws SQLException, IOException {
|
||||
if (shouldProcessItem(item)) {
|
||||
String baseParam = getBaseParameters(item);
|
||||
String fullParam = addObjectSpecificData(baseParam, item);
|
||||
processObject(fullParam);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional item data to the url
|
||||
*
|
||||
* @param string to which the additional data needs to be added
|
||||
* @param item
|
||||
* @return the string with additional data
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
protected String addObjectSpecificData(final String string, Item item) throws UnsupportedEncodingException {
|
||||
StringBuilder data = new StringBuilder(string);
|
||||
String itemInfo = getItemInfo(item);
|
||||
data.append("&").append(URLEncoder.encode("svc_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(itemInfo, UTF_8));
|
||||
data.append("&").append(URLEncoder.encode("rft_dat", UTF_8)).append("=")
|
||||
.append(URLEncoder.encode(ITEM_VIEW, UTF_8));
|
||||
return data.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Item info used for the url
|
||||
*
|
||||
* @param item
|
||||
* @return item info
|
||||
*/
|
||||
private String getItemInfo(final Item item) {
|
||||
StringBuilder sb = new StringBuilder(configurationService.getProperty("dspace.ui.url"));
|
||||
sb.append("/handle/").append(item.getHandle());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.statistics.export.OpenURLTracker;
|
||||
|
||||
/**
|
||||
* Interface of the service that handles the OpenURLTracker database operations
|
||||
*/
|
||||
public interface FailedOpenURLTrackerService {
|
||||
|
||||
/**
|
||||
* Removes an OpenURLTracker from the database
|
||||
* @param context
|
||||
* @param openURLTracker
|
||||
* @throws SQLException
|
||||
*/
|
||||
void remove(Context context, OpenURLTracker openURLTracker) throws SQLException;
|
||||
|
||||
/**
|
||||
* Returns all OpenURLTrackers from the database
|
||||
* @param context
|
||||
* @return all OpenURLTrackers
|
||||
* @throws SQLException
|
||||
*/
|
||||
List<OpenURLTracker> findAll(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Creates a new OpenURLTracker
|
||||
* @param context
|
||||
* @return the creatred OpenURLTracker
|
||||
* @throws SQLException
|
||||
*/
|
||||
OpenURLTracker create(Context context) throws SQLException;
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
* The Service responsible for processing urls
|
||||
*/
|
||||
public interface OpenUrlService {
|
||||
/**
|
||||
* Process the url
|
||||
* @param c - the context
|
||||
* @param urlStr - the url to be processed
|
||||
* @throws IOException
|
||||
* @throws SQLException
|
||||
*/
|
||||
void processUrl(Context c, String urlStr) throws SQLException;
|
||||
|
||||
/**
|
||||
* Will process all urls stored in the database and try contacting them again
|
||||
* @param context
|
||||
* @throws SQLException
|
||||
*/
|
||||
void reprocessFailedQueue(Context context) throws SQLException;
|
||||
|
||||
/**
|
||||
* Will log the failed url in the database
|
||||
* @param context
|
||||
* @param url
|
||||
* @throws SQLException
|
||||
*/
|
||||
void logfailed(Context context, String url) throws SQLException;
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.statistics.export.OpenURLTracker;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Implementation of the OpenUrlService interface
|
||||
*/
|
||||
public class OpenUrlServiceImpl implements OpenUrlService {
|
||||
|
||||
private Logger log = Logger.getLogger(OpenUrlService.class);
|
||||
|
||||
@Autowired
|
||||
protected FailedOpenURLTrackerService failedOpenUrlTrackerService;
|
||||
|
||||
/**
|
||||
* Processes the url
|
||||
* When the contacting the url fails, the url will be logged in a db table
|
||||
* @param c - the context
|
||||
* @param urlStr - the url to be processed
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void processUrl(Context c, String urlStr) throws SQLException {
|
||||
log.debug("Prepared to send url to tracker URL: " + urlStr);
|
||||
|
||||
try {
|
||||
int responseCode = getResponseCodeFromUrl(urlStr);
|
||||
if (responseCode != HttpURLConnection.HTTP_OK) {
|
||||
logfailed(c, urlStr);
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug("Successfully posted " + urlStr + " on " + new Date());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to send url to tracker URL: " + urlStr);
|
||||
logfailed(c, urlStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response code from accessing the url
|
||||
* @param urlStr
|
||||
* @return response code from the url
|
||||
* @throws IOException
|
||||
*/
|
||||
protected int getResponseCodeFromUrl(final String urlStr) throws IOException {
|
||||
URLConnection conn;
|
||||
URL url = new URL(urlStr);
|
||||
conn = url.openConnection();
|
||||
|
||||
HttpURLConnection httpURLConnection = (HttpURLConnection) conn;
|
||||
int responseCode = httpURLConnection.getResponseCode();
|
||||
httpURLConnection.disconnect();
|
||||
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry to send a failed url
|
||||
* @param context
|
||||
* @param tracker - db object containing the failed url
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected void tryReprocessFailed(Context context, OpenURLTracker tracker) throws SQLException {
|
||||
boolean success = false;
|
||||
try {
|
||||
|
||||
int responseCode = getResponseCodeFromUrl(tracker.getUrl());
|
||||
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
success = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
success = false;
|
||||
} finally {
|
||||
if (success) {
|
||||
failedOpenUrlTrackerService
|
||||
.remove(context, tracker);
|
||||
// If the tracker was able to post successfully, we remove it from the database
|
||||
log.info("Successfully posted " + tracker.getUrl() + " from " + tracker.getUploadDate());
|
||||
} else {
|
||||
// Still no luck - write an error msg but keep the entry in the table for future executions
|
||||
log.error("Failed attempt from " + tracker.getUrl() + " originating from " + tracker.getUploadDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reprocess all url trackers present in the database
|
||||
* @param context
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void reprocessFailedQueue(Context context) throws SQLException {
|
||||
if (failedOpenUrlTrackerService == null) {
|
||||
log.error("Error retrieving the \"failedOpenUrlTrackerService\" instance, aborting the processing");
|
||||
return;
|
||||
}
|
||||
List<OpenURLTracker> openURLTrackers = failedOpenUrlTrackerService.findAll(context);
|
||||
for (OpenURLTracker openURLTracker : openURLTrackers) {
|
||||
tryReprocessFailed(context, openURLTracker);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a failed url in the database
|
||||
* @param context
|
||||
* @param url
|
||||
* @throws SQLException
|
||||
*/
|
||||
public void logfailed(Context context, String url) throws SQLException {
|
||||
Date now = new Date();
|
||||
if (StringUtils.isBlank(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
OpenURLTracker tracker = failedOpenUrlTrackerService.create(context);
|
||||
tracker.setUploadDate(now);
|
||||
tracker.setUrl(url);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -10,8 +10,13 @@ package org.dspace.storage.rdbms;
|
||||
import java.sql.Connection;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Site;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.flywaydb.core.api.MigrationInfo;
|
||||
import org.flywaydb.core.api.callback.FlywayCallback;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -29,6 +34,12 @@ public class SiteServiceInitializer implements FlywayCallback {
|
||||
@Autowired(required = true)
|
||||
protected SiteService siteService;
|
||||
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Autowired
|
||||
private GroupService groupService;
|
||||
|
||||
public void initializeSiteObject() {
|
||||
// After every migrate, ensure default Site is setup correctly.
|
||||
Context context = null;
|
||||
@@ -37,10 +48,19 @@ public class SiteServiceInitializer implements FlywayCallback {
|
||||
context.turnOffAuthorisationSystem();
|
||||
// While it's not really a formal "registry", we need to ensure the
|
||||
// default, required Groups exist in the DSpace database
|
||||
Site site = null;
|
||||
if (siteService.findSite(context) == null) {
|
||||
siteService.createSite(context);
|
||||
site = siteService.createSite(context);
|
||||
}
|
||||
context.restoreAuthSystemState();
|
||||
if (!authorizeService.authorizeActionBoolean(context, site, Constants.READ)) {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Group anonGroup = groupService.findByName(context, Group.ANONYMOUS);
|
||||
if (anonGroup != null) {
|
||||
authorizeService.addPolicy(context, site, Constants.READ, anonGroup);
|
||||
}
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
// Commit changes and close context
|
||||
context.complete();
|
||||
} catch (Exception e) {
|
||||
|
@@ -0,0 +1,29 @@
|
||||
--
|
||||
-- The contents of this file are subject to the license and copyright
|
||||
-- detailed in the LICENSE and NOTICE files at the root of the source
|
||||
-- tree and available online at
|
||||
--
|
||||
-- http://www.dspace.org/license/
|
||||
--
|
||||
|
||||
-- ===============================================================
|
||||
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
--
|
||||
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
|
||||
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
|
||||
-- http://flywaydb.org/
|
||||
-- ===============================================================
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- This will create the setup for the IRUS statistics harvester
|
||||
-------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE openurltracker_seq;
|
||||
|
||||
CREATE TABLE openurltracker
|
||||
(
|
||||
tracker_id INTEGER,
|
||||
tracker_url VARCHAR(1000),
|
||||
uploaddate DATE,
|
||||
CONSTRAINT openurltracker_PK PRIMARY KEY (tracker_id)
|
||||
);
|
@@ -0,0 +1,29 @@
|
||||
--
|
||||
-- The contents of this file are subject to the license and copyright
|
||||
-- detailed in the LICENSE and NOTICE files at the root of the source
|
||||
-- tree and available online at
|
||||
--
|
||||
-- http://www.dspace.org/license/
|
||||
--
|
||||
|
||||
-- ===============================================================
|
||||
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
--
|
||||
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
|
||||
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
|
||||
-- http://flywaydb.org/
|
||||
-- ===============================================================
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- This will create the setup for the IRUS statistics harvester
|
||||
-------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE openurltracker_seq;
|
||||
|
||||
CREATE TABLE openurltracker
|
||||
(
|
||||
tracker_id NUMBER,
|
||||
tracker_url VARCHAR2(1000),
|
||||
uploaddate DATE,
|
||||
CONSTRAINT openurltracker_PK PRIMARY KEY (tracker_id)
|
||||
);
|
@@ -0,0 +1,29 @@
|
||||
--
|
||||
-- The contents of this file are subject to the license and copyright
|
||||
-- detailed in the LICENSE and NOTICE files at the root of the source
|
||||
-- tree and available online at
|
||||
--
|
||||
-- http://www.dspace.org/license/
|
||||
--
|
||||
|
||||
-- ===============================================================
|
||||
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
--
|
||||
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
|
||||
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
|
||||
-- http://flywaydb.org/
|
||||
-- ===============================================================
|
||||
|
||||
-------------------------------------------------------------
|
||||
-- This will create the setup for the IRUS statistics harvester
|
||||
-------------------------------------------------------------
|
||||
|
||||
CREATE SEQUENCE openurltracker_seq;
|
||||
|
||||
CREATE TABLE openurltracker
|
||||
(
|
||||
tracker_id INTEGER,
|
||||
tracker_url VARCHAR(1000),
|
||||
uploaddate DATE,
|
||||
CONSTRAINT openurltracker_PK PRIMARY KEY (tracker_id)
|
||||
);
|
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
|
||||
|
||||
<!-- Irus statistics tracking -->
|
||||
<bean class="org.dspace.statistics.export.IrusExportUsageEventListener">
|
||||
<property name="eventService" ref="org.dspace.services.EventService"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
||||
default-lazy-init="true">
|
||||
|
||||
|
||||
<bean class="org.dspace.statistics.export.FailedOpenURLTrackerServiceImpl"/>
|
||||
<bean class="org.dspace.statistics.export.service.MockOpenUrlServiceImpl"
|
||||
id="org.dspace.statistics.export.service.OpenUrlService"/>
|
||||
|
||||
<bean id="testProcessedUrls" class="java.util.ArrayList"/>
|
||||
|
||||
</beans>
|
@@ -27,9 +27,19 @@
|
||||
<property name="dspaceRunnableClass" value="org.dspace.curate.CurationCli"/>
|
||||
</bean>
|
||||
|
||||
<bean id="retry-tracker" class="org.dspace.statistics.export.RetryFailedOpenUrlTrackerScriptConfiguration" scope="prototype">
|
||||
<property name="description" value="Retry all failed commits to the OpenURLTracker"/>
|
||||
<property name="dspaceRunnableClass" value="org.dspace.statistics.export.RetryFailedOpenUrlTracker"/>
|
||||
</bean>
|
||||
|
||||
<bean id="another-mock-script" class="org.dspace.scripts.MockDSpaceRunnableScriptConfiguration" scope="prototype">
|
||||
<property name="description" value="Mocking a script for testing purposes" />
|
||||
<property name="dspaceRunnableClass" value="org.dspace.scripts.impl.MockDSpaceRunnableScript"/>
|
||||
</bean>
|
||||
<!-- Keep as last script; for test ScriptRestRepository#findOneScriptByNameTest -->
|
||||
<bean id="mock-script" class="org.dspace.scripts.MockDSpaceRunnableScriptConfiguration" scope="prototype">
|
||||
<property name="description" value="Mocking a script for testing purposes" />
|
||||
<property name="dspaceRunnableClass" value="org.dspace.scripts.impl.MockDSpaceRunnableScript"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
@@ -90,6 +90,10 @@ public class ItemBuilder extends AbstractDSpaceObjectBuilder<Item> {
|
||||
return addMetadataValue(item, "relationship", "type", null, relationshipType);
|
||||
}
|
||||
|
||||
public ItemBuilder withType(final String type) {
|
||||
return addMetadataValue(item, "dc", "type", null, type);
|
||||
}
|
||||
|
||||
public ItemBuilder withPublicationIssueNumber(final String issueNumber) {
|
||||
return addMetadataValue(item, "publicationissue", "issueNumber", null, issueNumber);
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ package org.dspace.builder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
@@ -43,6 +45,18 @@ public class ProcessBuilder extends AbstractBuilder<Process, ProcessService> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProcessBuilder withProcessStatus(ProcessStatus processStatus) {
|
||||
process.setProcessStatus(processStatus);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProcessBuilder withStartAndEndTime(String startTime, String endTime) throws ParseException {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
|
||||
process.setStartTime(simpleDateFormat.parse(startTime));
|
||||
process.setFinishedTime(simpleDateFormat.parse(endTime));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanup() throws Exception {
|
||||
try (Context c = new Context()) {
|
||||
|
@@ -1013,7 +1013,8 @@ public class CommunityTest extends AbstractDSpaceObjectTest {
|
||||
equalTo(c));
|
||||
assertThat("testGetAdminObject 1", (Community) communityService.getAdminObject(context, c, Constants.ADD),
|
||||
equalTo(c));
|
||||
assertThat("testGetAdminObject 2", communityService.getAdminObject(context, c, Constants.DELETE), nullValue());
|
||||
assertThat("testGetAdminObject 2", (Community) communityService.getAdminObject(context, c, Constants.DELETE),
|
||||
equalTo(c));
|
||||
assertThat("testGetAdminObject 3", (Community) communityService.getAdminObject(context, c, Constants.ADMIN),
|
||||
equalTo(c));
|
||||
}
|
||||
|
@@ -1598,8 +1598,8 @@ public class ItemTest extends AbstractDSpaceObjectTest {
|
||||
assertThat("testGetAdminObject 0", (Item) itemService.getAdminObject(context, it, Constants.REMOVE),
|
||||
equalTo(it));
|
||||
assertThat("testGetAdminObject 1", (Item) itemService.getAdminObject(context, it, Constants.ADD), equalTo(it));
|
||||
assertThat("testGetAdminObject 2", (Collection) itemService.getAdminObject(context, it, Constants.DELETE),
|
||||
equalTo(collection));
|
||||
assertThat("testGetAdminObject 2", (Item) itemService.getAdminObject(context, it, Constants.DELETE),
|
||||
equalTo(it));
|
||||
assertThat("testGetAdminObject 3", (Item) itemService.getAdminObject(context, it, Constants.ADMIN),
|
||||
equalTo(it));
|
||||
}
|
||||
|
@@ -14,13 +14,16 @@ import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dspace.AbstractUnitTest;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.SiteService;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -143,4 +146,17 @@ public class SiteTest extends AbstractUnitTest {
|
||||
assertThat("testGetURL 0", s.getURL(), equalTo(ConfigurationManager.getProperty("dspace.ui.url")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousReadRights() throws Exception {
|
||||
List<Group> groupList = authorizeService.getAuthorizedGroups(context, s, Constants.READ);
|
||||
boolean foundAnonInList = false;
|
||||
for (Group group : groupList) {
|
||||
if (StringUtils.equalsIgnoreCase(group.getName(), "Anonymous")) {
|
||||
foundAnonInList = true;
|
||||
}
|
||||
}
|
||||
assertTrue(foundAnonInList);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.statistics.export.dao.OpenURLTrackerDAO;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Class to test the FailedOpenURLTrackerServiceImpl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class FailedOpenURLTrackerServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
private FailedOpenURLTrackerServiceImpl openURLTrackerLoggerService;
|
||||
|
||||
@Mock
|
||||
private Context context;
|
||||
|
||||
@Mock
|
||||
private OpenURLTracker openURLTracker;
|
||||
|
||||
@Mock
|
||||
private OpenURLTrackerDAO openURLTrackerDAO;
|
||||
|
||||
/**
|
||||
* Tests the remove method
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testRemove() throws SQLException {
|
||||
openURLTrackerLoggerService.remove(context, openURLTracker);
|
||||
|
||||
Mockito.verify(openURLTrackerDAO, times(1)).delete(context, openURLTracker);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the findAll method
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testFindAll() throws SQLException {
|
||||
List<OpenURLTracker> trackers = new ArrayList<>();
|
||||
|
||||
when(openURLTrackerDAO.findAll(context, OpenURLTracker.class)).thenReturn(trackers);
|
||||
|
||||
assertEquals("TestFindAll 0", trackers, openURLTrackerLoggerService.findAll(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the create method
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testCreate() throws SQLException {
|
||||
OpenURLTracker tracker = new OpenURLTracker();
|
||||
|
||||
when(openURLTrackerDAO.create(any(), any())).thenReturn(tracker);
|
||||
|
||||
assertEquals("TestCreate 0", tracker, openURLTrackerLoggerService.create(context));
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,418 @@
|
||||
/**
|
||||
* 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.statistics.export;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.builder.BitstreamBuilder;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.EntityTypeBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.EntityType;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.BitstreamService;
|
||||
import org.dspace.content.service.BundleService;
|
||||
import org.dspace.content.service.CollectionService;
|
||||
import org.dspace.content.service.CommunityService;
|
||||
import org.dspace.content.service.EntityTypeService;
|
||||
import org.dspace.content.service.InstallItemService;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.content.service.WorkspaceItemService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.eperson.service.GroupService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.statistics.export.factory.OpenURLTrackerLoggerServiceFactory;
|
||||
import org.dspace.statistics.export.service.FailedOpenURLTrackerService;
|
||||
import org.dspace.usage.UsageEvent;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for the IrusExportUsageEventListener
|
||||
*/
|
||||
//@RunWith(MockitoJUnitRunner.class)
|
||||
public class ITIrusExportUsageEventListener extends AbstractIntegrationTestWithDatabase {
|
||||
|
||||
private static Logger log = Logger.getLogger(ITIrusExportUsageEventListener.class);
|
||||
|
||||
|
||||
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
|
||||
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
||||
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
||||
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
|
||||
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
|
||||
protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
||||
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
||||
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
||||
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
||||
protected EntityTypeService entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
|
||||
protected FailedOpenURLTrackerService failedOpenURLTrackerService =
|
||||
OpenURLTrackerLoggerServiceFactory.getInstance().getOpenUrlTrackerLoggerService();
|
||||
|
||||
protected ArrayList testProcessedUrls = DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("testProcessedUrls",
|
||||
ArrayList.class);
|
||||
|
||||
private IrusExportUsageEventListener exportUsageEventListener =
|
||||
DSpaceServicesFactory.getInstance()
|
||||
.getServiceManager()
|
||||
.getServicesByType(IrusExportUsageEventListener.class)
|
||||
.get(0);
|
||||
|
||||
private Item item;
|
||||
private Item itemNotToBeProcessed;
|
||||
private Bitstream bitstream;
|
||||
private Bitstream bitstreamNotToBeProcessed;
|
||||
private EntityType entityType;
|
||||
private Community community;
|
||||
private Collection collection;
|
||||
|
||||
private String encodedUrl;
|
||||
private String encodedUIUrl;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the test by setting up all objects needed to create a test item
|
||||
*/
|
||||
@Before()
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
configurationService.setProperty("irus.statistics.tracker.enabled", true);
|
||||
configurationService.setProperty("irus.statistics.tracker.type-field", "dc.type");
|
||||
configurationService.setProperty("irus.statistics.tracker.type-value", "Excluded type");
|
||||
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
try {
|
||||
|
||||
entityType = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build();
|
||||
community = CommunityBuilder.createCommunity(context).build();
|
||||
collection = CollectionBuilder.createCollection(context, community).build();
|
||||
item = ItemBuilder.createItem(context, collection)
|
||||
.withRelationshipType(entityType.getLabel())
|
||||
.build();
|
||||
|
||||
File f = new File(testProps.get("test.bitstream").toString());
|
||||
bitstream = BitstreamBuilder.createBitstream(context, item, new FileInputStream(f)).build();
|
||||
|
||||
itemNotToBeProcessed = ItemBuilder.createItem(context, collection)
|
||||
.withRelationshipType(entityType.getLabel())
|
||||
.withType("Excluded type")
|
||||
.build();
|
||||
File itemNotToBeProcessedFile = new File(testProps.get("test.bitstream").toString());
|
||||
bitstreamNotToBeProcessed = BitstreamBuilder
|
||||
.createBitstream(context, itemNotToBeProcessed, new FileInputStream(itemNotToBeProcessedFile))
|
||||
.build();
|
||||
|
||||
String dspaceUrl = configurationService.getProperty("dspace.server.url");
|
||||
encodedUrl = URLEncoder.encode(dspaceUrl, CharEncoding.UTF_8);
|
||||
String dspaceUIUrl = configurationService.getProperty("dspace.ui.url");
|
||||
encodedUIUrl = URLEncoder.encode(dspaceUIUrl, CharEncoding.UTF_8);
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the created objects
|
||||
* Empty the testProcessedUrls used to store succeeded urls
|
||||
* Empty the database table where the failed urls are logged
|
||||
*/
|
||||
@After
|
||||
public void destroy() throws Exception {
|
||||
try {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
for (OpenURLTracker tracker : all) {
|
||||
failedOpenURLTrackerService.remove(context, tracker);
|
||||
}
|
||||
|
||||
// Clear the list of processedUrls
|
||||
testProcessedUrls.clear();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
context.complete();
|
||||
} catch (SQLException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of an item meeting all conditions is processed and succeeds
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnItemThatShouldBeProcessed() throws UnsupportedEncodingException, SQLException {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRemoteAddr()).thenReturn("client-ip");
|
||||
when(request.getHeader(anyString())).thenReturn(null);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(item);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
|
||||
String regex = "https://irus.jisc.ac.uk/counter/test/\\?url_ver=Z39.88-2004&req_id=" +
|
||||
URLEncoder.encode(request.getRemoteAddr(), "UTF-8") + "&req_dat=&rft" +
|
||||
".artnum=oai%3Alocalhost%3A" + URLEncoder.encode(item.getHandle(), "UTF-8") + "&rfr_dat=&rfr_id" +
|
||||
"=localhost&url_tim=" + ".*" + "?&svc_dat=" + encodedUIUrl + "%2Fhandle%2F" + URLEncoder
|
||||
.encode(item.getHandle(), "UTF-8") + "&rft_dat=Investigation";
|
||||
|
||||
boolean isMatch = matchesString(String.valueOf(testProcessedUrls.get(0)), regex);
|
||||
|
||||
assertEquals(1, testProcessedUrls.size());
|
||||
assertTrue(isMatch);
|
||||
assertEquals(0, all.size());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of an item meeting all conditions is processed but fails
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnItemThatShouldBeProcessedFailed() throws SQLException, UnsupportedEncodingException {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRemoteAddr()).thenReturn("client-ip-fail");
|
||||
when(request.getHeader(anyString())).thenReturn(null);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(item);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
String regex = "https://irus.jisc.ac.uk/counter/test/\\?url_ver=Z39.88-2004&req_id=" +
|
||||
URLEncoder.encode(request.getRemoteAddr(), "UTF-8") + "&req_dat=&rft" +
|
||||
".artnum=oai%3Alocalhost%3A" + URLEncoder.encode(item.getHandle(), "UTF-8") + "&rfr_dat=&rfr_id" +
|
||||
"=localhost&url_tim=" + ".*" + "?&svc_dat=" + encodedUIUrl + "%2Fhandle%2F" + URLEncoder
|
||||
.encode(item.getHandle(), "UTF-8") + "&rft_dat=Investigation";
|
||||
|
||||
boolean isMatch = matchesString(all.get(0).getUrl(), regex);
|
||||
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
|
||||
assertEquals(1, all.size());
|
||||
assertTrue(isMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of an item that does not meet all conditions is not processed
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnItemThatShouldNotBeProcessed() throws SQLException, AuthorizeException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(itemNotToBeProcessed);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
itemService.clearMetadata(context, item, "relationship", "type", null, Item.ANY);
|
||||
itemService.addMetadata(context, item, "relationship", "type", null, null, "OrgUnit");
|
||||
itemService.update(context, item);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
// doCallRealMethod().when(IrusExportUsageEventListener).receiveEvent(usageEvent);
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
assertEquals(0, all.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of a bitstream meeting all conditions is processed and succeeds
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnBitstreamThatShouldBeProcessed() throws SQLException, UnsupportedEncodingException {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRemoteAddr()).thenReturn("client-ip");
|
||||
when(request.getHeader(anyString())).thenReturn(null);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(bitstream);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
String regex = "https://irus.jisc.ac.uk/counter/test/\\?url_ver=Z39.88-2004&req_id=" +
|
||||
URLEncoder.encode(request.getRemoteAddr(), "UTF-8") + "&req_dat=&rft" +
|
||||
".artnum=oai%3Alocalhost%3A" + URLEncoder.encode(item.getHandle(), "UTF-8") + "&rfr_dat=&rfr_id" +
|
||||
"=localhost&url_tim=" + ".*" + "?&svc_dat=" + encodedUrl + "%2Fapi%2Fcore%2Fbitstreams" +
|
||||
"%2F" + bitstream.getID() + "%2Fcontent" + "&rft_dat=Request";
|
||||
|
||||
boolean isMatch = matchesString(String.valueOf(testProcessedUrls.get(0)), regex);
|
||||
|
||||
assertEquals(1, testProcessedUrls.size());
|
||||
assertTrue(isMatch);
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
assertEquals(0, all.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of a bitstream meeting all conditions is processed but fails
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnBitstreamThatShouldBeProcessedFail() throws UnsupportedEncodingException,
|
||||
SQLException {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRemoteAddr()).thenReturn("client-ip-fail");
|
||||
when(request.getHeader(anyString())).thenReturn(null);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(bitstream);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
String regex = "https://irus.jisc.ac.uk/counter/test/\\?url_ver=Z39.88-2004&req_id=" +
|
||||
URLEncoder.encode(request.getRemoteAddr(), "UTF-8") + "&req_dat=&rft" +
|
||||
".artnum=oai%3Alocalhost%3A" + URLEncoder.encode(item.getHandle(), "UTF-8") + "&rfr_dat=&rfr_id" +
|
||||
"=localhost&url_tim=" + ".*" + "?&svc_dat=" + encodedUrl + "%2Fapi%2Fcore%2Fbitstreams" +
|
||||
"%2F" + bitstream.getID() + "%2Fcontent" + "&rft_dat=Request";
|
||||
|
||||
|
||||
boolean isMatch = matchesString(all.get(0).getUrl(), regex);
|
||||
|
||||
assertEquals(1, all.size());
|
||||
assertEquals(true, isMatch);
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether the usage event of a bitstream that does not meet all conditions is not processed
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnBitstreamThatShouldNotBeProcessed() throws SQLException, AuthorizeException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
when(request.getRemoteAddr()).thenReturn("client-ip-fail");
|
||||
when(request.getHeader(anyString())).thenReturn(null);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(bitstreamNotToBeProcessed);
|
||||
when(usageEvent.getRequest()).thenReturn(request);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
itemService.clearMetadata(context, item, "relationship", "type", null, Item.ANY);
|
||||
itemService.addMetadata(context, item, "relationship", "type", null, null, "OrgUnit");
|
||||
itemService.update(context, item);
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
|
||||
assertEquals(0, all.size());
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an object that is not an Item or Bitstream is not processed
|
||||
*/
|
||||
@Test
|
||||
public void testReceiveEventOnNonRelevantObject() throws SQLException {
|
||||
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
UsageEvent usageEvent = mock(UsageEvent.class);
|
||||
when(usageEvent.getObject()).thenReturn(community);
|
||||
when(usageEvent.getContext()).thenReturn(new Context());
|
||||
|
||||
exportUsageEventListener.receiveEvent(usageEvent);
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
|
||||
assertEquals(0, all.size());
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to test if a string matches a regex
|
||||
*
|
||||
* @param string
|
||||
* @param regex
|
||||
* @return whether the regex matches the string
|
||||
*/
|
||||
private boolean matchesString(String string, String regex) {
|
||||
|
||||
Pattern p = Pattern.compile(regex);
|
||||
|
||||
if (p.matcher(string).matches()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,182 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.statistics.export;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.AbstractIntegrationTest;
|
||||
import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
|
||||
import org.dspace.scripts.DSpaceRunnable;
|
||||
import org.dspace.scripts.configuration.ScriptConfiguration;
|
||||
import org.dspace.scripts.factory.ScriptServiceFactory;
|
||||
import org.dspace.scripts.service.ScriptService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.dspace.statistics.export.factory.OpenURLTrackerLoggerServiceFactory;
|
||||
import org.dspace.statistics.export.service.FailedOpenURLTrackerService;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Class to test the RetryFailedOpenUrlTracker
|
||||
*/
|
||||
public class ITRetryFailedOpenUrlTracker extends AbstractIntegrationTest {
|
||||
|
||||
private static Logger log = Logger.getLogger(ITRetryFailedOpenUrlTracker.class);
|
||||
|
||||
|
||||
protected FailedOpenURLTrackerService failedOpenURLTrackerService =
|
||||
OpenURLTrackerLoggerServiceFactory.getInstance().getOpenUrlTrackerLoggerService();
|
||||
|
||||
protected ArrayList testProcessedUrls = DSpaceServicesFactory.getInstance().getServiceManager()
|
||||
.getServiceByName("testProcessedUrls",
|
||||
ArrayList.class);
|
||||
|
||||
private ScriptService scriptService = ScriptServiceFactory.getInstance().getScriptService();
|
||||
|
||||
|
||||
/**
|
||||
* Clean up the logged entries from the db after each test
|
||||
*/
|
||||
@After
|
||||
@Override
|
||||
public void destroy() {
|
||||
try {
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
for (OpenURLTracker tracker : all) {
|
||||
failedOpenURLTrackerService.remove(context, tracker);
|
||||
}
|
||||
|
||||
// Clear the list of processedUrls
|
||||
testProcessedUrls.clear();
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
try {
|
||||
context.complete();
|
||||
} catch (SQLException e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the mode of the script that allows the user to add a failed url to the database
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testAddNewFailedUrl() throws Exception {
|
||||
|
||||
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||
ScriptConfiguration retryOpenUrlTrackerConfig = scriptService.getScriptConfiguration("retry-tracker");
|
||||
DSpaceRunnable retryOpenUrlTracker =
|
||||
scriptService.createDSpaceRunnableForScriptConfiguration(retryOpenUrlTrackerConfig);
|
||||
String urlToAdd = "test-failed-url";
|
||||
String[] args = {"-a", urlToAdd};
|
||||
|
||||
retryOpenUrlTracker.initialize(args, testDSpaceRunnableHandler, eperson);
|
||||
retryOpenUrlTracker.internalRun();
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
assertEquals(0, testProcessedUrls.size());
|
||||
assertEquals(1, all.size());
|
||||
assertEquals(urlToAdd, all.get(0).getUrl());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to check that all logged failed urls are reprocessed succesfully and removed from the db
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testReprocessAllUrls() throws Exception {
|
||||
|
||||
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||
ScriptConfiguration retryOpenUrlTrackerConfig = scriptService.getScriptConfiguration("retry-tracker");
|
||||
DSpaceRunnable retryOpenUrlTracker =
|
||||
scriptService.createDSpaceRunnableForScriptConfiguration(retryOpenUrlTrackerConfig);
|
||||
String[] args = {"-r"};
|
||||
|
||||
OpenURLTracker tracker1 = failedOpenURLTrackerService.create(context);
|
||||
tracker1.setUrl("test-url-1");
|
||||
OpenURLTracker tracker2 = failedOpenURLTrackerService.create(context);
|
||||
tracker2.setUrl("test-url-2");
|
||||
OpenURLTracker tracker3 = failedOpenURLTrackerService.create(context);
|
||||
tracker3.setUrl("test-url-3");
|
||||
|
||||
|
||||
retryOpenUrlTracker.initialize(args, testDSpaceRunnableHandler, eperson);
|
||||
retryOpenUrlTracker.internalRun();
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
|
||||
assertEquals(3, testProcessedUrls.size());
|
||||
assertEquals(true, testProcessedUrls.contains("test-url-1"));
|
||||
assertEquals(true, testProcessedUrls.contains("test-url-2"));
|
||||
assertEquals(true, testProcessedUrls.contains("test-url-3"));
|
||||
|
||||
assertEquals(0, all.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to check that the successful retries are removed, but the failed retries remain in the db
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testReprocessPartOfUrls() throws Exception {
|
||||
|
||||
TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
|
||||
ScriptConfiguration retryOpenUrlTrackerConfig = scriptService.getScriptConfiguration("retry-tracker");
|
||||
DSpaceRunnable retryOpenUrlTracker =
|
||||
scriptService.createDSpaceRunnableForScriptConfiguration(retryOpenUrlTrackerConfig);
|
||||
String[] args = {"-r"};
|
||||
|
||||
OpenURLTracker tracker1 = failedOpenURLTrackerService.create(context);
|
||||
tracker1.setUrl("test-url-1");
|
||||
OpenURLTracker tracker2 = failedOpenURLTrackerService.create(context);
|
||||
tracker2.setUrl("test-url-2-fail");
|
||||
OpenURLTracker tracker3 = failedOpenURLTrackerService.create(context);
|
||||
tracker3.setUrl("test-url-3-fail");
|
||||
OpenURLTracker tracker4 = failedOpenURLTrackerService.create(context);
|
||||
tracker4.setUrl("test-url-4-fail");
|
||||
OpenURLTracker tracker5 = failedOpenURLTrackerService.create(context);
|
||||
tracker5.setUrl("test-url-5");
|
||||
|
||||
|
||||
retryOpenUrlTracker.initialize(args, testDSpaceRunnableHandler, eperson);
|
||||
retryOpenUrlTracker.internalRun();
|
||||
|
||||
List<OpenURLTracker> all = failedOpenURLTrackerService.findAll(context);
|
||||
List<String> storedTrackerUrls = new ArrayList<>();
|
||||
for (OpenURLTracker tracker : all) {
|
||||
storedTrackerUrls.add(tracker.getUrl());
|
||||
}
|
||||
|
||||
assertEquals(2, testProcessedUrls.size());
|
||||
assertEquals(true, testProcessedUrls.contains("test-url-1"));
|
||||
assertEquals(true, testProcessedUrls.contains("test-url-5"));
|
||||
|
||||
assertEquals(3, all.size());
|
||||
assertEquals(true, storedTrackerUrls.contains("test-url-2-fail"));
|
||||
assertEquals(true, storedTrackerUrls.contains("test-url-3-fail"));
|
||||
assertEquals(true, storedTrackerUrls.contains("test-url-4-fail"));
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.builder.BitstreamBuilder;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for the BitstreamEventProcessor
|
||||
*/
|
||||
public class BitstreamEventProcessorTest extends AbstractIntegrationTestWithDatabase {
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
|
||||
private String encodedUrl;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
configurationService.setProperty("irus.statistics.tracker.enabled", true);
|
||||
|
||||
String dspaceUrl = configurationService.getProperty("dspace.server.url");
|
||||
try {
|
||||
encodedUrl = URLEncoder.encode(dspaceUrl, CharEncoding.UTF_8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError("Error occurred in setup()", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the method that adds data based on the object types
|
||||
*/
|
||||
public void testAddObectSpecificData() throws Exception {
|
||||
HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).build();
|
||||
|
||||
File f = new File(testProps.get("test.bitstream").toString());
|
||||
Bitstream bitstream = BitstreamBuilder.createBitstream(context, item, new FileInputStream(f)).build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
BitstreamEventProcessor bitstreamEventProcessor = new BitstreamEventProcessor(context, request, bitstream);
|
||||
|
||||
String result = bitstreamEventProcessor.addObjectSpecificData("existing-string", bitstream);
|
||||
|
||||
assertThat(result,
|
||||
is("existing-string&svc_dat=" + encodedUrl + "%2Fapi%2Fcore%2Fbitstreams%2F" + bitstream.getID()
|
||||
+ "%2Fcontent&rft_dat=Request"));
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.sql.SQLException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.EntityTypeBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.builder.WorkspaceItemBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.EntityType;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
|
||||
/**
|
||||
* Test for the ExportEventProcessor class
|
||||
*/
|
||||
public class ExportEventProcessorTest extends AbstractIntegrationTestWithDatabase {
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private EntityType publication;
|
||||
private EntityType otherEntity;
|
||||
private final String excluded_type = "Excluded type";
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
configurationService.setProperty("irus.statistics.tracker.urlversion", "Z39.88-2004");
|
||||
configurationService.setProperty("irus.statistics.tracker.enabled", true);
|
||||
configurationService.setProperty("irus.statistics.tracker.type-field", "dc.type");
|
||||
configurationService.setProperty("irus.statistics.tracker.type-value", "Excluded type");
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
publication = EntityTypeBuilder.createEntityTypeBuilder(context, "Publication").build();
|
||||
otherEntity = EntityTypeBuilder.createEntityTypeBuilder(context, "Other").build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the getBaseParameters method
|
||||
*/
|
||||
public void testGetBaseParameters() throws UnsupportedEncodingException {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).build();
|
||||
String encodedHandle = URLEncoder.encode(item.getHandle(), CharEncoding.UTF_8);
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
when(request.getRemoteAddr()).thenReturn("test-client-ip");
|
||||
when(request.getHeader("USER-AGENT")).thenReturn("test-user-agent");
|
||||
when(request.getHeader("referer")).thenReturn("test-referer");
|
||||
|
||||
String result = exportEventProcessor.getBaseParameters(item);
|
||||
String expected = "url_ver=Z39.88-2004&req_id=test-client-ip&req_dat=test-user-agent&rft.artnum=" +
|
||||
"oai%3Alocalhost%3A" + encodedHandle + "&rfr_dat=test-referer&rfr_id=localhost&url_tim=";
|
||||
|
||||
assertThat(result, startsWith(expected));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where the item is null
|
||||
*/
|
||||
public void testShouldProcessItemWhenNull() throws SQLException {
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, null);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(null);
|
||||
assertThat(result, is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where the item is not archived
|
||||
*/
|
||||
public void testShouldProcessItemWhenNotArchived() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
WorkspaceItem workspaceItem = WorkspaceItemBuilder.createWorkspaceItem(context, collection).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, workspaceItem.getItem());
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(workspaceItem.getItem());
|
||||
assertFalse(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where the item can be edit by the current user
|
||||
*/
|
||||
public void testShouldProcessItemWhenCanEdit() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withRelationshipType(otherEntity.getLabel()).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
context.setCurrentUser(admin);
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(item);
|
||||
assertFalse(result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where the item type should be excluded
|
||||
*/
|
||||
public void testShouldProcessItemWhenShouldNotProcessType() throws Exception {
|
||||
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection)
|
||||
.withType("Excluded type")
|
||||
.withRelationshipType(publication.getLabel())
|
||||
.build();
|
||||
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(item);
|
||||
assertFalse(result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where the item entity type should not be processed
|
||||
*/
|
||||
public void testShouldProcessItemWhenShouldNotProcessEntity() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withRelationshipType(otherEntity.getLabel()).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(item);
|
||||
assertFalse(result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessItem method where all conditions are met
|
||||
*/
|
||||
public void testShouldProcessItem() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withRelationshipType(publication.getLabel()).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItem(item);
|
||||
assertTrue(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessEntityType method where all conditions are met
|
||||
*/
|
||||
public void testShouldProcessEntityType() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withRelationshipType(publication.getLabel()).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessEntityType(item);
|
||||
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the ShouldProcessEntityType method where the item entity type is not present in the configured list
|
||||
*/
|
||||
public void testShouldProcessEntityTypeWhenNotInList() throws SQLException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withRelationshipType(otherEntity.getLabel()).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessEntityType(item);
|
||||
|
||||
assertFalse(result);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the shouldProcessItemType method where the item type is present in the list of excluded types
|
||||
*/
|
||||
public void testShouldProcessItemTypeInExcludeTrackerTypeList() {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withType(excluded_type).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItemType(item);
|
||||
assertFalse(result);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the shouldProcessItemType method where the item type is not present in the list of excluded types
|
||||
*/
|
||||
public void testShouldProcessItemTypeNotInExcludeTrackerTypeList() {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).withType("Not excluded type").build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
ExportEventProcessor exportEventProcessor = new ItemEventProcessor(context, request, item);
|
||||
|
||||
boolean result = exportEventProcessor.shouldProcessItemType(item);
|
||||
assertTrue(result);
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* 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.statistics.export.processor;
|
||||
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.dspace.AbstractIntegrationTestWithDatabase;
|
||||
import org.dspace.builder.CollectionBuilder;
|
||||
import org.dspace.builder.CommunityBuilder;
|
||||
import org.dspace.builder.ItemBuilder;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test class for the ItemEventProcessor
|
||||
*/
|
||||
public class ItemEventProcessorTest extends AbstractIntegrationTestWithDatabase {
|
||||
|
||||
|
||||
private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
|
||||
|
||||
private String encodedUrl;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
configurationService.setProperty("irus.statistics.tracker.enabled", true);
|
||||
|
||||
String dspaceUrl = configurationService.getProperty("dspace.ui.url");
|
||||
try {
|
||||
encodedUrl = URLEncoder.encode(dspaceUrl, CharEncoding.UTF_8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError("Error occurred in setup()", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
/**
|
||||
* Test the method that adds data based on the object types
|
||||
*/
|
||||
public void testAddObectSpecificData() throws UnsupportedEncodingException {
|
||||
context.turnOffAuthorisationSystem();
|
||||
Community community = CommunityBuilder.createCommunity(context).build();
|
||||
Collection collection = CollectionBuilder.createCollection(context, community).build();
|
||||
Item item = ItemBuilder.createItem(context, collection).build();
|
||||
context.restoreAuthSystemState();
|
||||
|
||||
String encodedHandle = URLEncoder.encode(item.getHandle(), CharEncoding.UTF_8);
|
||||
|
||||
ItemEventProcessor itemEventProcessor = new ItemEventProcessor(context, null, item);
|
||||
String result = itemEventProcessor.addObjectSpecificData("existing-string", item);
|
||||
|
||||
assertThat(result,
|
||||
is("existing-string&svc_dat=" + encodedUrl + "%2Fhandle%2F" + encodedHandle +
|
||||
"&rft_dat=Investigation"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Mock OpenUrlService that will ensure that IRUS tracker does need to be contacted in order to test the functionality
|
||||
*/
|
||||
public class MockOpenUrlServiceImpl extends OpenUrlServiceImpl {
|
||||
|
||||
@Autowired
|
||||
ArrayList testProcessedUrls;
|
||||
|
||||
/**
|
||||
* Returns a response code to simulate contact to the external url
|
||||
* When the url contains "fail", a fail code 500 will be returned
|
||||
* Otherwise the success code 200 will be returned
|
||||
* @param urlStr
|
||||
* @return 200 or 500 depending on whether the "fail" keyword is present in the url
|
||||
* @throws IOException
|
||||
*/
|
||||
protected int getResponseCodeFromUrl(final String urlStr) throws IOException {
|
||||
if (StringUtils.contains(urlStr, "fail")) {
|
||||
return HttpURLConnection.HTTP_INTERNAL_ERROR;
|
||||
} else {
|
||||
testProcessedUrls.add(urlStr);
|
||||
return HttpURLConnection.HTTP_OK;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doCallRealMethod;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.statistics.export.OpenURLTracker;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* Test class for the OpenUrlServiceImpl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class OpenUrlServiceImplTest {
|
||||
|
||||
@InjectMocks
|
||||
@Spy
|
||||
private OpenUrlServiceImpl openUrlService;
|
||||
|
||||
@Mock
|
||||
private FailedOpenURLTrackerService failedOpenURLTrackerService;
|
||||
|
||||
/**
|
||||
* Test the processUrl method
|
||||
* @throws IOException
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testProcessUrl() throws IOException, SQLException {
|
||||
Context context = mock(Context.class);
|
||||
|
||||
doReturn(HttpURLConnection.HTTP_OK).when(openUrlService)
|
||||
.getResponseCodeFromUrl(anyString());
|
||||
openUrlService.processUrl(context, "test-url");
|
||||
|
||||
verify(openUrlService, times(0)).logfailed(context, "test-url");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the processUrl method when the url connection fails
|
||||
* @throws IOException
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testProcessUrlOnFail() throws IOException, SQLException {
|
||||
Context context = mock(Context.class);
|
||||
|
||||
doReturn(HttpURLConnection.HTTP_INTERNAL_ERROR).when(openUrlService)
|
||||
.getResponseCodeFromUrl(anyString());
|
||||
doNothing().when(openUrlService).logfailed(any(Context.class), anyString());
|
||||
|
||||
openUrlService.processUrl(context, "test-url");
|
||||
|
||||
verify(openUrlService, times(1)).logfailed(context, "test-url");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the ReprocessFailedQueue method
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testReprocessFailedQueue() throws SQLException {
|
||||
Context context = mock(Context.class);
|
||||
|
||||
List<OpenURLTracker> trackers = new ArrayList<>();
|
||||
OpenURLTracker tracker1 = mock(OpenURLTracker.class);
|
||||
OpenURLTracker tracker2 = mock(OpenURLTracker.class);
|
||||
OpenURLTracker tracker3 = mock(OpenURLTracker.class);
|
||||
|
||||
trackers.add(tracker1);
|
||||
trackers.add(tracker2);
|
||||
trackers.add(tracker3);
|
||||
|
||||
when(failedOpenURLTrackerService.findAll(any(Context.class))).thenReturn(trackers);
|
||||
doNothing().when(openUrlService).tryReprocessFailed(any(Context.class), any(OpenURLTracker.class));
|
||||
|
||||
openUrlService.reprocessFailedQueue(context);
|
||||
|
||||
verify(openUrlService, times(3)).tryReprocessFailed(any(Context.class), any(OpenURLTracker.class));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the method that logs the failed urls in the db
|
||||
* @throws SQLException
|
||||
*/
|
||||
@Test
|
||||
public void testLogfailed() throws SQLException {
|
||||
Context context = mock(Context.class);
|
||||
OpenURLTracker tracker1 = mock(OpenURLTracker.class);
|
||||
|
||||
doCallRealMethod().when(tracker1).setUrl(anyString());
|
||||
when(tracker1.getUrl()).thenCallRealMethod();
|
||||
|
||||
when(failedOpenURLTrackerService.create(any(Context.class))).thenReturn(tracker1);
|
||||
|
||||
String failedUrl = "failed-url";
|
||||
openUrlService.logfailed(context, failedUrl);
|
||||
|
||||
Assert.assertThat(tracker1.getUrl(), is(failedUrl));
|
||||
|
||||
}
|
||||
}
|
@@ -29,121 +29,6 @@
|
||||
<start-class>org.dspace.app.rest.Application</start-class>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
||||
See also the 'skiptests' profile in Parent POM. -->
|
||||
<profile>
|
||||
<id>test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Unit/Integration Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupTestEnvironment</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the FileWeaver & Surefire plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>generate-test-resources
|
||||
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<!-- Specify the dspace.dir to use for test environment -->
|
||||
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
|
||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
||||
<!-- Turn off any DSpace logging -->
|
||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<!-- Specify the dspace.dir to use for test environment -->
|
||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
||||
<!-- Turn off any DSpace logging -->
|
||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -187,9 +72,160 @@
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: https://groovy.github.io/gmaven/groovy-maven-plugin/execute.html )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire & Failsafe plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- Setup the Unit Test Environment (when -DskipUnitTests=false) -->
|
||||
<profile>
|
||||
<id>unit-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipUnitTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Unit Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupUnitTestEnvironment</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<!-- Specify the dspace.dir to use for test environment -->
|
||||
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
|
||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
||||
<!-- Turn off any DSpace logging -->
|
||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</profile>
|
||||
|
||||
<!-- Setup the Integration Test Environment (when -DskipIntegrationTests=false) -->
|
||||
<profile>
|
||||
<id>integration-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipIntegrationTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Integration Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<!-- Specify the dspace.dir to use for test environment -->
|
||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
||||
<!-- Turn off any DSpace logging -->
|
||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||
<solr.install.dir>${agnostic.build.dir}/testing/dspace/solr/</solr.install.dir>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@@ -62,8 +63,14 @@ public class ShibbolethRestController implements InitializingBean {
|
||||
// Validate that the redirectURL matches either the server or UI hostname. It *cannot* be an arbitrary URL.
|
||||
String redirectHostName = Utils.getHostName(redirectUrl);
|
||||
String serverHostName = Utils.getHostName(configurationService.getProperty("dspace.server.url"));
|
||||
String clientHostName = Utils.getHostName(configurationService.getProperty("dspace.ui.url"));
|
||||
if (StringUtils.equalsAnyIgnoreCase(redirectHostName, serverHostName, clientHostName)) {
|
||||
ArrayList<String> allowedHostNames = new ArrayList<String>();
|
||||
allowedHostNames.add(serverHostName);
|
||||
String[] allowedUrls = configurationService.getArrayProperty("rest.cors.allowed-origins");
|
||||
for (String url : allowedUrls) {
|
||||
allowedHostNames.add(Utils.getHostName(url));
|
||||
}
|
||||
|
||||
if (StringUtils.equalsAnyIgnoreCase(redirectHostName, allowedHostNames.toArray(new String[0]))) {
|
||||
log.debug("Shibboleth redirecting to " + redirectUrl);
|
||||
response.sendRedirect(redirectUrl);
|
||||
} else {
|
||||
|
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.content.service.DSpaceObjectService;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This class is a wrapper around the AuthorizationService which takes Rest objects instead of dspace objects
|
||||
*/
|
||||
@Component
|
||||
public class AuthorizeServiceRestUtil {
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
@Autowired
|
||||
private ContentServiceFactory contentServiceFactory;
|
||||
|
||||
/**
|
||||
* Checks that the specified eperson can perform the given action on the rest given object.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param object The Rest object to test the action against
|
||||
* @param dSpaceRestPermission The permission to check
|
||||
* @return A boolean indicating if the action is allowed by the logged in ePerson on the given object
|
||||
* @throws SQLException
|
||||
*/
|
||||
public boolean authorizeActionBoolean(Context context, BaseObjectRest object,
|
||||
DSpaceRestPermission dSpaceRestPermission)
|
||||
throws SQLException {
|
||||
|
||||
DSpaceObject dSpaceObject = (DSpaceObject)utils.getDSpaceAPIObjectFromRest(context, object);
|
||||
if (dSpaceObject == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DSpaceObjectService<DSpaceObject> dSpaceObjectService =
|
||||
contentServiceFactory.getDSpaceObjectService(dSpaceObject.getType());
|
||||
|
||||
EPerson ePerson = context.getCurrentUser();
|
||||
|
||||
// If the item is still inprogress we can process here only the READ permission.
|
||||
// Other actions need to be evaluated against the wrapper object (workspace or workflow item)
|
||||
if (dSpaceObject instanceof Item) {
|
||||
if (!DSpaceRestPermission.READ.equals(dSpaceRestPermission)
|
||||
&& !((Item) dSpaceObject).isArchived() && !((Item) dSpaceObject).isWithdrawn()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return authorizeService.authorizeActionBoolean(context, ePerson, dSpaceObject,
|
||||
dSpaceRestPermission.getDspaceApiActionId(), true);
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.BundleService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The create bitstream feature. It can be used to verify if bitstreams can be created in a specific bundle.
|
||||
*
|
||||
* Authorization is granted if the current user has ADD & WRITE permissions on the given bundle AND the item
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = CreateBitstreamFeature.NAME,
|
||||
description = "It can be used to verify if bitstreams can be created in a specific bundle")
|
||||
public class CreateBitstreamFeature implements AuthorizationFeature {
|
||||
|
||||
Logger log = Logger.getLogger(CreateBitstreamFeature.class);
|
||||
|
||||
public final static String NAME = "canCreateBitstream";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
@Autowired
|
||||
private BundleService bundleService;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof BundleRest) {
|
||||
if (!authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE)) {
|
||||
return false;
|
||||
}
|
||||
if (!authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.ADD)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DSpaceObject owningObject = bundleService.getParentObject(context,
|
||||
(Bundle)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
|
||||
// Safety check. In case this is ever not true, this method should be revised.
|
||||
if (!(owningObject instanceof Item)) {
|
||||
log.error("The parent object of bundle " + object.getType() + " is not an item");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), owningObject,
|
||||
Constants.WRITE, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), owningObject,
|
||||
Constants.ADD, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
BundleRest.CATEGORY + "." + BundleRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The create bundle feature. It can be used to verify if bundles can be created in a specific item.
|
||||
*
|
||||
* Authorization is granted if the current user has ADD & WRITE permissions on the given item
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = CreateBundleFeature.NAME,
|
||||
description = "It can be used to verify if bundles can be created in a specific item")
|
||||
public class CreateBundleFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canCreateBundle";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof ItemRest) {
|
||||
if (!authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE)) {
|
||||
return false;
|
||||
}
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.ADD);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.model.CollectionRest;
|
||||
import org.dspace.app.rest.model.CommunityRest;
|
||||
import org.dspace.app.rest.model.EPersonRest;
|
||||
import org.dspace.app.rest.model.GroupRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.content.factory.ContentServiceFactory;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The delete feature. It can be used to verify if specific content can be deleted/expunged.
|
||||
*
|
||||
* Authorization is granted
|
||||
* - for a bitstream if the current used has REMOVE permissions on both the Item and the Bundle
|
||||
* - for a bundle if the current user has REMOVE permissions on the Item
|
||||
* - for an item if the current user has REMOVE permissions on the collection AND and DELETE permissions on the item
|
||||
* - for a collection if the current user has REMOVE permissions on the community
|
||||
* - for a community with a parent community if the current user has REMOVE permissions on the parent community
|
||||
* - for a community without a parent community if the current user has DELETE permissions on the current community
|
||||
* - for other objects if the current user has REMOVE permissions on the parent object if there is one. Otherwise if the
|
||||
* current user has DELETE permissions on the current object
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = DeleteFeature.NAME,
|
||||
description = "It can be used to verify if specific content can be deleted/expunged")
|
||||
public class DeleteFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canDelete";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
@Autowired
|
||||
private ContentServiceFactory contentServiceFactory;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof BaseObjectRest) {
|
||||
if (object.getType().equals(WorkspaceItemRest.NAME)) {
|
||||
object = ((WorkspaceItemRest)object).getItem();
|
||||
}
|
||||
|
||||
DSpaceObject dSpaceObject = (DSpaceObject) utils.getDSpaceAPIObjectFromRest(context, object);
|
||||
DSpaceObject parentObject = getParentObject(context, dSpaceObject);
|
||||
|
||||
switch (object.getType()) {
|
||||
case BitstreamRest.NAME:
|
||||
return (
|
||||
authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), parentObject,
|
||||
Constants.REMOVE, true)
|
||||
&& authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), dSpaceObject,
|
||||
Constants.REMOVE, true)
|
||||
);
|
||||
case ItemRest.NAME:
|
||||
return (
|
||||
authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), parentObject,
|
||||
Constants.REMOVE, true)
|
||||
&& authorizeServiceRestUtil.authorizeActionBoolean(context, object,
|
||||
DSpaceRestPermission.DELETE)
|
||||
);
|
||||
case CollectionRest.NAME:
|
||||
case CommunityRest.NAME:
|
||||
case BundleRest.NAME:
|
||||
case WorkspaceItemRest.NAME:
|
||||
case EPersonRest.NAME:
|
||||
case GroupRest.NAME:
|
||||
default:
|
||||
if (parentObject != null) {
|
||||
return authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), parentObject,
|
||||
Constants.REMOVE, true);
|
||||
}
|
||||
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object,
|
||||
DSpaceRestPermission.DELETE);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private DSpaceObject getParentObject(Context context, DSpaceObject object) throws SQLException {
|
||||
DSpaceObject parentObject
|
||||
= contentServiceFactory.getDSpaceObjectService(object.getType()).getParentObject(context, object);
|
||||
if (object.getType() == Constants.ITEM && parentObject == null) {
|
||||
Item item = (Item) object;
|
||||
parentObject = item.getOwningCollection();
|
||||
WorkspaceItem byItem = ContentServiceFactory.getInstance()
|
||||
.getWorkspaceItemService()
|
||||
.findByItem(context, item);
|
||||
if (byItem != null) {
|
||||
parentObject = byItem.getCollection();
|
||||
}
|
||||
}
|
||||
return parentObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
CommunityRest.CATEGORY + "." + CommunityRest.NAME,
|
||||
CollectionRest.CATEGORY + "." + CollectionRest.NAME,
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME,
|
||||
BundleRest.CATEGORY + "." + BundleRest.NAME,
|
||||
BitstreamRest.CATEGORY + "." + BitstreamRest.NAME,
|
||||
WorkspaceItemRest.CATEGORY + "." + WorkspaceItemRest.NAME,
|
||||
EPersonRest.CATEGORY + "." + EPersonRest.NAME,
|
||||
GroupRest.CATEGORY + "." + GroupRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.model.CollectionRest;
|
||||
import org.dspace.app.rest.model.CommunityRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The edit metadata feature. It can be used to verify if the metadata of the specified objects can be edited.
|
||||
*
|
||||
* Authorization is granted if the current user has WRITE permissions on the given DSO
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = EditMetadataFeature.NAME,
|
||||
description = "It can be used to verify if the metadata of the specified objects can be edited")
|
||||
public class EditMetadataFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canEditMetadata";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof CommunityRest
|
||||
|| object instanceof CollectionRest
|
||||
|| object instanceof ItemRest
|
||||
|| object instanceof BundleRest
|
||||
|| object instanceof BitstreamRest
|
||||
|| object instanceof SiteRest
|
||||
) {
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
CommunityRest.CATEGORY + "." + CommunityRest.NAME,
|
||||
CollectionRest.CATEGORY + "." + CollectionRest.NAME,
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME,
|
||||
BundleRest.CATEGORY + "." + BundleRest.NAME,
|
||||
BitstreamRest.CATEGORY + "." + BitstreamRest.NAME,
|
||||
SiteRest.CATEGORY + "." + SiteRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The make discoverable feature. It can be used to verify if an item can be made discoverable.
|
||||
*
|
||||
* Authorization is granted if the current user has WRITE permissions on the given item
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = MakeDiscoverableFeature.NAME,
|
||||
description = "It can be used to verify if an item can be made discoverable")
|
||||
public class MakeDiscoverableFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canMakeDiscoverable";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof ItemRest) {
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The make private feature. It can be used to verify if an item can be made private.
|
||||
*
|
||||
* Authorization is granted if the current user has WRITE permissions on the given item
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = MakePrivateFeature.NAME,
|
||||
description = "It can be used to verify if an item can be made private")
|
||||
public class MakePrivateFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canMakePrivate";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof ItemRest) {
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.service.ItemService;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The move feature. It can be used to verify if item can be moved to a different collection.
|
||||
*
|
||||
* Authorization is granted if the current user has WRITE permissions on the given item and REMOVE permissions on the
|
||||
* item’s owning collection
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = MoveFeature.NAME,
|
||||
description = "It can be used to verify if item can be moved to a different collection")
|
||||
public class MoveFeature implements AuthorizationFeature {
|
||||
|
||||
Logger log = Logger.getLogger(MoveFeature.class);
|
||||
|
||||
public final static String NAME = "canMove";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
@Autowired
|
||||
private ItemService itemService;
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof ItemRest) {
|
||||
if (!authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DSpaceObject owningObject = itemService.getParentObject(context,
|
||||
(Item)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
|
||||
if (!(owningObject instanceof Collection)) {
|
||||
log.error("The partent object of item " + object.getType() + " is not a collection");
|
||||
return false;
|
||||
}
|
||||
|
||||
return authorizeService.authorizeActionBoolean(context, context.getCurrentUser(), owningObject,
|
||||
Constants.REMOVE, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.model.CollectionRest;
|
||||
import org.dspace.app.rest.model.CommunityRest;
|
||||
import org.dspace.app.rest.model.ItemRest;
|
||||
import org.dspace.app.rest.model.SiteRest;
|
||||
import org.dspace.app.rest.utils.Utils;
|
||||
import org.dspace.app.util.AuthorizeUtil;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.Bundle;
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.Community;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The policy feature. It can be used by administrators (or community/collection delegate) to manage resource policies
|
||||
*
|
||||
* Authorization is granted
|
||||
* - for the site if the current user is administrator
|
||||
* - for other objects if the current user has ADMIN permissions on the object
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = PolicyFeature.NAME,
|
||||
description = "It can be used to verify if the resourcepolicies of the specified objects can be managed")
|
||||
public class PolicyFeature implements AuthorizationFeature {
|
||||
|
||||
public static final String NAME = "canManagePolicies";
|
||||
|
||||
@Autowired
|
||||
AuthorizeService authService;
|
||||
@Autowired
|
||||
private Utils utils;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object != null) {
|
||||
try {
|
||||
if (object instanceof SiteRest) {
|
||||
return authService.isAdmin(context);
|
||||
}
|
||||
if (object instanceof CommunityRest) {
|
||||
AuthorizeUtil.authorizeManageCommunityPolicy(context,
|
||||
(Community)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
return true;
|
||||
}
|
||||
if (object instanceof CollectionRest) {
|
||||
AuthorizeUtil.authorizeManageCollectionPolicy(context,
|
||||
(Collection) utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
return true;
|
||||
}
|
||||
if (object instanceof ItemRest) {
|
||||
AuthorizeUtil.authorizeManageItemPolicy(context,
|
||||
(Item)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
return true;
|
||||
}
|
||||
if (object instanceof BundleRest) {
|
||||
AuthorizeUtil.authorizeManageBundlePolicy(context,
|
||||
(Bundle)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
return true;
|
||||
}
|
||||
if (object instanceof BitstreamRest) {
|
||||
AuthorizeUtil.authorizeManageBitstreamPolicy(context,
|
||||
(Bitstream)utils.getDSpaceAPIObjectFromRest(context, object));
|
||||
return true;
|
||||
}
|
||||
} catch (AuthorizeException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
SiteRest.CATEGORY + "." + SiteRest.NAME,
|
||||
CommunityRest.CATEGORY + "." + CommunityRest.NAME,
|
||||
CollectionRest.CATEGORY + "." + CollectionRest.NAME,
|
||||
ItemRest.CATEGORY + "." + ItemRest.NAME,
|
||||
BundleRest.CATEGORY + "." + BundleRest.NAME,
|
||||
BitstreamRest.CATEGORY + "." + BitstreamRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* The contents of this file are subject to the license and copyright
|
||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||
* tree and available online at
|
||||
*
|
||||
* http://www.dspace.org/license/
|
||||
*/
|
||||
package org.dspace.app.rest.authorization.impl;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeature;
|
||||
import org.dspace.app.rest.authorization.AuthorizationFeatureDocumentation;
|
||||
import org.dspace.app.rest.authorization.AuthorizeServiceRestUtil;
|
||||
import org.dspace.app.rest.model.BaseObjectRest;
|
||||
import org.dspace.app.rest.model.BundleRest;
|
||||
import org.dspace.app.rest.security.DSpaceRestPermission;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* The reorder bitstream feature. It can be used to verify if bitstreams can be reordered in a specific bundle.
|
||||
*
|
||||
* Authorization is granted if the current user has WRITE permissions on the given bundle
|
||||
*/
|
||||
@Component
|
||||
@AuthorizationFeatureDocumentation(name = ReorderBitstreamFeature.NAME,
|
||||
description = "It can be used to verify if bitstreams can be reordered in a specific bundle")
|
||||
public class ReorderBitstreamFeature implements AuthorizationFeature {
|
||||
|
||||
public final static String NAME = "canReorderBitstreams";
|
||||
|
||||
@Autowired
|
||||
private AuthorizeServiceRestUtil authorizeServiceRestUtil;
|
||||
|
||||
@Override
|
||||
public boolean isAuthorized(Context context, BaseObjectRest object) throws SQLException {
|
||||
if (object instanceof BundleRest) {
|
||||
return authorizeServiceRestUtil.authorizeActionBoolean(context, object, DSpaceRestPermission.WRITE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedTypes() {
|
||||
return new String[]{
|
||||
BundleRest.CATEGORY + "." + BundleRest.NAME
|
||||
};
|
||||
}
|
||||
}
|
@@ -9,11 +9,17 @@ package org.dspace.app.rest.repository;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.app.rest.Parameter;
|
||||
import org.dspace.app.rest.SearchRestMethod;
|
||||
import org.dspace.app.rest.converter.ConverterService;
|
||||
import org.dspace.app.rest.exception.DSpaceBadRequestException;
|
||||
import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
|
||||
import org.dspace.app.rest.model.BitstreamRest;
|
||||
import org.dspace.app.rest.model.ProcessRest;
|
||||
@@ -21,12 +27,18 @@ import org.dspace.app.rest.projection.Projection;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.service.AuthorizeService;
|
||||
import org.dspace.content.Bitstream;
|
||||
import org.dspace.content.ProcessStatus;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.service.EPersonService;
|
||||
import org.dspace.scripts.Process;
|
||||
import org.dspace.scripts.ProcessQueryParameterContainer;
|
||||
import org.dspace.scripts.Process_;
|
||||
import org.dspace.scripts.service.ProcessService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -49,6 +61,9 @@ public class ProcessRestRepository extends DSpaceRestRepository<ProcessRest, Int
|
||||
@Autowired
|
||||
private AuthorizeService authorizeService;
|
||||
|
||||
@Autowired
|
||||
private EPersonService epersonService;
|
||||
|
||||
|
||||
@Override
|
||||
@PreAuthorize("hasPermission(#id, 'PROCESS', 'READ')")
|
||||
@@ -135,6 +150,104 @@ public class ProcessRestRepository extends DSpaceRestRepository<ProcessRest, Int
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search method that will take Parameters and return a list of {@link ProcessRest} objects
|
||||
* based on the {@link Process} objects that were in the databank that adhere to these params
|
||||
* @param ePersonUuid The UUID for the EPerson that started the Process
|
||||
* @param scriptName The name of the Script for which the Process belongs to
|
||||
* @param processStatusString The status of the Process
|
||||
* @param pageable The pageable
|
||||
* @return A page of {@link ProcessRest} objects adhering to the params
|
||||
* @throws SQLException If something goes wrong
|
||||
*/
|
||||
@SearchRestMethod(name = "byProperty")
|
||||
@PreAuthorize("hasAuthority('ADMIN')")
|
||||
public Page<ProcessRest> findProcessesByProperty(@Parameter(value = "userId") UUID ePersonUuid,
|
||||
@Parameter(value = "scriptName") String scriptName,
|
||||
@Parameter(value = "processStatus") String processStatusString,
|
||||
Pageable pageable)
|
||||
throws SQLException {
|
||||
if (StringUtils.isBlank(scriptName) && ePersonUuid == null && StringUtils.isBlank(processStatusString)) {
|
||||
throw new DSpaceBadRequestException("Either a name, user UUID or ProcessStatus should be provided");
|
||||
}
|
||||
|
||||
Context context = obtainContext();
|
||||
EPerson ePerson = null;
|
||||
if (ePersonUuid != null) {
|
||||
ePerson = epersonService.find(context, ePersonUuid);
|
||||
if (ePerson == null) {
|
||||
throw new DSpaceBadRequestException("No EPerson with the given UUID is found");
|
||||
}
|
||||
}
|
||||
|
||||
ProcessStatus processStatus = StringUtils.isBlank(processStatusString) ? null :
|
||||
ProcessStatus.valueOf(processStatusString);
|
||||
ProcessQueryParameterContainer processQueryParameterContainer = createProcessQueryParameterContainer(scriptName,
|
||||
ePerson, processStatus);
|
||||
handleSearchSort(pageable, processQueryParameterContainer);
|
||||
List<Process> processes = processService.search(context, processQueryParameterContainer, pageable.getPageSize(),
|
||||
Math.toIntExact(pageable.getOffset()));
|
||||
return converterService.toRestPage(processes, pageable,
|
||||
processService.countSearch(context, processQueryParameterContainer),
|
||||
utils.obtainProjection());
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will retrieve the {@link Sort} from the given {@link Pageable} and it'll create the sortOrder and
|
||||
* sortProperty Strings on the {@link ProcessQueryParameterContainer} object so that we can store how the sorting
|
||||
* should be done
|
||||
* @param pageable The pageable object
|
||||
* @param processQueryParameterContainer The object in which the sorting will be filled in
|
||||
*/
|
||||
private void handleSearchSort(Pageable pageable, ProcessQueryParameterContainer processQueryParameterContainer) {
|
||||
Sort sort = pageable.getSort();
|
||||
if (sort != null) {
|
||||
Iterator<Sort.Order> iterator = sort.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
Sort.Order order = iterator.next();
|
||||
if (StringUtils.equalsIgnoreCase(order.getProperty(), "startTime")) {
|
||||
processQueryParameterContainer.setSortProperty(Process_.START_TIME);
|
||||
processQueryParameterContainer.setSortOrder(order.getDirection().name());
|
||||
} else if (StringUtils.equalsIgnoreCase(order.getProperty(), "endTime")) {
|
||||
processQueryParameterContainer.setSortProperty(Process_.FINISHED_TIME);
|
||||
processQueryParameterContainer.setSortOrder(order.getDirection().name());
|
||||
} else {
|
||||
throw new DSpaceBadRequestException("The given sort option was invalid: " + order.getProperty());
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
throw new DSpaceBadRequestException("Only one sort method is supported, can't give multiples");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will create a new {@link ProcessQueryParameterContainer} object and return it.
|
||||
* This object will contain a map which is filled in with the database column reference as key and the value that
|
||||
* it should contain when searching as the value of the entry
|
||||
* @param scriptName The name that the script of the process should have
|
||||
* @param ePerson The eperson that the process should have
|
||||
* @param processStatus The status that the process should have
|
||||
* @return The newly created {@link ProcessQueryParameterContainer}
|
||||
*/
|
||||
private ProcessQueryParameterContainer createProcessQueryParameterContainer(String scriptName, EPerson ePerson,
|
||||
ProcessStatus processStatus) {
|
||||
ProcessQueryParameterContainer processQueryParameterContainer =
|
||||
new ProcessQueryParameterContainer();
|
||||
if (StringUtils.isNotBlank(scriptName)) {
|
||||
processQueryParameterContainer.addToQueryParameterMap(Process_.NAME, scriptName);
|
||||
}
|
||||
if (ePerson != null) {
|
||||
processQueryParameterContainer.addToQueryParameterMap(Process_.E_PERSON, ePerson);
|
||||
}
|
||||
if (processStatus != null) {
|
||||
processQueryParameterContainer.addToQueryParameterMap(Process_.PROCESS_STATUS, processStatus);
|
||||
}
|
||||
return processQueryParameterContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ProcessRest> getDomainClass() {
|
||||
return ProcessRest.class;
|
||||
|
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
package org.dspace.app.rest;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
@@ -18,6 +19,7 @@ import java.sql.SQLException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.codec.CharEncoding;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
@@ -158,39 +160,40 @@ public class ProcessRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(process.getName(), String.valueOf(process.getEPerson().getID()),
|
||||
process.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess.getName(),
|
||||
String.valueOf(newProcess.getEPerson().getID()),
|
||||
newProcess.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(newProcess1.getEPerson().getID()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(newProcess2.getEPerson().getID()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(newProcess3.getEPerson().getID()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess4.getName(),
|
||||
String.valueOf(newProcess4.getEPerson().getID()),
|
||||
newProcess4.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess5.getName(),
|
||||
String.valueOf(newProcess5.getEPerson().getID()),
|
||||
newProcess5.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess6.getName(),
|
||||
String.valueOf(newProcess6.getEPerson().getID()),
|
||||
newProcess6.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess7.getName(),
|
||||
String.valueOf(newProcess7.getEPerson().getID()),
|
||||
newProcess7.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
// Expect all processes to be returned, newest to oldest
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess9.getName(),
|
||||
String.valueOf(newProcess9.getEPerson().getID()),
|
||||
newProcess9.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess8.getName(),
|
||||
String.valueOf(newProcess8.getEPerson().getID()),
|
||||
newProcess8.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess9.getName(),
|
||||
String.valueOf(newProcess9.getEPerson().getID()),
|
||||
newProcess9.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
ProcessMatcher.matchProcess(newProcess7.getName(),
|
||||
String.valueOf(newProcess7.getEPerson().getID()),
|
||||
newProcess7.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess6.getName(),
|
||||
String.valueOf(newProcess6.getEPerson().getID()),
|
||||
newProcess6.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess5.getName(),
|
||||
String.valueOf(newProcess5.getEPerson().getID()),
|
||||
newProcess5.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess4.getName(),
|
||||
String.valueOf(newProcess4.getEPerson().getID()),
|
||||
newProcess4.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(newProcess3.getEPerson().getID()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(newProcess2.getEPerson().getID()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(newProcess1.getEPerson().getID()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess.getName(),
|
||||
String.valueOf(newProcess.getEPerson().getID()),
|
||||
newProcess.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(process.getName(), String.valueOf(process.getEPerson().getID()),
|
||||
process.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 11))));
|
||||
@@ -323,6 +326,464 @@ public class ProcessRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestForbidden() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty"))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestUnauthorized() throws Exception {
|
||||
|
||||
getClient().perform(get("/api/system/processes/search/byProperty"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUser() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", admin.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(process.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
process.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess7.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess7.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess8.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess8.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess9.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess9.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 4))));
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(newProcess.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess4.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess4.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess5.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess5.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess6.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess6.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 7))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByProcessStatus() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("processStatus", "FAILED"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(newProcess7.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess7.getID(), parameters, ProcessStatus.FAILED),
|
||||
ProcessMatcher.matchProcess(newProcess9.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess9.getID(), parameters, ProcessStatus.FAILED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByScriptName() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("scriptName", "another-mock-script"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(newProcess8.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess8.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 1))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByScriptNameAndUserId() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("scriptName", "another-mock-script")
|
||||
.param("userId", admin.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(newProcess7.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess7.getID(), parameters, ProcessStatus.FAILED),
|
||||
ProcessMatcher.matchProcess(newProcess8.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess8.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserIdAndProcessStatus() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("processStatus", "FAILED")
|
||||
.param("userId", admin.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess(newProcess9.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess9.getID(), parameters, ProcessStatus.FAILED),
|
||||
ProcessMatcher.matchProcess(newProcess8.getName(),
|
||||
String.valueOf(admin.getID().toString()),
|
||||
newProcess8.getID(), parameters, ProcessStatus.FAILED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserIdAndProcessStatusAndScriptName() throws Exception {
|
||||
Process newProcess = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess4 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters).build();
|
||||
Process newProcess5 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess6 = ProcessBuilder.createProcess(context, eperson, "another-mock-script", parameters).build();
|
||||
Process newProcess7 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters).build();
|
||||
Process newProcess8 = ProcessBuilder.createProcess(context, admin, "another-mock-script", parameters)
|
||||
.withProcessStatus(ProcessStatus.FAILED).build();
|
||||
Process newProcess9 = ProcessBuilder.createProcess(context, admin, "mock-script", parameters).build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("processStatus", "FAILED")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("scriptName", "mock-script"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", containsInAnyOrder(
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.FAILED),
|
||||
ProcessMatcher.matchProcess("mock-script",
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.FAILED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestNoParametersBadRequest() throws Exception {
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void searchProcessTestUnparseableProcessStatusParamBadRequest() throws Exception {
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("processStatus", "not-a-valid-status"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestInvalidEPersonUuid() throws Exception {
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", UUID.randomUUID().toString()))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnStartTimeAsc() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "startTime,asc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnStartTimeDesc() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "startTime,desc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnEndTimeAsc() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "endTime,asc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnEndTimeDesc() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "endTime,desc"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnMultipleBadRequest() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "endTime,desc")
|
||||
.param("sort", "startTime,desc"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnDefault() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString()))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$._embedded.processes", contains(
|
||||
ProcessMatcher.matchProcess(newProcess3.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess3.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess2.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess2.getID(), parameters, ProcessStatus.SCHEDULED),
|
||||
ProcessMatcher.matchProcess(newProcess1.getName(),
|
||||
String.valueOf(eperson.getID().toString()),
|
||||
newProcess1.getID(), parameters, ProcessStatus.SCHEDULED)
|
||||
)))
|
||||
.andExpect(jsonPath("$.page", is(
|
||||
PageMatcher.pageEntryWithTotalPagesAndElements(0, 20, 1, 3))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchProcessTestByUserSortedOnNonExistingIsSortedAsDefault() throws Exception {
|
||||
Process newProcess1 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("10/01/1990", "20/01/1990").build();
|
||||
Process newProcess2 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("11/01/1990", "19/01/1990").build();
|
||||
Process newProcess3 = ProcessBuilder.createProcess(context, eperson, "mock-script", parameters)
|
||||
.withStartAndEndTime("12/01/1990", "18/01/1990").build();
|
||||
|
||||
String token = getAuthToken(admin.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/system/processes/search/byProperty")
|
||||
.param("userId", eperson.getID().toString())
|
||||
.param("sort", "eaz,desc"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProcessOutput() throws Exception {
|
||||
try (InputStream is = IOUtils.toInputStream("Test File For Process", CharEncoding.UTF_8)) {
|
||||
|
@@ -91,7 +91,11 @@ public class ScriptRestRepositoryIT extends AbstractControllerIntegrationTest {
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(3).getName(),
|
||||
scriptConfigurations.get(3).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(4).getName(),
|
||||
scriptConfigurations.get(4).getDescription())
|
||||
scriptConfigurations.get(4).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(5).getName(),
|
||||
scriptConfigurations.get(5).getDescription()),
|
||||
ScriptMatcher.matchScript(scriptConfigurations.get(6).getName(),
|
||||
scriptConfigurations.get(6).getDescription())
|
||||
)));
|
||||
|
||||
}
|
||||
|
@@ -12,7 +12,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Integration test that cover ShibbolethRestController
|
||||
@@ -21,6 +24,17 @@ import org.junit.Test;
|
||||
*/
|
||||
public class ShibbolethRestControllerIT extends AbstractControllerIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
ConfigurationService configurationService;
|
||||
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
super.setUp();
|
||||
configurationService.setProperty("rest.cors.allowed-origins",
|
||||
"${dspace.ui.url}, http://anotherdspacehost:4000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToDefaultDspaceUrl() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
@@ -32,6 +46,7 @@ public class ShibbolethRestControllerIT extends AbstractControllerIntegrationTes
|
||||
|
||||
@Test
|
||||
public void testRedirectToGivenTrustedUrl() throws Exception {
|
||||
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/authn/shibboleth")
|
||||
@@ -40,6 +55,16 @@ public class ShibbolethRestControllerIT extends AbstractControllerIntegrationTes
|
||||
.andExpect(redirectedUrl("http://localhost:8080/server/api/authn/status"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToAnotherGivenTrustedUrl() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
||||
getClient(token).perform(get("/api/authn/shibboleth")
|
||||
.param("redirectUrl", "http://anotherdspacehost:4000/home"))
|
||||
.andExpect(status().is3xxRedirection())
|
||||
.andExpect(redirectedUrl("http://anotherdspacehost:4000/home"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectToGivenUntrustedUrl() throws Exception {
|
||||
String token = getAuthToken(eperson.getEmail(), password);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.statistics.export.service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* Mock OpenUrlService that will ensure that IRUS tracker does need to be contacted in order to test the functionality
|
||||
*/
|
||||
public class MockOpenUrlServiceImpl extends OpenUrlServiceImpl {
|
||||
|
||||
@Autowired
|
||||
ArrayList testProcessedUrls;
|
||||
|
||||
/**
|
||||
* Returns a response code to simulate contact to the external url
|
||||
* When the url contains "fail", a fail code 500 will be returned
|
||||
* Otherwise the success code 200 will be returned
|
||||
* @param urlStr
|
||||
* @return 200 or 500 depending on whether the "fail" keyword is present in the url
|
||||
* @throws IOException
|
||||
*/
|
||||
protected int getResponseCodeFromUrl(final String urlStr) throws IOException {
|
||||
if (StringUtils.contains(urlStr, "fail")) {
|
||||
return HttpURLConnection.HTTP_INTERNAL_ERROR;
|
||||
} else {
|
||||
testProcessedUrls.add(urlStr);
|
||||
return HttpURLConnection.HTTP_OK;
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,21 +18,20 @@
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
||||
See also the 'skiptests' profile in Parent POM. -->
|
||||
<!-- Setup the Unit Test Environment (when -DskipUnitTests=false) -->
|
||||
<profile>
|
||||
<id>test-environment</id>
|
||||
<id>unit-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<name>skipUnitTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
||||
(see: https://groovy.github.io/gmaven/groovy-maven-plugin/execute.html )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire plugin (see below) to
|
||||
@@ -59,21 +58,9 @@
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<!-- TODO: When Groovy 3.0.0 is released, we should upgrade to fix this warning
|
||||
(which appears in Maven builds) https://issues.apache.org/jira/browse/GROOVY-8339
|
||||
The below (commented out) dependency should let us upgrade to v3.0.0 once released. -->
|
||||
<!--<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<scope>runtime</scope>
|
||||
<type>pom</type>
|
||||
</dependency>
|
||||
</dependencies>-->
|
||||
</plugin>
|
||||
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<!-- Run Unit Testing! This plugin just kicks off the tests. -->
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
|
@@ -21,7 +21,8 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
public interface ServiceManager {
|
||||
|
||||
/**
|
||||
* Get the application context
|
||||
* Get the application context.
|
||||
* @return the Spring application context.
|
||||
*/
|
||||
public ConfigurableApplicationContext getApplicationContext();
|
||||
|
||||
@@ -46,18 +47,14 @@ public interface ServiceManager {
|
||||
* service manager objects. If using Spring this allows access to the
|
||||
* underlying ApplicationContext object like so:<br>
|
||||
* {@code getServiceByName(ApplicationContext.class.getName(), ApplicationContext.class);}
|
||||
* If using Guice then the same applies like so:<br>
|
||||
* {@code getServiceByName(Injector.class.getName(), Injector.class);}
|
||||
* It is also possible to register a module and cause Guice to fill
|
||||
* in any injected core services (see register method).
|
||||
* </p>
|
||||
*
|
||||
* @param <T> Class type
|
||||
* @param <T> Class type.
|
||||
* @param name (optional) the unique name for this service.
|
||||
* If null then the bean will be returned if there is only one
|
||||
* service of this type.
|
||||
* @param type the type for the requested service (this will typically be the interface class but can be concrete
|
||||
* as well)
|
||||
* @param type the type for the requested service (this will typically be
|
||||
* the interface class but can be concrete as well).
|
||||
* @return the service singleton OR null if none is found
|
||||
*/
|
||||
public <T> T getServiceByName(String name, Class<T> type);
|
||||
@@ -90,12 +87,6 @@ public interface ServiceManager {
|
||||
* down the context (webapp, etc.) that registered the service so
|
||||
* that the full lifecycle completes correctly.
|
||||
* </p>
|
||||
* <p>
|
||||
* <em>NOTE:</em> if using Guice it is possible to register a Guice
|
||||
* Module as a service, which will not actually register it but will
|
||||
* cause anything in the Module to have existing core services injected
|
||||
* into it. You can use anything as the name in this case.
|
||||
* </p>
|
||||
*
|
||||
* @param name the name of the service (must be unique)
|
||||
* @param service the object to register as a singleton service
|
||||
@@ -103,6 +94,14 @@ public interface ServiceManager {
|
||||
*/
|
||||
public void registerService(String name, Object service);
|
||||
|
||||
/**
|
||||
* Add a singleton service at runtime, but do not inject dependencies.
|
||||
* Typically used with a service instance that has already had all
|
||||
* dependencies injected explicitly, for example in test code.
|
||||
*
|
||||
* @param name the name of the service (must be unique).
|
||||
* @param service the instance to register as a singleton service.
|
||||
*/
|
||||
public void registerServiceNoAutowire(String name, Object service);
|
||||
|
||||
/**
|
||||
@@ -112,7 +111,7 @@ public interface ServiceManager {
|
||||
* except that it allows the core service manager to startup your
|
||||
* service for you instead of you providing a service to the core.
|
||||
* In general, it is better if you use your own service manager
|
||||
* (like Spring or Guice) to manage your services and simply
|
||||
* (like Spring) to manage your services and simply
|
||||
* inherit the core service beans from the DSpace core service
|
||||
* manager using the special capabilities of
|
||||
* {@link #getServiceByName(String, Class)}.
|
||||
|
@@ -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.kernel.mixins;
|
||||
|
||||
/**
|
||||
* Allow the service or provider to be initialized when it is started
|
||||
* by the service manager. After all injections are complete the init
|
||||
* method will be called. Any initialization that a service needs to do
|
||||
* should happen here.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public interface InitializedService {
|
||||
|
||||
/**
|
||||
* Executed after the service is created and all dependencies and
|
||||
* configurations injected.
|
||||
*/
|
||||
public void init();
|
||||
|
||||
}
|
@@ -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.kernel.mixins;
|
||||
|
||||
|
||||
/**
|
||||
* Allow the service to be notified when the service manager is shutting
|
||||
* it down. This will typically be called when the kernel is stopped or
|
||||
* destroyed. Any cleanup that a service needs to do when it is
|
||||
* shut down should happen here.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public interface ShutdownService {
|
||||
|
||||
/**
|
||||
* Called as the service manager is stopping or shutting down.
|
||||
*/
|
||||
public void shutdown();
|
||||
|
||||
}
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.servicemanager;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -17,23 +18,19 @@ import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.dspace.kernel.Activator;
|
||||
import org.dspace.kernel.config.SpringLoader;
|
||||
import org.dspace.kernel.mixins.ConfigChangeListener;
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ServiceChangeListener;
|
||||
import org.dspace.kernel.mixins.ServiceManagerReadyAware;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.servicemanager.config.DSpaceConfigurationService;
|
||||
import org.dspace.servicemanager.spring.DSpaceBeanFactoryPostProcessor;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
@@ -374,7 +371,18 @@ public final class DSpaceServiceManager implements ServiceManagerSystem {
|
||||
applicationContext.getBeanFactory().destroyBean(name, beanInstance);
|
||||
} catch (NoSuchBeanDefinitionException e) {
|
||||
// this happens if the bean was registered manually (annoyingly)
|
||||
DSpaceServiceManager.shutdownService(beanInstance);
|
||||
for (final Method method : beanInstance.getClass().getMethods()) {
|
||||
if (method.isAnnotationPresent(PreDestroy.class)) {
|
||||
try {
|
||||
method.invoke(beanInstance);
|
||||
} catch (IllegalAccessException
|
||||
| IllegalArgumentException
|
||||
| InvocationTargetException ex) {
|
||||
log.warn("Failed to call declared @PreDestroy method of {} service",
|
||||
name, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (BeansException e) {
|
||||
// nothing to do here, could not find the bean
|
||||
@@ -578,79 +586,6 @@ public final class DSpaceServiceManager implements ServiceManagerSystem {
|
||||
|
||||
// STATICS
|
||||
|
||||
/**
|
||||
* Configures a given service (i.e. bean) based on any DSpace configuration
|
||||
* settings which refer to it by name. .
|
||||
* <P>
|
||||
* NOTE: Any configurations related to a specific service MUST be prefixed
|
||||
* with the given service's name (e.g. [serviceName].setting = value)
|
||||
* <P>
|
||||
* This method logs an error if it encounters configs which refer to a
|
||||
* service by name, but is an invalid setting for that service.
|
||||
*
|
||||
* @param serviceName the name of the service
|
||||
* @param service the service object (which will be configured)
|
||||
* @param config the running configuration service
|
||||
*/
|
||||
public static void configureService(String serviceName, Object service, ConfigurationService config) {
|
||||
|
||||
// Check if the configuration has any properties whose prefix
|
||||
// corresponds to this service's name
|
||||
List<String> configKeys = config.getPropertyKeys(serviceName);
|
||||
if (configKeys != null && !configKeys.isEmpty()) {
|
||||
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(service);
|
||||
for (String key : configKeys) {
|
||||
// Remove serviceName prefix from key. This is the name of the actual bean's parameter
|
||||
// This removes the first x chars, where x is length of serviceName + 1 char
|
||||
// Format of Key: [serviceName].[param]
|
||||
String param = key.substring(serviceName.length() + 1);
|
||||
|
||||
try {
|
||||
// Attempt to set this configuration on the given service's bean
|
||||
beanWrapper.setPropertyValue(param, config.getProperty(key));
|
||||
log.info("Set param (" + param + ") on service bean (" + serviceName + ") to: " + config
|
||||
.getProperty(key));
|
||||
} catch (RuntimeException e) {
|
||||
// If an error occurs, just log it
|
||||
log.error("Unable to set param (" + param + ") on service bean (" + serviceName + ") to: " + config
|
||||
.getProperty(key), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a service if it asks to be initialized or does nothing.
|
||||
*
|
||||
* @param service any bean
|
||||
* @throws IllegalStateException if the service init fails
|
||||
*/
|
||||
public static void initService(Object service) {
|
||||
if (service instanceof InitializedService) {
|
||||
try {
|
||||
((InitializedService) service).init();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Failure attempting to initialize service (" + service + "): " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down a service if it asks to be shutdown or does nothing.
|
||||
*
|
||||
* @param service any bean
|
||||
*/
|
||||
public static void shutdownService(Object service) {
|
||||
if (service instanceof ShutdownService) {
|
||||
try {
|
||||
((ShutdownService) service).shutdown();
|
||||
} catch (Exception e) {
|
||||
log.error("Failure shutting down service: {}", service, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the complete list of Spring configuration paths, including
|
||||
* hard-wired paths.
|
||||
@@ -702,5 +637,4 @@ public final class DSpaceServiceManager implements ServiceManagerSystem {
|
||||
}
|
||||
return pathList.toArray(new String[pathList.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,72 +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.servicemanager.spring;
|
||||
|
||||
import org.dspace.servicemanager.DSpaceServiceManager;
|
||||
import org.dspace.servicemanager.config.DSpaceConfigurationService;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
|
||||
|
||||
/**
|
||||
* This processes beans as they are loaded into the system by spring.
|
||||
* Allows us to handle the init method and also push config options.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public final class DSpaceBeanPostProcessor implements BeanPostProcessor, DestructionAwareBeanPostProcessor {
|
||||
|
||||
private DSpaceConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
public DSpaceBeanPostProcessor(DSpaceConfigurationService configurationService) {
|
||||
if (configurationService == null) {
|
||||
throw new IllegalArgumentException("configuration service cannot be null");
|
||||
}
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang
|
||||
* .Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
// Before initializing the service, first configure it based on any related settings in the configurationService
|
||||
// NOTE: configs related to this bean MUST be prefixed with the bean's name (e.g. [beanName].setting = value)
|
||||
DSpaceServiceManager.configureService(beanName, bean, configurationService);
|
||||
return bean;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang
|
||||
* .Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
DSpaceServiceManager.initService(bean);
|
||||
return bean;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor#postProcessBeforeDestruction
|
||||
* (java.lang.Object, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
|
||||
DSpaceServiceManager.shutdownService(bean);
|
||||
}
|
||||
|
||||
// @Override
|
||||
public boolean requiresDestruction(Object arg0) {
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -16,14 +16,14 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import net.sf.ehcache.Ehcache;
|
||||
import net.sf.ehcache.Statistics;
|
||||
import org.dspace.kernel.ServiceManager;
|
||||
import org.dspace.kernel.mixins.ConfigChangeListener;
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ServiceChangeListener;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.providers.CacheProvider;
|
||||
import org.dspace.services.CachingService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
@@ -38,7 +38,6 @@ import org.dspace.utils.servicemanager.ProviderHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
* Implementation of the core caching service, which is available for
|
||||
@@ -47,16 +46,16 @@ import org.springframework.beans.factory.annotation.Required;
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public final class CachingServiceImpl
|
||||
implements CachingService, InitializedService, ShutdownService, ConfigChangeListener, ServiceChangeListener {
|
||||
implements CachingService, ConfigChangeListener, ServiceChangeListener {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(CachingServiceImpl.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(CachingServiceImpl.class);
|
||||
|
||||
/**
|
||||
* This is the event key for a full cache reset.
|
||||
*/
|
||||
protected static final String EVENT_RESET = "caching.reset";
|
||||
/**
|
||||
* The default config location.
|
||||
* The default configuration location.
|
||||
*/
|
||||
protected static final String DEFAULT_CONFIG = "org/dspace/services/caching/ehcache-config.xml";
|
||||
|
||||
@@ -64,15 +63,14 @@ public final class CachingServiceImpl
|
||||
* All the non-thread caches that we know about.
|
||||
* Mostly used for tracking purposes.
|
||||
*/
|
||||
private Map<String, EhcacheCache> cacheRecord = new ConcurrentHashMap<String, EhcacheCache>();
|
||||
private final Map<String, EhcacheCache> cacheRecord = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* All the request caches. This is bound to the thread.
|
||||
* The initial value of this TL is set automatically when it is
|
||||
* created.
|
||||
*/
|
||||
private Map<String, Map<String, MapCache>> requestCachesMap = new ConcurrentHashMap<String, Map<String,
|
||||
MapCache>>();
|
||||
private final Map<String, Map<String, MapCache>> requestCachesMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* @return the current request map which is bound to the current thread
|
||||
@@ -84,7 +82,7 @@ public final class CachingServiceImpl
|
||||
|
||||
Map<String, MapCache> requestCaches = requestCachesMap.get(requestService.getCurrentRequestId());
|
||||
if (requestCaches == null) {
|
||||
requestCaches = new HashMap<String, MapCache>();
|
||||
requestCaches = new HashMap<>();
|
||||
requestCachesMap.put(requestService.getCurrentRequestId(), requestCaches);
|
||||
}
|
||||
|
||||
@@ -94,6 +92,7 @@ public final class CachingServiceImpl
|
||||
/**
|
||||
* Unbinds all request caches. Destroys the caches completely.
|
||||
*/
|
||||
@Override
|
||||
public void unbindRequestCaches() {
|
||||
if (requestService != null) {
|
||||
requestCachesMap.remove(requestService.getCurrentRequestId());
|
||||
@@ -102,8 +101,7 @@ public final class CachingServiceImpl
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
@@ -117,8 +115,7 @@ public final class CachingServiceImpl
|
||||
|
||||
private ServiceManager serviceManager;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setServiceManager(ServiceManager serviceManager) {
|
||||
this.serviceManager = serviceManager;
|
||||
}
|
||||
@@ -128,8 +125,7 @@ public final class CachingServiceImpl
|
||||
*/
|
||||
protected net.sf.ehcache.CacheManager cacheManager;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) {
|
||||
this.cacheManager = cacheManager;
|
||||
}
|
||||
@@ -145,7 +141,7 @@ public final class CachingServiceImpl
|
||||
private int timeToIdleSecs = 600;
|
||||
|
||||
/**
|
||||
* Reloads the config settings from the configuration service.
|
||||
* Reloads the configuration settings from the configuration service.
|
||||
*/
|
||||
protected void reloadConfig() {
|
||||
// Reload caching configurations, but have sane default values if unspecified in configs
|
||||
@@ -160,7 +156,7 @@ public final class CachingServiceImpl
|
||||
* WARNING: Do not change the order of these! <br/>
|
||||
* If you do, you have to fix the {@link #reloadConfig()} method -AZ
|
||||
*/
|
||||
private String[] knownConfigNames = {
|
||||
private final String[] knownConfigNames = {
|
||||
"caching.use.clustering", // bool - whether to use clustering
|
||||
"caching.default.use.disk.store", // whether to use the disk store
|
||||
"caching.default.max.elements", // the maximum number of elements in memory, before they are evicted
|
||||
@@ -172,13 +168,15 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ConfigChangeListener#notifyForConfigNames()
|
||||
*/
|
||||
@Override
|
||||
public String[] notifyForConfigNames() {
|
||||
return knownConfigNames == null ? null : knownConfigNames.clone();
|
||||
return knownConfigNames.clone();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ConfigChangeListener#configurationChanged(java.util.List, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void configurationChanged(List<String> changedSettingNames, Map<String, String> changedSettings) {
|
||||
reloadConfig();
|
||||
}
|
||||
@@ -187,7 +185,7 @@ public final class CachingServiceImpl
|
||||
* This will make it easier to handle a provider which might go away
|
||||
* because the classloader is gone.
|
||||
*/
|
||||
private ProviderHolder<CacheProvider> provider = new ProviderHolder<CacheProvider>();
|
||||
private final ProviderHolder<CacheProvider> provider = new ProviderHolder<>();
|
||||
|
||||
public CacheProvider getCacheProvider() {
|
||||
return provider.getProvider();
|
||||
@@ -211,6 +209,7 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#notifyForTypes()
|
||||
*/
|
||||
@Override
|
||||
public Class<?>[] notifyForTypes() {
|
||||
return new Class<?>[] {CacheProvider.class};
|
||||
}
|
||||
@@ -219,6 +218,7 @@ public final class CachingServiceImpl
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceRegistered(java.lang.String, java.lang.Object, java
|
||||
* .util.List)
|
||||
*/
|
||||
@Override
|
||||
public void serviceRegistered(String serviceName, Object service, List<Class<?>> implementedTypes) {
|
||||
provider.setProvider((CacheProvider) service);
|
||||
}
|
||||
@@ -226,14 +226,12 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceUnregistered(java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void serviceUnregistered(String serviceName, Object service) {
|
||||
provider.setProvider(null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.InitializedService#init()
|
||||
*/
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
log.info("init()");
|
||||
// get settings
|
||||
@@ -256,17 +254,13 @@ public final class CachingServiceImpl
|
||||
log.info("Caching service initialized:\n" + getStatus(null));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
|
||||
*/
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
log.info("destroy()");
|
||||
// for some reason this causes lots of errors so not using it for now -AZ
|
||||
//ehCacheManagementService.dispose();
|
||||
try {
|
||||
if (cacheRecord != null) {
|
||||
cacheRecord.clear();
|
||||
}
|
||||
cacheRecord.clear();
|
||||
} catch (RuntimeException e) {
|
||||
// whatever
|
||||
}
|
||||
@@ -290,6 +284,7 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.CachingService#destroyCache(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void destroyCache(String cacheName) {
|
||||
if (cacheName == null || "".equals(cacheName)) {
|
||||
throw new IllegalArgumentException("cacheName cannot be null or empty string");
|
||||
@@ -319,6 +314,7 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.CachingService#getCache(java.lang.String, org.dspace.services.model.CacheConfig)
|
||||
*/
|
||||
@Override
|
||||
public Cache getCache(String cacheName, CacheConfig cacheConfig) {
|
||||
Cache cache = null;
|
||||
|
||||
@@ -359,8 +355,9 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.CachingService#getCaches()
|
||||
*/
|
||||
@Override
|
||||
public List<Cache> getCaches() {
|
||||
List<Cache> caches = new ArrayList<Cache>(this.cacheRecord.values());
|
||||
List<Cache> caches = new ArrayList<>(this.cacheRecord.values());
|
||||
if (getCacheProvider() != null) {
|
||||
try {
|
||||
caches.addAll(getCacheProvider().getCaches());
|
||||
@@ -377,6 +374,7 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.CachingService#getStatus(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getStatus(String cacheName) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -433,6 +431,7 @@ public final class CachingServiceImpl
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.CachingService#resetCaches()
|
||||
*/
|
||||
@Override
|
||||
public void resetCaches() {
|
||||
log.debug("resetCaches()");
|
||||
|
||||
@@ -468,7 +467,7 @@ public final class CachingServiceImpl
|
||||
if (sorted) {
|
||||
Arrays.sort(cacheNames);
|
||||
}
|
||||
final List<Ehcache> caches = new ArrayList<Ehcache>(cacheNames.length);
|
||||
final List<Ehcache> caches = new ArrayList<>(cacheNames.length);
|
||||
for (String cacheName : cacheNames) {
|
||||
caches.add(cacheManager.getEhcache(cacheName));
|
||||
}
|
||||
@@ -612,6 +611,7 @@ public final class CachingServiceImpl
|
||||
public static final class NameComparator implements Comparator<Cache>, Serializable {
|
||||
public static final long serialVersionUID = 1l;
|
||||
|
||||
@Override
|
||||
public int compare(Cache o1, Cache o2) {
|
||||
return o1.getName().compareTo(o2.getName());
|
||||
}
|
||||
@@ -619,22 +619,25 @@ public final class CachingServiceImpl
|
||||
|
||||
private class CachingServiceRequestInterceptor implements RequestInterceptor {
|
||||
|
||||
@Override
|
||||
public void onStart(String requestId) {
|
||||
if (requestId != null) {
|
||||
Map<String, MapCache> requestCaches = requestCachesMap.get(requestId);
|
||||
if (requestCaches == null) {
|
||||
requestCaches = new HashMap<String, MapCache>();
|
||||
requestCaches = new HashMap<>();
|
||||
requestCachesMap.put(requestId, requestCaches);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(String requestId, boolean succeeded, Exception failure) {
|
||||
if (requestId != null) {
|
||||
requestCachesMap.remove(requestId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 1;
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.services.email;
|
||||
|
||||
import java.util.Properties;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.PasswordAuthentication;
|
||||
import javax.mail.Session;
|
||||
@@ -17,14 +18,12 @@ import javax.naming.NamingException;
|
||||
import javax.naming.NoInitialContextException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.EmailService;
|
||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
* Provides mail sending services through JavaMail. If a {@link javax.mail.Session}
|
||||
@@ -35,7 +34,7 @@ import org.springframework.beans.factory.annotation.Required;
|
||||
*/
|
||||
public class EmailServiceImpl
|
||||
extends Authenticator
|
||||
implements EmailService, InitializedService {
|
||||
implements EmailService {
|
||||
private static final Logger logger = LoggerFactory.getLogger(EmailServiceImpl.class);
|
||||
|
||||
private Session session = null;
|
||||
@@ -47,8 +46,7 @@ public class EmailServiceImpl
|
||||
*
|
||||
* @param cfg the configurationService object
|
||||
*/
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setCfg(ConfigurationService cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
@@ -63,7 +61,7 @@ public class EmailServiceImpl
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// See if there is already a Session in our environment
|
||||
String sessionName = cfg.getProperty("mail.session.name");
|
||||
|
@@ -12,9 +12,9 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.services.CachingService;
|
||||
import org.dspace.services.EventService;
|
||||
import org.dspace.services.RequestService;
|
||||
@@ -36,7 +36,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski@gmail.com) - azeckoski - 4:02:31 PM Nov 19, 2008
|
||||
*/
|
||||
public final class SystemEventService implements EventService, ShutdownService {
|
||||
public final class SystemEventService implements EventService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(SystemEventService.class);
|
||||
|
||||
@@ -45,7 +45,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
/**
|
||||
* Map for holding onto the listeners which is ClassLoader safe.
|
||||
*/
|
||||
private Map<String, EventListener> listenersMap = new ConcurrentHashMap<String, EventListener>();
|
||||
private final Map<String, EventListener> listenersMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final RequestService requestService;
|
||||
private final CachingService cachingService;
|
||||
@@ -64,9 +64,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
this.requestService.registerRequestInterceptor(this.requestInterceptor);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
|
||||
*/
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
this.requestInterceptor = null; // clear the interceptor
|
||||
this.listenersMap.clear();
|
||||
@@ -76,6 +74,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.EventService#fireEvent(org.dspace.services.model.Event)
|
||||
*/
|
||||
@Override
|
||||
public void fireEvent(Event event) {
|
||||
validateEvent(event);
|
||||
// check scopes for this event
|
||||
@@ -97,6 +96,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.EventService#queueEvent(org.dspace.services.model.Event)
|
||||
*/
|
||||
@Override
|
||||
public void queueEvent(Event event) {
|
||||
validateEvent(event);
|
||||
|
||||
@@ -118,6 +118,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.EventService#registerEventListener(org.dspace.services.model.EventListener)
|
||||
*/
|
||||
@Override
|
||||
public void registerEventListener(EventListener listener) {
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("Cannot register a listener that is null");
|
||||
@@ -293,7 +294,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
return allowName && allowResource;
|
||||
}
|
||||
|
||||
private Random random = new Random();
|
||||
private final Random random = new Random();
|
||||
|
||||
/**
|
||||
* Generate an event ID used to identify and track this event uniquely.
|
||||
@@ -316,6 +317,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
* @see org.dspace.services.model.RequestInterceptor#onStart(java.lang.String, org.dspace.services.model
|
||||
* .Session)
|
||||
*/
|
||||
@Override
|
||||
public void onStart(String requestId) {
|
||||
// nothing to really do here unless we decide we should purge out any existing events? -AZ
|
||||
}
|
||||
@@ -324,6 +326,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
* @see org.dspace.services.model.RequestInterceptor#onEnd(java.lang.String, org.dspace.services.model
|
||||
* .Session, boolean, java.lang.Exception)
|
||||
*/
|
||||
@Override
|
||||
public void onEnd(String requestId, boolean succeeded, Exception failure) {
|
||||
if (succeeded) {
|
||||
int fired = fireQueuedEvents();
|
||||
@@ -338,6 +341,7 @@ public final class SystemEventService implements EventService, ShutdownService {
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.OrderedService#getOrder()
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 20; // this should fire pretty late
|
||||
}
|
||||
|
@@ -15,12 +15,12 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.dspace.services.RequestService;
|
||||
import org.dspace.services.model.Request;
|
||||
@@ -32,7 +32,6 @@ import org.dspace.utils.servicemanager.OrderedServiceComparator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
|
||||
/**
|
||||
@@ -45,14 +44,13 @@ import org.springframework.beans.factory.annotation.Required;
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
* @author Tom Desair (tom dot desair at atmire dot com)
|
||||
*/
|
||||
public final class StatelessRequestServiceImpl implements RequestService, InitializedService, ShutdownService {
|
||||
public final class StatelessRequestServiceImpl implements RequestService {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(StatelessRequestServiceImpl.class);
|
||||
private static final Logger log = LoggerFactory.getLogger(StatelessRequestServiceImpl.class);
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
@@ -60,18 +58,14 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/**
|
||||
* map for holding onto the request interceptors which is classloader safe.
|
||||
*/
|
||||
private Map<String, RequestInterceptor> interceptorsMap = new HashMap<String, RequestInterceptor>();
|
||||
private final Map<String, RequestInterceptor> interceptorsMap = new HashMap<>();
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.InitializedService#init()
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
log.info("init");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
|
||||
*/
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
log.info("shutdown");
|
||||
clear();
|
||||
@@ -90,6 +84,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#startRequest()
|
||||
*/
|
||||
@Override
|
||||
public String startRequest() {
|
||||
return startRequest(new InternalRequestImpl());
|
||||
}
|
||||
@@ -97,6 +92,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#startRequest()
|
||||
*/
|
||||
@Override
|
||||
public String startRequest(ServletRequest request, ServletResponse response) {
|
||||
return startRequest(new HttpRequestImpl(request, response));
|
||||
}
|
||||
@@ -128,6 +124,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#endRequest(java.lang.Exception)
|
||||
*/
|
||||
@Override
|
||||
public String endRequest(Exception failure) {
|
||||
String requestId = null;
|
||||
try {
|
||||
@@ -175,7 +172,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
* @return the current list of interceptors in the correct order
|
||||
*/
|
||||
private List<RequestInterceptor> getInterceptors(boolean reverse) {
|
||||
ArrayList<RequestInterceptor> l = new ArrayList<RequestInterceptor>(this.interceptorsMap.values());
|
||||
ArrayList<RequestInterceptor> l = new ArrayList<>(this.interceptorsMap.values());
|
||||
OrderedServiceComparator comparator = new OrderedServiceComparator();
|
||||
Collections.sort(l, comparator);
|
||||
if (reverse) {
|
||||
@@ -187,6 +184,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#registerRequestListener(org.dspace.services.model.RequestInterceptor)
|
||||
*/
|
||||
@Override
|
||||
public void registerRequestInterceptor(RequestInterceptor interceptor) {
|
||||
if (interceptor == null) {
|
||||
throw new IllegalArgumentException("Cannot register an interceptor that is null");
|
||||
@@ -198,11 +196,12 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
this.interceptorsMap.put(key, interceptor);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.dspace.services.RequestService#getCurrentUserId()
|
||||
*/
|
||||
@Override
|
||||
public String getCurrentUserId() {
|
||||
Request currentRequest = getCurrentRequest();
|
||||
if (currentRequest == null) {
|
||||
@@ -212,11 +211,12 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.dspace.services.RequestService#setCurrentUserId()
|
||||
*/
|
||||
@Override
|
||||
public void setCurrentUserId(UUID epersonId) {
|
||||
Request currentRequest = getCurrentRequest();
|
||||
if (currentRequest != null) {
|
||||
@@ -227,6 +227,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#getCurrentRequestId()
|
||||
*/
|
||||
@Override
|
||||
public String getCurrentRequestId() {
|
||||
Request req = requests.getCurrent();
|
||||
if (req != null) {
|
||||
@@ -239,6 +240,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.services.RequestService#getCurrentRequest()
|
||||
*/
|
||||
@Override
|
||||
public Request getCurrentRequest() {
|
||||
return requests.getCurrent();
|
||||
}
|
||||
@@ -247,7 +249,7 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
* Class to hold the current request. Uses Map keyed on current thread id.
|
||||
*/
|
||||
private class RequestHolder {
|
||||
Map<Long, Request> requestMap = new ConcurrentHashMap<Long, Request>();
|
||||
Map<Long, Request> requestMap = new ConcurrentHashMap<>();
|
||||
|
||||
Request getCurrent() {
|
||||
return requestMap.get(Thread.currentThread().getId());
|
||||
@@ -298,5 +300,5 @@ public final class StatelessRequestServiceImpl implements RequestService, Initia
|
||||
}
|
||||
}
|
||||
|
||||
private RequestHolder requests = new RequestHolder();
|
||||
private final RequestHolder requests = new RequestHolder();
|
||||
}
|
||||
|
@@ -19,7 +19,4 @@
|
||||
|
||||
<context:annotation-config/> <!-- allows us to use spring annotations in beans -->
|
||||
|
||||
<!-- the bean processor interceptor -->
|
||||
<bean class="org.dspace.servicemanager.spring.DSpaceBeanPostProcessor"/>
|
||||
|
||||
</beans>
|
@@ -16,9 +16,9 @@ import static org.junit.Assert.fail;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.servicemanager.config.DSpaceConfigurationService;
|
||||
import org.dspace.servicemanager.example.ConcreteExample;
|
||||
import org.dspace.servicemanager.fakeservices.FakeService1;
|
||||
@@ -28,7 +28,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* testing the main dspace service manager
|
||||
* Testing the main DSpace service manager.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
@@ -42,10 +42,6 @@ public class DSpaceServiceManagerTest {
|
||||
public void init() {
|
||||
configurationService = new DSpaceConfigurationService();
|
||||
|
||||
// Set some sample configurations relating to services/beans
|
||||
configurationService.loadConfig(SampleAnnotationBean.class.getName() + ".sampleValue", "beckyz");
|
||||
configurationService.loadConfig("fakeBean.fakeParam", "beckyz");
|
||||
|
||||
dsm = new DSpaceServiceManager(configurationService, SPRING_TEST_CONFIG_FILE);
|
||||
}
|
||||
|
||||
@@ -175,16 +171,6 @@ public class DSpaceServiceManagerTest {
|
||||
ConcreteExample concrete = dsm.getServiceByName(ConcreteExample.class.getName(), ConcreteExample.class);
|
||||
assertNotNull(concrete);
|
||||
assertEquals("azeckoski", concrete.getName());
|
||||
concrete = null;
|
||||
|
||||
// initialize a SampleAnnotationBean
|
||||
SampleAnnotationBean sab = dsm
|
||||
.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
|
||||
assertNotNull(sab);
|
||||
// Based on the configuration for "sampleValue" in the init() method above,
|
||||
// a value should be pre-set!
|
||||
assertEquals("beckyz", sab.getSampleValue());
|
||||
sab = null;
|
||||
|
||||
SpringAnnotationBean spr = dsm.getServiceByName(
|
||||
SpringAnnotationBean.class.getName(), SpringAnnotationBean.class);
|
||||
@@ -192,7 +178,6 @@ public class DSpaceServiceManagerTest {
|
||||
assertEquals("azeckoski", spr.getConcreteName());
|
||||
assertEquals("aaronz", spr.getExampleName());
|
||||
assertEquals(null, spr.getSampleValue());
|
||||
spr = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -271,25 +256,6 @@ public class DSpaceServiceManagerTest {
|
||||
// TODO need to do a better test here
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitAndShutdown() {
|
||||
dsm.startup();
|
||||
|
||||
SampleAnnotationBean sab = dsm
|
||||
.getServiceByName(SampleAnnotationBean.class.getName(), SampleAnnotationBean.class);
|
||||
assertNotNull(sab);
|
||||
assertEquals(1, sab.initCounter);
|
||||
sab = null;
|
||||
|
||||
TestService ts = new TestService();
|
||||
assertEquals(0, ts.value);
|
||||
dsm.registerService(TestService.class.getName(), ts);
|
||||
assertEquals(1, ts.value);
|
||||
dsm.unregisterService(TestService.class.getName());
|
||||
assertEquals(2, ts.value);
|
||||
ts = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterProviderLifecycle() {
|
||||
dsm.startup();
|
||||
@@ -321,16 +287,16 @@ public class DSpaceServiceManagerTest {
|
||||
properties = null;
|
||||
}
|
||||
|
||||
public static class TestService implements InitializedService, ShutdownService {
|
||||
public static class TestService {
|
||||
|
||||
public int value = 0;
|
||||
|
||||
@Override
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
value++;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
value++;
|
||||
}
|
||||
|
@@ -7,44 +7,45 @@
|
||||
*/
|
||||
package org.dspace.servicemanager;
|
||||
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.dspace.servicemanager.example.ConcreteExample;
|
||||
import org.dspace.servicemanager.example.ServiceExample;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* This bean is a simple example of a bean which is annotated as a spring bean and should be found when the AC starts up
|
||||
* This bean is a simple example of a bean which is annotated as a Spring Bean
|
||||
* and should be found when the AC starts up.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
@Service
|
||||
public class SampleAnnotationBean implements InitializedService, ShutdownService {
|
||||
public class SampleAnnotationBean {
|
||||
|
||||
public int initCounter = 0;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
initCounter++;
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
initCounter++;
|
||||
}
|
||||
|
||||
private ServiceExample serviceExample;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setServiceExample(ServiceExample serviceExample) {
|
||||
this.serviceExample = serviceExample;
|
||||
}
|
||||
|
||||
private ConcreteExample concreteExample;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setConcreteExample(ConcreteExample concreteExample) {
|
||||
this.concreteExample = concreteExample;
|
||||
}
|
||||
|
@@ -10,23 +10,23 @@ package org.dspace.servicemanager.fakeservices;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import org.dspace.kernel.mixins.ConfigChangeListener;
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
import org.dspace.kernel.mixins.ServiceChangeListener;
|
||||
import org.dspace.kernel.mixins.ShutdownService;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
|
||||
/**
|
||||
* This is just testing a fake service and running it through some paces to see if the lifecycles work
|
||||
* This is just testing a fake service and running it through some paces to see
|
||||
* if the lifecycles work.
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public class FakeService1 implements ConfigChangeListener, ServiceChangeListener,
|
||||
InitializedService, ShutdownService, Serializable {
|
||||
Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public int triggers = 0;
|
||||
@@ -56,8 +56,7 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
|
||||
private ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
@Autowired(required = true)
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
@@ -69,6 +68,7 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ConfigChangeListener#configurationChanged(java.util.List, java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public void configurationChanged(List<String> changedSettingNames,
|
||||
Map<String, String> changedSettings) {
|
||||
something = "config:" + changedSettings.get("azeckoski.FakeService1.something");
|
||||
@@ -79,6 +79,7 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceRegistered(java.lang.String, java.lang.Object, java
|
||||
* .util.List)
|
||||
*/
|
||||
@Override
|
||||
public void serviceRegistered(String serviceName, Object service,
|
||||
List<Class<?>> implementedTypes) {
|
||||
something = "registered:" + serviceName;
|
||||
@@ -88,22 +89,19 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#serviceUnregistered(java.lang.String, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void serviceUnregistered(String serviceName, Object service) {
|
||||
something = "unregistered:" + serviceName;
|
||||
triggers++;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.InitializedService#init()
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
something = "init";
|
||||
triggers = 1; // RESET to 1
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ShutdownService#shutdown()
|
||||
*/
|
||||
@PreDestroy
|
||||
public void shutdown() {
|
||||
something = "shutdown";
|
||||
triggers++;
|
||||
@@ -112,6 +110,7 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ConfigChangeListener#notifyForConfigNames()
|
||||
*/
|
||||
@Override
|
||||
public String[] notifyForConfigNames() {
|
||||
return null; // ALL
|
||||
}
|
||||
@@ -119,6 +118,7 @@ public class FakeService1 implements ConfigChangeListener, ServiceChangeListener
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.ServiceChangeListener#notifyForTypes()
|
||||
*/
|
||||
@Override
|
||||
public Class<?>[] notifyForTypes() {
|
||||
return null; // ALL
|
||||
}
|
||||
|
@@ -8,16 +8,14 @@
|
||||
package org.dspace.servicemanager.fakeservices;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.dspace.kernel.mixins.InitializedService;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
/**
|
||||
* Simple fake service 2
|
||||
*
|
||||
* @author Aaron Zeckoski (azeckoski @ gmail.com)
|
||||
*/
|
||||
public class FakeService2 implements InitializedService, Comparable<FakeService2>, Serializable {
|
||||
public class FakeService2 implements Comparable<FakeService2>, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public String data = "data";
|
||||
@@ -30,13 +28,12 @@ public class FakeService2 implements InitializedService, Comparable<FakeService2
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.dspace.kernel.mixins.InitializedService#init()
|
||||
*/
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
data = "initData";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FakeService2 o) {
|
||||
return data.compareTo(o.data);
|
||||
}
|
||||
|
@@ -2026,3 +2026,4 @@ include = ${module_dir}/translator.cfg
|
||||
include = ${module_dir}/usage-statistics.cfg
|
||||
include = ${module_dir}/versioning.cfg
|
||||
include = ${module_dir}/workflow.cfg
|
||||
include = ${module_dir}/irus-statistics.cfg
|
||||
|
@@ -82,5 +82,7 @@
|
||||
<mapping class="org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole"/>
|
||||
<mapping class="org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem"/>
|
||||
|
||||
<mapping class="org.dspace.statistics.export.OpenURLTracker"/>
|
||||
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
||||
|
@@ -187,6 +187,13 @@
|
||||
<class>org.dspace.administer.RegistryLoader</class>
|
||||
</step>
|
||||
</command>
|
||||
<command>
|
||||
<name>retry-tracker</name>
|
||||
<description>Retry all failed commits to the OpenURLTracker</description>
|
||||
<step>
|
||||
<class>org.dspace.statistics.export.RetryFailedOpenUrlTracker</class>
|
||||
</step>
|
||||
</command>
|
||||
<command>
|
||||
<name>solr-export-statistics</name>
|
||||
<description>Export usage statistics data from Solr for back-up purposes</description>
|
||||
|
35
dspace/config/modules/irus-statistics.cfg
Normal file
35
dspace/config/modules/irus-statistics.cfg
Normal file
@@ -0,0 +1,35 @@
|
||||
# Enable the IRUS tracker. By default or when omitted, the tracker will be disabled
|
||||
irus.statistics.tracker.enabled = false
|
||||
|
||||
# OPTIONAL metadata field used for filtering.
|
||||
# If items with specific values for the "dc.type" field should be excluded, "dc.type" should be placed here.
|
||||
# This should comply to the syntax schema.element.qualified or schema.element if the qualifier is null.
|
||||
# irus.statistics.tracker.type-field = dc.type
|
||||
# If "tracker.type-field" is set, the list of values must be defined in "tracker.type-value".
|
||||
# This lists a comma separated list of values that will be excluded for the given field.
|
||||
# irus.statistics.tracker.type-value = Article, Postprint
|
||||
|
||||
# This lists a comma separated list of entities that will be included
|
||||
# When no list is provided, the default value "Publication" will be used
|
||||
# irus.statistics.tracker.entity-types = Publication
|
||||
|
||||
# Set the tracker environment to "test" or "production". Defaults to "test" if empty.
|
||||
# The URL used by the test environment can be configured in property tracker.testurl
|
||||
# The URL used by the production environment can be configured in property tracker.produrl
|
||||
irus.statistics.tracker.environment = test
|
||||
# The url used to test the submission of tracking info to.
|
||||
irus.statistics.tracker.testurl = https://irus.jisc.ac.uk/counter/test/
|
||||
# The base url for submitting the tracking info to.
|
||||
irus.statistics.tracker.produrl = https://irus.jisc.ac.uk/counter/
|
||||
# Identifies data as OpenURL 1.0
|
||||
irus.statistics.tracker.urlversion = Z39.88-2004
|
||||
|
||||
# Add the agentregex configuration below uncommented to local.cfg to include the bot agents list by
|
||||
# Project COUNTER when filtering bots in DSpace. The agents file is downloaded by the Apache ant
|
||||
# stage of the build process.
|
||||
|
||||
# Location of the COUNTER agents file
|
||||
# irus.statistics.spider.agentregex.regexfile = ${dspace.dir}/config/spiders/agents/COUNTER_Robots_list.txt
|
||||
|
||||
# External URL to COUNTER the agents file
|
||||
# irus.statistics.spider.agentregex.url = https://raw.githubusercontent.com/atmire/COUNTER-Robots/master/generated/COUNTER_Robots_list.txt
|
@@ -62,6 +62,7 @@
|
||||
<bean class="org.dspace.xmlworkflow.storedcomponents.dao.impl.PoolTaskDAOImpl"/>
|
||||
<bean class="org.dspace.xmlworkflow.storedcomponents.dao.impl.WorkflowItemRoleDAOImpl"/>
|
||||
<bean class="org.dspace.xmlworkflow.storedcomponents.dao.impl.XmlWorkflowItemDAOImpl"/>
|
||||
<bean class="org.dspace.statistics.export.dao.impl.OpenURLTrackerDAOImpl"/>
|
||||
|
||||
|
||||
|
||||
|
@@ -49,4 +49,6 @@
|
||||
|
||||
<bean id="indexObjectFactoryFactory" class="org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactoryImpl"/>
|
||||
|
||||
<bean id="openURLTrackerLoggerServiceFactory" class="org.dspace.statistics.export.factory.OpenURLTrackerLoggerServiceFactoryImpl"/>
|
||||
|
||||
</beans>
|
||||
|
10
dspace/config/spring/api/openurltracker.xml
Normal file
10
dspace/config/spring/api/openurltracker.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
|
||||
default-lazy-init="true">
|
||||
|
||||
|
||||
<bean class="org.dspace.statistics.export.FailedOpenURLTrackerServiceImpl"/>
|
||||
<bean class="org.dspace.statistics.export.service.OpenUrlServiceImpl"/>
|
||||
|
||||
</beans>
|
@@ -18,6 +18,11 @@
|
||||
<property name="dspaceRunnableClass" value="org.dspace.app.bulkedit.MetadataExportCli"/>
|
||||
</bean>
|
||||
|
||||
<bean id="retry-tracker" class="org.dspace.statistics.export.RetryFailedOpenUrlTrackerScriptConfiguration" scope="prototype">
|
||||
<property name="description" value="Retry all failed commits to the OpenURLTracker"/>
|
||||
<property name="dspaceRunnableClass" value="org.dspace.statistics.export.RetryFailedOpenUrlTracker"/>
|
||||
</bean>
|
||||
|
||||
<bean id="curate" class="org.dspace.curate.CurationCliScriptConfiguration">
|
||||
<property name="description" value="Curation tasks"/>
|
||||
<property name="dspaceRunnableClass" value="org.dspace.curate.CurationCli"/>
|
||||
|
@@ -21,4 +21,9 @@
|
||||
<property name="eventService" ref="org.dspace.services.EventService"/>
|
||||
</bean>
|
||||
|
||||
<!-- Irus statistics tracking -->
|
||||
<bean class="org.dspace.statistics.export.IrusExportUsageEventListener">
|
||||
<property name="eventService" ref="org.dspace.services.EventService"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -26,6 +26,40 @@
|
||||
<root.basedir>${basedir}/../../..</root.basedir>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: https://groovy.github.io/gmaven/groovy-maven-plugin/execute.html )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire & Failsafe plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>oracle-support</id>
|
||||
@@ -42,20 +76,20 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
||||
See also the 'skiptests' profile in Parent POM. -->
|
||||
|
||||
<!-- Setup the Unit Test Environment (when -DskipUnitTests=false) -->
|
||||
<profile>
|
||||
<id>test-environment</id>
|
||||
<id>unit-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<name>skipUnitTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Unit/Integration Testing setup: This plugin unzips the
|
||||
<!-- Unit Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
@@ -75,50 +109,12 @@
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupTestEnvironment</id>
|
||||
<id>setupUnitTestEnvironment</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the FileWeaver & Surefire plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>generate-test-resources
|
||||
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
@@ -136,6 +132,60 @@
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<!-- When running tests, also include test classes from dspace-api
|
||||
(this test-jar is only built when tests are enabled). -->
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-api</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<!-- Setup the Integration Test Environment (when -DskipIntegrationTests=false) -->
|
||||
<profile>
|
||||
<id>integration-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipIntegrationTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Integration Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<plugin>
|
||||
@@ -163,6 +213,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
</profiles>
|
||||
|
||||
<!--
|
||||
|
@@ -73,24 +73,52 @@ just adding new jar in the classloader</description>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: https://groovy.github.io/gmaven/groovy-maven-plugin/execute.html )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the Surefire & Failsafe plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
||||
See also the 'skiptests' profile in Parent POM. -->
|
||||
<!-- Setup the Unit Test Environment (when -DskipUnitTests=false) -->
|
||||
<profile>
|
||||
<id>test-environment</id>
|
||||
<id>unit-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<name>skipUnitTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Unit/Integration Testing setup: This plugin unzips the
|
||||
<!-- Unit Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
@@ -110,49 +138,12 @@ just adding new jar in the classloader</description>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupTestEnvironment</id>
|
||||
<id>setupUnitTestEnvironment</id>
|
||||
<phase>generate-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
||||
the ${project.build.directory} property (full path of target dir).
|
||||
This is needed by the FileWeaver & Surefire plugins (see below)
|
||||
to initialize the Unit Test environment's dspace.cfg file.
|
||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
||||
This Groovy code was mostly borrowed from:
|
||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.codehaus.gmaven</groupId>
|
||||
<artifactId>groovy-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setproperty</id>
|
||||
<phase>initialize</phase>
|
||||
<goals>
|
||||
<goal>execute</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<source>
|
||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
||||
log.info("Initializing Maven property 'agnostic.build.dir' to: {}", project.properties['agnostic.build.dir']);
|
||||
</source>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
@@ -171,6 +162,60 @@ just adding new jar in the classloader</description>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<!-- When running tests, also include test classes from dspace-server-webapp
|
||||
(this test-jar is only built when tests are enabled). -->
|
||||
<dependency>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-server-webapp</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<!-- Setup the Integration Test Environment (when -DskipIntegrationTests=false) -->
|
||||
<profile>
|
||||
<id>integration-test-environment</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipIntegrationTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Integration Testing setup: This plugin unzips the
|
||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
||||
the 'target/testing/' folder, to essentially create a test
|
||||
install of DSpace, against which Tests can be run. -->
|
||||
<plugin>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.dspace</groupId>
|
||||
<artifactId>dspace-parent</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<classifier>testEnvironment</classifier>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>setupIntegrationTestEnvironment</id>
|
||||
<phase>pre-integration-test</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
||||
<plugin>
|
||||
@@ -199,6 +244,7 @@ just adding new jar in the classloader</description>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>oracle-support</id>
|
||||
<activation>
|
||||
|
@@ -148,30 +148,28 @@
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<!-- Profile to aggregate (local) code coverage reports via JaCoCo
|
||||
(jacoco.org) during the Unit and Integration testing process.
|
||||
This profile is only enabled when tests are (skipTests=false).
|
||||
<!-- Profile to aggregate (local) code coverage reports created by JaCoCo (jacoco.org)
|
||||
during the Unit and Integration testing processes.
|
||||
This plugin is disabled by default, as it is triggered by name in [src]/.travis.yml
|
||||
See also jacoco-maven-plugin settings in Parent POM, as those
|
||||
settings generate the reports aggregated here. -->
|
||||
settings generate the module-specific reports that are aggregated here. -->
|
||||
<profile>
|
||||
<id>test-coverage-report</id>
|
||||
<id>coverage-report</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
<property>
|
||||
<name>skipTests</name>
|
||||
<value>false</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- Aggregate unit test code coverage reports -->
|
||||
<!-- Aggregate all test code coverage reports from the individual module coverage reports
|
||||
that are generated during unit & integration testing.
|
||||
Results (HTML and XML) are written to ./target/site/jacoco-aggregate/ -->
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>aggregate-test-report</id>
|
||||
<phase>post-integration-test</phase>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>report-aggregate</goal>
|
||||
</goals>
|
||||
@@ -182,8 +180,6 @@
|
||||
<dataFileInclude>**/jacoco-ut.exec</dataFileInclude>
|
||||
<dataFileInclude>**/jacoco-it.exec</dataFileInclude>
|
||||
</dataFileIncludes>
|
||||
<!-- Sets the output directory for the code coverage report. -->
|
||||
<outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregated</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
@@ -231,50 +227,6 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
|
||||
<!-- Send coverage reports (generated by jacoco-maven-plugin) to coveralls.io. See 'test-coverage-report'
|
||||
profile above for more details on aggregating of code coverage reports.
|
||||
This plugin is disabled by default, as it is triggered by name in [src]/.travis.yml -->
|
||||
<profile>
|
||||
<id>coveralls</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eluder.coveralls</groupId>
|
||||
<artifactId>coveralls-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>report-test-coverage</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<failOnServiceError>false</failOnServiceError>
|
||||
<jacocoReports>
|
||||
<jacocoReport>${project.reporting.outputDirectory}/jacoco-aggregated/jacoco.xml</jacocoReport>
|
||||
</jacocoReports>
|
||||
<sourceDirectories>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-api/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-api/target/generated-sources/annotations</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-oai/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-rdf/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-rest/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-services/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-server-webapp/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-sword/src/main/java</sourceDirectory>
|
||||
<sourceDirectory>${project.parent.basedir}/dspace-swordv2/src/main/java</sourceDirectory>
|
||||
</sourceDirectories>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -114,6 +114,7 @@ Common usage:
|
||||
<echo message="update --> Update ${dspace.dir} config, etc, lib and web applications without " />
|
||||
<echo message=" touching your data" />
|
||||
<echo message="update_configs --> Update your configs directory with new configuration files"/>
|
||||
<echo message="update_spiders --> Dowload and install Spider Robots database into ${dspace.dir}/config" />
|
||||
<echo message="update_code --> Update compiled code (bin, lib, and etc directories)" />
|
||||
<echo message="update_webapps --> Update web applications" />
|
||||
<echo message="" />
|
||||
@@ -177,6 +178,7 @@ Common usage:
|
||||
<target name="update_configs"
|
||||
depends="overwrite_configs,overwrite_solr_configs"
|
||||
description="Updates the Configuration Directory">
|
||||
<antcall target="init_spiders" />
|
||||
</target>
|
||||
|
||||
<target name="overwrite_configs" description="Overwrites a configuration directory." if="${overwrite}" depends="copy_configs_keep">
|
||||
@@ -827,6 +829,8 @@ Common usage:
|
||||
|
||||
<antcall target="copy_webapps" />
|
||||
|
||||
<antcall target="init_spiders" />
|
||||
|
||||
<echo>
|
||||
====================================================================
|
||||
The DSpace code has been installed.
|
||||
@@ -856,4 +860,27 @@ Common usage:
|
||||
|
||||
</target>
|
||||
|
||||
<!-- installs and/or updates Project Counter Robot List resolution database -->
|
||||
<target name="update_spiders">
|
||||
<echo>Downloading: ${irus.statistics.spider.agentregex.url}</echo>
|
||||
<get src="${irus.statistics.spider.agentregex.url}" dest="${irus.statistics.spider.agentregex.regexfile}" verbose="true" />
|
||||
</target>
|
||||
|
||||
<target name="check_spiders">
|
||||
<condition property="need.spiders">
|
||||
<and>
|
||||
<not>
|
||||
<available file="${irus.statistics.spider.agentregex.regexfile}" />
|
||||
</not>
|
||||
<not>
|
||||
<contains string="${irus.statistics.spider.agentregex.url}" substring="irus.statistics.spider.agentregex.url"/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="init_spiders" depends="check_spiders" if="need.spiders">
|
||||
<antcall target="update_spiders" />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
@@ -13,6 +13,6 @@ export const environment = {
|
||||
host: 'localhost',
|
||||
port: 8080,
|
||||
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
|
||||
nameSpace: '/server/api'
|
||||
nameSpace: '/server'
|
||||
}
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user