Merge branch 'master' into DS-4239-migrate-workflow-xml-to-spring

This commit is contained in:
Kevin Van de Velde
2019-12-16 13:00:54 +01:00
1042 changed files with 48289 additions and 9469 deletions

View File

@@ -3,4 +3,9 @@
.settings/
*/target/
dspace/modules/*/target/
Dockerfile.*
Dockerfile.*
dspace/src/main/docker/dspace-postgres-pgcrypto
dspace/src/main/docker/dspace-postgres-pgcrypto-curl
dspace/src/main/docker/solr
dspace/src/main/docker/README.md
dspace/src/main/docker-compose/

2
.gitignore vendored
View File

@@ -41,4 +41,4 @@ nb-configuration.xml
.DS_Store
##Ignore JRebel project configuration
rebel.xml
rebel.xml

View File

@@ -1,5 +1,6 @@
language: java
sudo: false
dist: trusty
env:
# Give Maven 1GB of memory to work with

54
Dockerfile.cli.jdk8 Normal file
View File

@@ -0,0 +1,54 @@
# This image will be published as dspace/dspace-cli
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
# This version is JDK8 compatible
# - openjdk:8-jdk
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - default tag for branch: dspace/dspace-cli: dspace/dspace-cli:dspace-7_x
# Step 1 - Run Maven Build
FROM dspace/dspace-dependencies:dspace-7_x as build
ARG TARGET_DIR=dspace-installer
WORKDIR /app
# The dspace-install directory will be written to /install
RUN mkdir /install \
&& chown -Rv dspace: /install \
&& chown -Rv dspace: /app
USER dspace
# Copy the DSpace source code into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
COPY dspace/src/main/docker/local.cfg /app/local.cfg
# Build DSpace. Copy the dspace-install directory to /install. Clean up the build to keep the docker image small
RUN mvn package -P'!dspace-rest' && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
# Step 2 - Run Ant Deploy
FROM openjdk:8-jdk as ant_build
ARG TARGET_DIR=dspace-installer
COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code
# Step 3 - Run jdk
# Create a new tomcat image that does not retain the the build directory contents
FROM openjdk:8-jdk
ENV DSPACE_INSTALL=/dspace
COPY --from=ant_build /dspace $DSPACE_INSTALL
ENV JAVA_OPTS=-Xmx1000m

View File

@@ -1,11 +1,11 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
#
# This version is JDK8 compatible
# - tomcat:8-jre8
# - ANT 1.10.5
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8
# Step 1 - Run Maven Build
@@ -36,14 +36,14 @@ COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.5
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
RUN ant init_installation update_configs update_code update_webapps
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
@@ -54,10 +54,13 @@ EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
# Run the "server" webapp off the /server path (e.g. http://localhost:8080/server/)
# and the v6.x (deprecated) REST API off the "/rest" path
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
# If you wish to run "server" webapp off the ROOT path, then comment out the above RUN, and uncomment the below RUN.
# You also MUST update the URL in dspace/src/main/docker/local.cfg
# Please note that server webapp should only run on one path at a time.
#RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT && \
# ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest

View File

@@ -1,11 +1,11 @@
# This image will be published as dspace/dspace
# See https://dspace-labs.github.io/DSpace-Docker-Images/ for usage details
#
#
# This version is JDK8 compatible
# - tomcat:8-jre8
# - ANT 1.10.5
# - ANT 1.10.7
# - maven:3-jdk-8
# - note:
# - note:
# - default tag for branch: dspace/dspace: dspace/dspace:dspace-7_x-jdk8-test
# Step 1 - Run Maven Build
@@ -36,14 +36,14 @@ COPY --from=build /install /dspace-src
WORKDIR /dspace-src
# Create the initial install deployment using ANT
ENV ANT_VERSION 1.10.5
ENV ANT_VERSION 1.10.7
ENV ANT_HOME /tmp/ant-$ANT_VERSION
ENV PATH $ANT_HOME/bin:$PATH
RUN mkdir $ANT_HOME && \
wget -qO- "https://www.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
wget -qO- "https://archive.apache.org/dist/ant/binaries/apache-ant-$ANT_VERSION-bin.tar.gz" | tar -zx --strip-components=1 -C $ANT_HOME
RUN ant init_installation update_configs update_code update_webapps update_solr_indexes
RUN ant init_installation update_configs update_code update_webapps
# Step 3 - Run tomcat
# Create a new tomcat image that does not retain the the build directory contents
@@ -54,16 +54,17 @@ EXPOSE 8080 8009
ENV JAVA_OPTS=-Xmx2000m
RUN ln -s $DSPACE_INSTALL/webapps/solr /usr/local/tomcat/webapps/solr && \
ln -s $DSPACE_INSTALL/webapps/spring-rest /usr/local/tomcat/webapps/spring-rest && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest && \
ln -s $DSPACE_INSTALL/webapps/oai /usr/local/tomcat/webapps/oai && \
ln -s $DSPACE_INSTALL/webapps/rdf /usr/local/tomcat/webapps/rdf && \
ln -s $DSPACE_INSTALL/webapps/sword /usr/local/tomcat/webapps/sword && \
ln -s $DSPACE_INSTALL/webapps/swordv2 /usr/local/tomcat/webapps/swordv2
# Run the "server" webapp off the /server path (e.g. http://localhost:8080/server/)
# and the v6.x (deprecated) REST API off the "/rest" path
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
# If you wish to run "server" webapp off the ROOT path, then comment out the above RUN, and uncomment the below RUN.
# You also MUST update the URL in dspace/src/main/docker/local.cfg
# Please note that server webapp should only run on one path at a time.
#RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT && \
# ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
COPY dspace/src/main/docker/test/solr_web.xml $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml
# Overwrite the v6.x (deprecated) REST API's web.xml, so that we can run it on HTTP (defaults to requiring HTTPS)
COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/solr/WEB-INF/web.xml && \
sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml

View File

@@ -3,21 +3,21 @@
[![Build Status](https://travis-ci.org/DSpace/DSpace.png?branch=master)](https://travis-ci.org/DSpace/DSpace)
[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) |
[DSpace Documentation](https://wiki.duraspace.org/display/DSDOC/) |
[DSpace Releases](https://github.com/DSpace/DSpace/releases) |
[DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) |
[DSpace Wiki](https://wiki.duraspace.org/display/DSPACE/Home) |
[Support](https://wiki.duraspace.org/display/DSPACE/Support)
DSpace open source software is a turnkey repository application used by more than
DSpace open source software is a turnkey repository application used by more than
2,000 organizations and institutions worldwide to provide durable access to digital resources.
For more information, visit http://www.dspace.org/
***
:warning: **Work on DSpace 7 has begun on our `master` branch.** This means that there is temporarily NO user interface on this `master` branch. DSpace 7 will feature a new, unified [Angular](https://angular.io/) user interface, along with an enhanced, rebuilt REST API. The latest status of this work can be found on the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) page. Additionally, the codebases can be found in the following places:
* DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-spring-rest) of this repository.
* DSpace 7 REST API work is occurring on the [`master` branch](https://github.com/DSpace/DSpace/tree/master/dspace-server-webapp) of this repository.
* The REST Contract is being documented at https://github.com/DSpace/Rest7Contract
* DSpace 7 Angular UI work is occurring at https://github.com/DSpace/dspace-angular
**If you would like to get involved in our DSpace 7 development effort, we welcome new contributors.** Just join one of our meetings or get in touch via Slack. See the [DSpace 7 UI Working Group](https://wiki.duraspace.org/display/DSPACE/DSpace+7+UI+Working+Group) wiki page for more info.
**If you are looking for the ongoing maintenance work for DSpace 6 (or prior releases)**, you can find that work on the corresponding maintenance branch (e.g. [`dspace-6_x`](https://github.com/DSpace/DSpace/tree/dspace-6_x)) in this repository.
@@ -31,21 +31,21 @@ Past releases are all available via GitHub at https://github.com/DSpace/DSpace/r
## Documentation / Installation
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/).
Documentation for each release may be viewed online or downloaded via our [Documentation Wiki](https://wiki.duraspace.org/display/DSDOC/).
The latest DSpace Installation instructions are available at:
https://wiki.duraspace.org/display/DSDOC6x/Installing+DSpace
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle)
Please be aware that, as a Java web application, DSpace requires a database (PostgreSQL or Oracle)
and a servlet container (usually Tomcat) in order to function.
More information about these and all other prerequisites can be found in the Installation instructions above.
## Dockerfile Usage
See the [DSpace Docker Tutorial](https://dspace-labs.github.io/DSpace-Docker-Images/).
## Running DSpace 7 in Docker
See [Running DSpace 7 with Docker Compose](dspace/src/main/docker-compose/README.md)
## Contributing
DSpace is a community built and supported project. We do not have a centralized development or support team,
DSpace is a community built and supported project. We do not have a centralized development or support team,
but have a dedicated group of volunteers who help us improve the software, documentation, resources, etc.
We welcome contributions of any type. Here's a few basic guides that provide suggestions for contributing to DSpace:
@@ -71,8 +71,8 @@ Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stack
Additional support options are listed at https://wiki.duraspace.org/display/DSPACE/Support
DSpace also has an active service provider network. If you'd rather hire a service provider to
install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our
DSpace also has an active service provider network. If you'd rather hire a service provider to
install, upgrade, customize or host DSpace, then we recommend getting in touch with one of our
[Registered Service Providers](http://www.dspace.org/service-providers).
## Issue Tracker
@@ -101,7 +101,7 @@ run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all P
# Run all tests in a specific test class
# NOTE: testClassName is just the class name, do not include package
mvn clean test -Dmaven.test.skip=false -Dtest=[testClassName]
# Run one test method in a specific test class
mvn clean test -Dmaven.test.skip=false -Dtest=[testClassName]#[testMethodName]
```
@@ -115,7 +115,7 @@ run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all P
# NOTE: Integration Tests only run for "verify" or "install" phases
# NOTE: testClassName is just the class name, do not include package
mvn clean verify -Dmaven.test.skip=false -DskipITs=false -Dit.test=[testClassName]
# Run one test method in a specific test class
mvn clean verify -Dmaven.test.skip=false -DskipITs=false -Dit.test=[testClassName]#[testMethodName]
```
@@ -124,9 +124,9 @@ run automatically by [Travis CI](https://travis-ci.org/DSpace/DSpace/) for all P
# Before you can run only one module's tests, other modules may need installing into your ~/.m2
cd [dspace-src]
mvn clean install
# Then, move into a module subdirectory, and run the test command
cd [dspace-src]/dspace-spring-rest
cd [dspace-src]/dspace-server-webapp
# Choose your test command from the lists above
```

25
docker-compose-cli.yml Normal file
View File

@@ -0,0 +1,25 @@
version: "3.7"
services:
dspace-cli:
image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-dspace-7_x}"
container_name: dspace-cli
build:
context: .
dockerfile: Dockerfile.cli.jdk8
#environment:
volumes:
- ./dspace/src/main/docker-compose/local.cfg:/dspace/config/local.cfg
- assetstore:/dspace/assetstore
entrypoint: /dspace/bin/dspace
command: help
networks:
- dspacenet
tty: true
stdin_open: true
volumes:
assetstore:
networks:
dspacenet:

62
docker-compose.yml Normal file
View File

@@ -0,0 +1,62 @@
version: '3.7'
networks:
dspacenet:
services:
dspace:
container_name: dspace
image: "${DOCKER_OWNER:-dspace}/dspace:${DSPACE_VER:-dspace-7_x-jdk8-test}"
build:
context: .
dockerfile: Dockerfile.jdk8-test
depends_on:
- dspacedb
networks:
dspacenet:
ports:
- published: 8080
target: 8080
stdin_open: true
tty: true
volumes:
- assetstore:/dspace/assetstore
- ./dspace/src/main/docker-compose/local.cfg:/dspace/config/local.cfg
# Ensure that the database is ready before starting tomcat
entrypoint:
- /bin/bash
- '-c'
- |
/dspace/bin/dspace database migrate
catalina.sh run
dspacedb:
container_name: dspacedb
environment:
PGDATA: /pgdata
image: dspace/dspace-postgres-pgcrypto
networks:
dspacenet:
stdin_open: true
tty: true
volumes:
- pgdata:/pgdata
dspacesolr:
container_name: dspacesolr
image: dspace/dspace-solr
networks:
dspacenet:
ports:
- published: 8983
target: 8983
stdin_open: true
tty: true
volumes:
- solr_authority:/opt/solr/server/solr/authority/data
- solr_oai:/opt/solr/server/solr/oai/data
- solr_search:/opt/solr/server/solr/search/data
- solr_statistics:/opt/solr/server/solr/statistics/data
volumes:
assetstore:
pgdata:
solr_authority:
solr_oai:
solr_search:
solr_statistics:

View File

@@ -1,5 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-api</artifactId>
@@ -87,7 +86,6 @@
<exclude>**/.gitignore</exclude>
<exclude>**/src/main/resources/rebel.xml</exclude>
<exclude>src/test/data/dspaceFolder/config/spiders/**</exclude>
<exclude>src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java</exclude>
</excludes>
</configuration>
</plugin>
@@ -335,6 +333,16 @@
<groupId>org.dspace</groupId>
<artifactId>handle</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.aggregate</groupId>
<artifactId>jetty-all</artifactId>
<exclusions>
<exclusion>
<artifactId>javax.servlet</artifactId>
<groupId>org.eclipse.jetty.orbit</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>jargon</artifactId>
@@ -450,14 +458,6 @@
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
@@ -600,6 +600,12 @@
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-cell</artifactId>
<version>${solr.client.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
@@ -757,6 +763,34 @@
<artifactId>json</artifactId>
<version>20180130</version>
</dependency>
<!-- Used for Solr core export/import -->
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.5</version>
</dependency>
<!-- Email templating -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-matchers</artifactId>
<version>2.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
</dependencies>
</project>

View File

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

View File

@@ -21,6 +21,7 @@ import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
@@ -248,7 +249,7 @@ public class MetadataImporter {
// If the schema is not provided default to DC
if (schema == null) {
schema = MetadataSchema.DC_SCHEMA;
schema = MetadataSchemaEnum.DC.getName();
}

View File

@@ -7,12 +7,16 @@
*/
package org.dspace.administer;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -23,12 +27,16 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.xpath.XPathAPI;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
@@ -36,6 +44,7 @@ import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.jdom.Element;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -47,18 +56,17 @@ import org.xml.sax.SAXException;
* an XML file.
*
* The XML file structure needs to be:
* <p>
* {@code
* <pre>{@code
* <import_structure>
* <community>
* <name>....</name>
* <community>...</community>
* <collection>
* <name>....</name>
* </collection>
* </community>
* <community>
* <name>....</name>
* <community>...</community>
* <collection>
* <name>....</name>
* </collection>
* </community>
* </import_structure>
* }
* }</pre>
* <p>
* It can be arbitrarily deep, and supports all the metadata elements
* that make up the community and collection metadata. See the system
@@ -68,26 +76,31 @@ import org.xml.sax.SAXException;
*/
public class StructBuilder {
/**
* The output XML document which will contain updated information about the
* imported structure.
/** Name of the root element for the document to be imported. */
static final String INPUT_ROOT = "import_structure";
/*
* Name of the root element for the document produced by importing.
* Community and collection elements are annotated with their identifiers.
*/
private static final org.jdom.Document xmlOutput
= new org.jdom.Document(new Element("imported_structure"));
static final String RESULT_ROOT = "imported_structure";
/**
* A hash table to hold metadata for the collection being worked on.
* A table to hold metadata for the collection being worked on.
*/
private static final Map<String, String> collectionMap = new HashMap<>();
/**
* A hash table to hold metadata for the community being worked on.
* A table to hold metadata for the community being worked on.
*/
private static final Map<String, String> communityMap = new HashMap<>();
protected static CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected static EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
protected static CommunityService communityService
= ContentServiceFactory.getInstance().getCommunityService();
protected static CollectionService collectionService
= ContentServiceFactory.getInstance().getCollectionService();
protected static EPersonService ePersonService
= EPersonServiceFactory.getInstance().getEPersonService();
/**
* Default constructor
@@ -96,31 +109,48 @@ public class StructBuilder {
/**
* Main method to be run from the command line to import a structure into
* DSpace
* DSpacee or export existing structure to a file.The command is of the form:
*
* This is of the form:
* <p>{@code StructBuilder -f [XML source] -e [administrator email] -o [output file]}
*
* {@code StructBuilder -f [xml source] -e [administrator email] -o [output file]}
* <p>to import, or
*
* The output file will contain exactly the same as the source xml document, but
* with the handle for each imported item added as an attribute.
* <p>{@code StructBuilder -x -e [administrator email] -o [output file]}</p>
*
* @param argv the command line arguments given
* <p>to export. The output will contain exactly the same as the source XML
* document, but with the Handle for each imported item added as an attribute.
*
*
* @param argv command line arguments.
* @throws ParserConfigurationException passed through.
* @throws SQLException passed through.
* @throws FileNotFoundException if input or output could not be opened.
* @throws TransformerException if the input document is invalid.
*/
public static void main(String[] argv)
throws ParserConfigurationException, SQLException {
CommandLineParser parser = new DefaultParser();
throws ParserConfigurationException, SQLException,
FileNotFoundException, IOException, TransformerException {
// Define command line options.
Options options = new Options();
options.addOption("h", "help", false, "help");
options.addOption("h", "help", false, "Print this help message.");
options.addOption("?", "help");
options.addOption("f", "file", true, "input structure document");
options.addOption("e", "eperson", true, "eperson");
options.addOption("o", "output", true, "output structure document");
options.addOption("x", "export", false, "Export the current structure as XML.");
options.addOption(Option.builder("e").longOpt("eperson")
.desc("User who is manipulating the repository's structure.")
.hasArg().argName("eperson").required().build());
options.addOption(Option.builder("f").longOpt("file")
.desc("File of new structure information.")
.hasArg().argName("input").build());
options.addOption(Option.builder("o").longOpt("output")
.desc("File to receive the structure map ('-' for standard out).")
.hasArg().argName("output").required().build());
// Parse the command line.
CommandLineParser parser = new DefaultParser();
CommandLine line = null;
try {
line = parser.parse(options, argv);
@@ -130,36 +160,33 @@ public class StructBuilder {
System.exit(1);
}
// If the user asked for help, give it and exit.
if (line.hasOption('h') || line.hasOption('?')) {
usage(options);
giveHelp(options);
System.exit(0);
}
String file = null;
String eperson = null;
String output = null;
if (line.hasOption('f')) {
file = line.getOptionValue('f');
}
if (line.hasOption('e')) {
eperson = line.getOptionValue('e');
}
if (line.hasOption('o')) {
output = line.getOptionValue('o');
}
if (output == null || eperson == null || file == null) {
usage(options);
// Otherwise, analyze the command.
// Must be import or export.
if (!(line.hasOption('f') || line.hasOption('x'))) {
giveHelp(options);
System.exit(1);
}
// Open the output stream.
String output = line.getOptionValue('o');
OutputStream outputStream;
if ("-".equals(output)) {
outputStream = System.out;
} else {
outputStream = new FileOutputStream(output);
}
// create a context
Context context = new Context();
// set the context
// set the context.
String eperson = line.getOptionValue('e');
try {
context.setCurrentUser(ePersonService.findByEmail(context, eperson));
} catch (SQLException ex) {
@@ -167,10 +194,47 @@ public class StructBuilder {
System.exit(1);
}
// Export? Import?
if (line.hasOption('x')) { // export
exportStructure(context, outputStream);
} else { // Must be import
String input = line.getOptionValue('f');
if (null == input) {
usage(options);
System.exit(1);
}
InputStream inputStream;
if ("-".equals(input)) {
inputStream = System.in;
} else {
inputStream = new FileInputStream(input);
}
importStructure(context, inputStream, outputStream);
}
System.exit(0);
}
/**
* Import new Community/Collection structure.
*
* @param context
* @param input XML which describes the new communities and collections.
* @param output input, annotated with the new objects' identifiers.
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
* @throws TransformerException
* @throws SQLException
*/
static void importStructure(Context context, InputStream input, OutputStream output)
throws IOException, ParserConfigurationException, SQLException, TransformerException {
// load the XML
Document document = null;
try {
document = loadXML(file);
document = loadXML(input);
} catch (IOException ex) {
System.err.format("The input document could not be read: %s%n", ex.getMessage());
System.exit(1);
@@ -180,7 +244,7 @@ public class StructBuilder {
}
// run the preliminary validation, to be sure that the the XML document
// is properly structured
// is properly structured.
try {
validate(document);
} catch (TransformerException ex) {
@@ -188,6 +252,12 @@ public class StructBuilder {
System.exit(1);
}
// Check for 'identifier' attributes -- possibly output by this class.
NodeList identifierNodes = XPathAPI.selectNodeList(document, "//*[@identifier]");
if (identifierNodes.getLength() > 0) {
System.err.println("The input document has 'identifier' attributes, which will be ignored.");
}
// load the mappings into the member variable hashmaps
communityMap.put("name", "name");
communityMap.put("description", "short_description");
@@ -219,33 +289,154 @@ public class StructBuilder {
}
// generate the output
Element root = xmlOutput.getRootElement();
final Element root = new Element(RESULT_ROOT);
for (Element element : elements) {
root.addContent(element);
}
// finally write the string into the output file
try (BufferedWriter out = new BufferedWriter(new FileWriter(output));) {
out.write(new XMLOutputter().outputString(xmlOutput));
// finally write the string into the output file.
final org.jdom.Document xmlOutput = new org.jdom.Document(root);
try {
new XMLOutputter().output(xmlOutput, output);
} catch (IOException e) {
System.out.println("Unable to write to output file " + output);
System.out.printf("Unable to write to output file %s: %s%n",
output, e.getMessage());
System.exit(1);
}
context.complete();
}
/**
* Add a single community, and its children, to the Document.
*
* @param community
* @return a fragment representing this Community.
*/
private static Element exportACommunity(Community community) {
// Export this Community.
Element element = new Element("community");
element.setAttribute("identifier", community.getHandle());
element.addContent(new Element("name").setText(community.getName()));
element.addContent(new Element("description")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY)));
element.addContent(new Element("intro")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY)));
element.addContent(new Element("copyright")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY)));
element.addContent(new Element("sidebar")
.setText(communityService.getMetadataFirstValue(community,
MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY)));
// Export this Community's Community children.
for (Community subCommunity : community.getSubcommunities()) {
element.addContent(exportACommunity(subCommunity));
}
// Export this Community's Collection children.
for (Collection collection : community.getCollections()) {
element.addContent(exportACollection(collection));
}
return element;
}
/**
* Add a single Collection to the Document.
*
* @param collection
* @return a fragment representing this Collection.
*/
private static Element exportACollection(Collection collection) {
// Export this Collection.
Element element = new Element("collection");
element.setAttribute("identifier", collection.getHandle());
element.addContent(new Element("name").setText(collection.getName()));
element.addContent(new Element("description")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY)));
element.addContent(new Element("intro")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY)));
element.addContent(new Element("copyright")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY)));
element.addContent(new Element("sidebar")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY)));
element.addContent(new Element("license")
.setText(collectionService.getMetadataFirstValue(collection,
MetadataSchemaEnum.DC.getName(), "rights", "license", Item.ANY)));
// Provenance is special: multivalued
for (MetadataValue value : collectionService.getMetadata(collection,
MetadataSchemaEnum.DC.getName(), "provenance", null, Item.ANY)) {
element.addContent(new Element("provenance")
.setText(value.getValue()));
}
return element;
}
/**
* Write out the existing Community/Collection structure.
*/
static void exportStructure(Context context, OutputStream output) {
// Build a document from the Community/Collection hierarchy.
Element rootElement = new Element(INPUT_ROOT); // To be read by importStructure, perhaps
List<Community> communities = null;
try {
communities = communityService.findAllTop(context);
} catch (SQLException ex) {
System.out.printf("Unable to get the list of top-level communities: %s%n",
ex.getMessage());
System.exit(1);
}
for (Community community : communities) {
rootElement.addContent(exportACommunity(community));
}
// Now write the structure out.
org.jdom.Document xmlOutput = new org.jdom.Document(rootElement);
try {
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(xmlOutput, output);
} catch (IOException e) {
System.out.printf("Unable to write to output file %s: %s%n",
output, e.getMessage());
System.exit(1);
}
}
/**
* Output the usage information.
*/
private static void usage(Options options) {
HelpFormatter helper = new HelpFormatter();
helper.printHelp("java StructBuilder -f <source XML file> -o <output file> -e <eperson email>",
"Load community/collection structure from a file.",
try (PrintWriter writer = new PrintWriter(System.out);) {
helper.printUsage(writer, 80/* FIXME Magic */,
"structure-builder", options);
}
}
/**
* Help the user more.
*/
private static void giveHelp(Options options) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("struct-builder",
"Import or export Community/Collection structure.",
options,
"Communities will be created from the top level,"
+ " and a map of communities to handles will be returned"
+ " in the output file.");
"When importing (-f), communities will be created from the "
+ "top level, and a map of communities to handles will "
+ "be returned in the output file. When exporting (-x),"
+ "the current structure will be written to the map file.",
true);
}
/**
@@ -267,7 +458,7 @@ public class StructBuilder {
if (first.getLength() == 0) {
err.append("-There are no top level communities in the source document.");
System.out.println(err.toString());
System.exit(0);
System.exit(1);
}
String errs = validateCommunities(first, 1);
@@ -278,7 +469,7 @@ public class StructBuilder {
if (trip) {
System.out.println(err.toString());
System.exit(0);
System.exit(1);
}
}
@@ -367,17 +558,17 @@ public class StructBuilder {
}
/**
* Load in the XML from file.
* Load the XML document from input.
*
* @param filename the filename to load from
* @return the DOM representation of the XML file
* @param input the filename to load from.
* @return the DOM representation of the XML input.
*/
private static org.w3c.dom.Document loadXML(String filename)
private static org.w3c.dom.Document loadXML(InputStream input)
throws IOException, ParserConfigurationException, SAXException {
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
org.w3c.dom.Document document = builder.parse(new File(filename));
org.w3c.dom.Document document = builder.parse(input);
return document;
}
@@ -388,7 +579,7 @@ public class StructBuilder {
* @param node the node from which we want to extract the string value
* @return the string value of the node
*/
public static String getStringValue(Node node) {
private static String getStringValue(Node node) {
String value = node.getNodeValue();
if (node.hasChildNodes()) {

View File

@@ -27,6 +27,7 @@ import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory;
import org.dspace.authority.service.AuthorityValueService;
@@ -34,6 +35,7 @@ import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
import org.dspace.content.factory.ContentServiceFactory;
@@ -168,6 +170,9 @@ public class DSpaceCSV implements Serializable {
if ("collection".equals(element)) {
// Store the heading
headings.add(element);
} else if ("rowName".equals(element)) {
// Store the heading
headings.add(element);
} else if ("action".equals(element)) { // Store the action
// Store the heading
headings.add(element);
@@ -198,20 +203,24 @@ public class DSpaceCSV implements Serializable {
}
// Check that the scheme exists
MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema);
if (foundSchema == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException.SCHEMA,
columnCounter);
}
if (!StringUtils.equals(metadataSchema, MetadataSchemaEnum.RELATION.getName())) {
MetadataSchema foundSchema = metadataSchemaService.find(c, metadataSchema);
if (foundSchema == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException
.SCHEMA,
columnCounter);
}
// Check that the metadata element exists in the schema
MetadataField foundField = metadataFieldService
.findByElement(c, foundSchema, metadataElement, metadataQualifier);
if (foundField == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException.ELEMENT,
columnCounter);
// Check that the metadata element exists in the schema
MetadataField foundField = metadataFieldService
.findByElement(c, foundSchema, metadataElement, metadataQualifier);
if (foundField == null) {
throw new MetadataImportInvalidHeadingException(clean[0],
MetadataImportInvalidHeadingException
.ELEMENT,
columnCounter);
}
}
// Store the heading

View File

@@ -14,10 +14,14 @@ import java.io.InputStreamReader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
@@ -33,14 +37,25 @@ import org.dspace.authority.service.AuthorityValueService;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Entity;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.Relationship;
import org.dspace.content.RelationshipType;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.authority.Choices;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.EntityService;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
@@ -89,6 +104,45 @@ public class MetadataImport {
*/
protected static final String AC_PREFIX = "authority.controlled.";
/**
* Map of field:value to csv row number, used to resolve indirect entity target references.
*
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
*/
protected Map<String, Set<Integer>> csvRefMap = new HashMap<>();
/**
* Map of csv row number to UUID, used to resolve indirect entity target references.
*
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
*/
protected HashMap<Integer, UUID> csvRowMap = new HashMap<>();
/**
* Map of UUIDs to their entity types.
*
* @see #populateRefAndRowMap(DSpaceCSVLine, UUID)
*/
protected static HashMap<UUID, String> entityTypeMap = new HashMap<>();
/**
* Map of UUIDs to their relations that are referenced within any import with their referers.
*
* @see #populateEntityRelationMap(String, String, String)
*/
protected static HashMap<String, HashMap<String, ArrayList<String>>> entityRelationMap = new HashMap<>();
/**
* Collection of errors generated during relation validation process.
*/
protected ArrayList<String> relationValidationErrors = new ArrayList<>();
/**
* Counter of rows proccssed in a CSV.
*/
protected Integer rowCount = 1;
/**
* Logger
*/
@@ -101,6 +155,10 @@ public class MetadataImport {
protected final CollectionService collectionService;
protected final HandleService handleService;
protected final WorkspaceItemService workspaceItemService;
protected final RelationshipTypeService relationshipTypeService;
protected final RelationshipService relationshipService;
protected final EntityTypeService entityTypeService;
protected final EntityService entityService;
/**
* Create an instance of the metadata importer. Requires a context and an array of CSV lines
@@ -120,6 +178,10 @@ public class MetadataImport {
handleService = HandleServiceFactory.getInstance().getHandleService();
authorityValueService = AuthorityServiceFactory.getInstance().getAuthorityValueService();
workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
entityService = ContentServiceFactory.getInstance().getEntityService();
}
/**
@@ -131,7 +193,7 @@ public class MetadataImport {
* @param workflowNotify If the workflows should be used, whether to send notifications or not
* @param useTemplate Use collection template if create new item
* @return An array of BulkEditChange elements representing the items that have changed
* @throws MetadataImportException if something goes wrong
* @throws MetadataImportException if something goes wrong
*/
public List<BulkEditChange> runImport(boolean change,
boolean useWorkflow,
@@ -146,7 +208,11 @@ public class MetadataImport {
c.setMode(Context.Mode.BATCH_EDIT);
// Process each change
rowCount = 1;
for (DSpaceCSVLine line : toImport) {
// Resolve target references to other items
populateRefAndRowMap(line, line.getID());
line = resolveEntityRefs(line);
// Get the DSpace item to compare with
UUID id = line.getID();
@@ -159,7 +225,7 @@ public class MetadataImport {
WorkflowItem wfItem = null;
Item item = null;
// Is this a new item?
// Is this an existing item?
if (id != null) {
// Get the item
item = itemService.find(c, id);
@@ -196,9 +262,8 @@ public class MetadataImport {
}
}
}
// Compare
compare(item, fromCSV, change, md, whatHasChanged, line);
compareAndUpdate(item, fromCSV, change, md, whatHasChanged, line);
}
}
@@ -259,7 +324,7 @@ public class MetadataImport {
BulkEditChange whatHasChanged = new BulkEditChange();
for (String md : line.keys()) {
// Get the values we already have
if (!"id".equals(md)) {
if (!"id".equals(md) && !"rowName".equals(md)) {
// Get the values from the CSV
String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]);
@@ -337,14 +402,23 @@ public class MetadataImport {
// Add the metadata to the item
for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
itemService.addMetadata(c, item, dcv.getSchema(),
dcv.getElement(),
dcv.getQualifier(),
dcv.getLanguage(),
dcv.getValue(),
dcv.getAuthority(),
dcv.getConfidence());
if (!StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
itemService.addMetadata(c, item, dcv.getSchema(),
dcv.getElement(),
dcv.getQualifier(),
dcv.getLanguage(),
dcv.getValue(),
dcv.getAuthority(),
dcv.getConfidence());
}
}
//Add relations after all metadata has been processed
for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
addRelationship(c, item, dcv.getElement(), dcv.getValue());
}
}
// Should the workflow be used?
if (useWorkflow) {
@@ -368,8 +442,6 @@ public class MetadataImport {
}
}
// Commit changes to the object
// c.commit();
whatHasChanged.setItem(item);
}
@@ -383,6 +455,9 @@ public class MetadataImport {
c.uncacheEntity(wfItem);
c.uncacheEntity(item);
}
populateRefAndRowMap(line, item == null ? null : item.getID());
// keep track of current rows processed
rowCount++;
}
c.setMode(originalMode);
@@ -393,11 +468,14 @@ public class MetadataImport {
}
// Return the changes
if (!change ) {
validateExpressedRelations();
}
return changes;
}
/**
* Compare an item metadata with a line from CSV, and optionally update the item
* Compare an item metadata with a line from CSV, and optionally update the item.
*
* @param item The current item metadata
* @param fromCSV The metadata from the CSV file
@@ -407,10 +485,11 @@ public class MetadataImport {
* @param line line in CSV file
* @throws SQLException if there is a problem accessing a Collection from the database, from its handle
* @throws AuthorizeException if there is an authorization problem with permissions
* @throws MetadataImportException custom exception for error handling within metadataimport
*/
protected void compare(Item item, String[] fromCSV, boolean change,
String md, BulkEditChange changes, DSpaceCSVLine line)
throws SQLException, AuthorizeException {
protected void compareAndUpdate(Item item, String[] fromCSV, boolean change,
String md, BulkEditChange changes, DSpaceCSVLine line)
throws SQLException, AuthorizeException, MetadataImportException {
// Log what metadata element we're looking at
String all = "";
for (String part : fromCSV) {
@@ -420,8 +499,8 @@ public class MetadataImport {
log.debug(LogManager.getHeader(c, "metadata_import",
"item_id=" + item.getID() + ",fromCSV=" + all));
// Don't compare collections or actions
if (("collection".equals(md)) || ("action".equals(md))) {
// Don't compare collections or actions or rowNames
if (("collection".equals(md)) || ("action".equals(md)) || ("rowName".equals(md))) {
return;
}
@@ -583,13 +662,131 @@ public class MetadataImport {
}
}
// Set those values
itemService.clearMetadata(c, item, schema, element, qualifier, language);
itemService.addMetadata(c, item, schema, element, qualifier, language, values, authorities, confidences);
itemService.update(c, item);
if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName())) {
List<RelationshipType> relationshipTypeList = relationshipTypeService
.findByLeftwardOrRightwardTypeName(c, element);
for (RelationshipType relationshipType : relationshipTypeList) {
for (Relationship relationship : relationshipService
.findByItemAndRelationshipType(c, item, relationshipType)) {
relationshipService.delete(c, relationship);
relationshipService.update(c, relationship);
}
}
addRelationships(c, item, element, values);
} else {
itemService.clearMetadata(c, item, schema, element, qualifier, language);
itemService.addMetadata(c, item, schema, element, qualifier,
language, values, authorities, confidences);
itemService.update(c, item);
}
}
}
/**
*
* Adds multiple relationships with a matching typeName to an item.
*
* @param c The relevant DSpace context
* @param item The item to which this metadatavalue belongs to
* @param typeName The element for the metadatavalue
* @param values to iterate over
* @throws SQLException If something goes wrong
* @throws AuthorizeException If something goes wrong
*/
private void addRelationships(Context c, Item item, String typeName, List<String> values)
throws SQLException, AuthorizeException,
MetadataImportException {
for (String value : values) {
addRelationship(c, item, typeName, value);
}
}
/**
* Gets an existing entity from a target reference.
*
* @param context the context to use.
* @param targetReference the target reference which may be a UUID, metadata reference, or rowName reference.
* @return the entity, which is guaranteed to exist.
* @throws MetadataImportException if the target reference is badly formed or refers to a non-existing item.
*/
private Entity getEntity(Context context, String targetReference) throws MetadataImportException {
Entity entity = null;
UUID uuid = resolveEntityRef(context, targetReference);
// At this point, we have a uuid, so we can get an entity
try {
entity = entityService.findByItemId(context, uuid);
if (entity.getItem() == null) {
throw new IllegalArgumentException("No item found in repository with uuid: " + uuid);
}
return entity;
} catch (SQLException sqle) {
throw new MetadataImportException("Unable to find entity using reference: " + targetReference, sqle);
}
}
/**
*
* Creates a relationship for the given item
*
* @param c The relevant DSpace context
* @param item The item that the relationships will be made for
* @param typeName The relationship typeName
* @param value The value for the relationship
* @throws SQLException If something goes wrong
* @throws AuthorizeException If something goes wrong
*/
private void addRelationship(Context c, Item item, String typeName, String value)
throws SQLException, AuthorizeException, MetadataImportException {
if (value.isEmpty()) {
return;
}
boolean left = false;
// Get entity from target reference
Entity relationEntity = getEntity(c, value);
// Get relationship type of entity and item
String relationEntityRelationshipType = itemService.getMetadata(relationEntity.getItem(),
"relationship", "type",
null, Item.ANY).get(0).getValue();
String itemRelationshipType = itemService.getMetadata(item, "relationship", "type",
null, Item.ANY).get(0).getValue();
// Get the correct RelationshipType based on typeName
List<RelationshipType> relType = relationshipTypeService.findByLeftwardOrRightwardTypeName(c, typeName);
RelationshipType foundRelationshipType = matchRelationshipType(relType,
relationEntityRelationshipType, itemRelationshipType, typeName);
if (foundRelationshipType == null) {
throw new MetadataImportException("Error on CSV row " + rowCount + ":" + "\n" +
"No Relationship type found for:\n" +
"Target type: " + relationEntityRelationshipType + "\n" +
"Origin referer type: " + itemRelationshipType + "\n" +
"with typeName: " + typeName);
}
if (foundRelationshipType.getLeftwardType().equalsIgnoreCase(typeName)) {
left = true;
}
// Placeholder items for relation placing
Item leftItem = null;
Item rightItem = null;
if (left) {
leftItem = item;
rightItem = relationEntity.getItem();
} else {
leftItem = relationEntity.getItem();
rightItem = item;
}
// Create the relationship
int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem);
int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem);
Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem,
foundRelationshipType, leftPlace, rightPlace);
relationshipService.update(c, persistedRelationship);
}
/**
* Compare changes between an items owning collection and mapped collections
* and what is in the CSV file
@@ -1078,6 +1275,8 @@ public class MetadataImport {
"notify - when adding new items using a workflow, send notification emails");
options.addOption("t", "template", false,
"template - when adding new items, use the collection template (if it exists)");
options.addOption("v", "validate-only", false,
"validate - just validate the csv, don't run the import");
options.addOption("h", "help", false, "help");
// Parse the command line arguments
@@ -1175,7 +1374,9 @@ public class MetadataImport {
MetadataImport importer = new MetadataImport(c, csv);
List<BulkEditChange> changes;
if (!line.hasOption('s')) {
boolean validateOnly = line.hasOption('v');
if (!line.hasOption('s') || validateOnly) {
// See what has changed
try {
changes = importer.runImport(false, useWorkflow, workflowNotify, useTemplate);
@@ -1189,7 +1390,7 @@ public class MetadataImport {
int changeCounter = displayChanges(changes, false);
// If there were changes, ask if we should execute them
if (changeCounter > 0) {
if (!validateOnly && changeCounter > 0) {
try {
// Ask the user if they want to make the changes
System.out.println("\n" + changeCounter + " item(s) will be changed\n");
@@ -1214,7 +1415,7 @@ public class MetadataImport {
try {
// If required, make the change
if (change) {
if (change && !validateOnly) {
try {
// Make the changes
changes = importer.runImport(true, useWorkflow, workflowNotify, useTemplate);
@@ -1226,9 +1427,6 @@ public class MetadataImport {
// Display the changes
displayChanges(changes, true);
// Commit the change to the DB
// c.commit();
}
// Finsh off and tidy up
@@ -1241,4 +1439,418 @@ public class MetadataImport {
System.exit(1);
}
}
/**
* Gets a copy of the given csv line with all entity target references resolved to UUID strings.
* Keys being iterated over represent metadatafields or special columns to be processed.
*
* @param line the csv line to process.
* @return a copy, with all references resolved.
* @throws MetadataImportException if there is an error resolving any entity target reference.
*/
public DSpaceCSVLine resolveEntityRefs(DSpaceCSVLine line) throws MetadataImportException {
DSpaceCSVLine newLine = new DSpaceCSVLine(line.getID());
UUID originId = evaluateOriginId(line.getID());
for (String key : line.keys()) {
// If a key represents a relation field attempt to resolve the target reference from the csvRefMap
if (key.split("\\.")[0].equalsIgnoreCase("relation")) {
if (line.get(key).size() > 0) {
for (String val : line.get(key)) {
// Attempt to resolve the relation target reference
// These can be a UUID, metadata target reference or rowName target reference
String uuid = resolveEntityRef(c, val).toString();
newLine.add(key, uuid);
//Entity refs have been resolved / placeholdered
//Populate the EntityRelationMap
populateEntityRelationMap(uuid, key, originId.toString());
}
}
} else {
if (line.get(key).size() > 1) {
for (String value : line.get(key)) {
newLine.add(key, value);
}
} else {
if (line.get(key).size() > 0) {
newLine.add(key, line.get(key).get(0));
}
}
}
}
return newLine;
}
/**
* Populate the entityRelationMap with all target references and it's asscoiated typeNames
* to their respective origins
*
* @param refUUID the target reference UUID for the relation
* @param relationField the field of the typeNames to relate from
*/
private void populateEntityRelationMap(String refUUID, String relationField, String originId) {
HashMap<String, ArrayList<String>> typeNames = null;
if (entityRelationMap.get(refUUID) == null) {
typeNames = new HashMap<>();
ArrayList<String> originIds = new ArrayList<>();
originIds.add(originId);
typeNames.put(relationField, originIds);
entityRelationMap.put(refUUID, typeNames);
} else {
typeNames = entityRelationMap.get(refUUID);
if (typeNames.get(relationField) == null) {
ArrayList<String> originIds = new ArrayList<>();
originIds.add(originId);
typeNames.put(relationField, originIds);
} else {
ArrayList<String> originIds = typeNames.get(relationField);
originIds.add(originId);
typeNames.put(relationField, originIds);
}
entityRelationMap.put(refUUID, typeNames);
}
}
/**
* Populates the csvRefMap, csvRowMap, and entityTypeMap for the given csv line.
*
* The csvRefMap is an index that keeps track of which rows have a specific value for
* a specific metadata field or the special "rowName" column. This is used to help resolve indirect
* entity target references in the same CSV.
*
* The csvRowMap is a row number to UUID map, and contains an entry for every row that has
* been processed so far which has a known (minted) UUID for its item. This is used to help complete
* the resolution after the row number has been determined.
*
* @param line the csv line.
* @param uuid the uuid of the item, which may be null if it has not been minted yet.
*/
private void populateRefAndRowMap(DSpaceCSVLine line, @Nullable UUID uuid) {
if (uuid != null) {
csvRowMap.put(rowCount, uuid);
} else {
csvRowMap.put(rowCount, new UUID(0, rowCount));
}
for (String key : line.keys()) {
if (key.contains(".") && !key.split("\\.")[0].equalsIgnoreCase("relation") ||
key.equalsIgnoreCase("rowName")) {
for (String value : line.get(key)) {
String valueKey = key + ":" + value;
Set<Integer> rowNums = csvRefMap.get(valueKey);
if (rowNums == null) {
rowNums = new HashSet<>();
csvRefMap.put(valueKey, rowNums);
}
rowNums.add(rowCount);
}
}
//Populate entityTypeMap
if (key.equalsIgnoreCase("relationship.type") && line.get(key).size() > 0) {
if (uuid == null) {
entityTypeMap.put(new UUID(0, rowCount), line.get(key).get(0));
} else {
entityTypeMap.put(uuid, line.get(key).get(0));
}
}
}
}
/**
* Gets the UUID of the item indicated by the given target reference,
* which may be a direct UUID string, a row reference
* of the form rowName:VALUE, or a metadata value reference of the form schema.element[.qualifier]:VALUE.
*
* The reference may refer to a previously-processed item in the CSV or an item in the database.
*
* @param context the context to use.
* @param reference the target reference which may be a UUID, metadata reference, or rowName reference.
* @return the uuid.
* @throws MetadataImportException if the target reference is malformed or ambiguous (refers to multiple items).
*/
private UUID resolveEntityRef(Context context, String reference) throws MetadataImportException {
// value reference
UUID uuid = null;
if (!reference.contains(":")) {
// assume it's a UUID
try {
return UUID.fromString(reference);
} catch (IllegalArgumentException e) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Not a UUID or indirect entity reference: '" + reference + "'");
}
} else if (!reference.startsWith("rowName:") ) { // Not a rowName ref; so it's a metadata value reference
MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
MetadataFieldService metadataFieldService =
ContentServiceFactory.getInstance().getMetadataFieldService();
int i = reference.indexOf(":");
String mfValue = reference.substring(i + 1);
String mf[] = reference.substring(0, i).split("\\.");
if (mf.length < 2) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Bad metadata field in reference: '" + reference
+ "' (expected syntax is schema.element[.qualifier])");
}
String schema = mf[0];
String element = mf[1];
String qualifier = mf.length == 2 ? null : mf[2];
try {
MetadataField mfo = metadataFieldService.findByElement(context, schema, element, qualifier);
Iterator<MetadataValue> mdv = metadataValueService.findByFieldAndValue(context, mfo, mfValue);
if (mdv.hasNext()) {
MetadataValue mdvVal = mdv.next();
uuid = mdvVal.getDSpaceObject().getID();
if (mdv.hasNext()) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Ambiguous reference; multiple matches in db: " + reference);
}
}
} catch (SQLException e) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Error looking up item by metadata reference: " + reference, e);
}
}
// Lookup UUIDs that may have already been processed into the csvRefMap
// See populateRefAndRowMap() for how the csvRefMap is populated
// See getMatchingCSVUUIDs() for how the reference param is sourced from the csvRefMap
Set<UUID> csvUUIDs = getMatchingCSVUUIDs(reference);
if (csvUUIDs.size() > 1) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Ambiguous reference; multiple matches in csv: " + reference);
} else if (csvUUIDs.size() == 1) {
UUID csvUUID = csvUUIDs.iterator().next();
if (csvUUID.equals(uuid)) {
return uuid; // one match from csv and db (same item)
} else if (uuid != null) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"Ambiguous reference; multiple matches in db and csv: " + reference);
} else {
return csvUUID; // one match from csv
}
} else { // size == 0; the reference does not exist throw an error
if (uuid == null) {
throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
"No matches found for reference: " + reference
+ "\nKeep in mind you can only reference entries that are listed before " +
"this one within the CSV.");
} else {
return uuid; // one match from db
}
}
}
/**
* Gets the set of matching lines as UUIDs that have already been processed given a metadata value.
*
* @param mdValueRef the metadataValue reference to search for.
* @return the set of matching lines as UUIDs.
*/
private Set<UUID> getMatchingCSVUUIDs(String mdValueRef) {
Set<UUID> set = new HashSet<>();
if (csvRefMap.containsKey(mdValueRef)) {
for (Integer rowNum : csvRefMap.get(mdValueRef)) {
set.add(getUUIDForRow(rowNum));
}
}
return set;
}
/**
* Gets the UUID of the item of a given row in the CSV, if it has been minted.
* If the UUID has not yet been minted, gets a UUID representation of the row
* (a UUID whose numeric value equals the row number).
*
* @param rowNum the row number.
* @return the UUID of the item
*/
private UUID getUUIDForRow(int rowNum) {
if (csvRowMap.containsKey(rowNum)) {
return csvRowMap.get(rowNum);
} else {
return new UUID(0, rowNum);
}
}
/**
* Return a UUID of the origin in process or a placeholder for the origin to be evaluated later
*
* @param originId UUID of the origin
* @return the UUID of the item or UUID placeholder
*/
private UUID evaluateOriginId(@Nullable UUID originId) {
if (originId != null) {
return originId;
} else {
return new UUID(0, rowCount);
}
}
/**
* Validate every relation modification expressed in the CSV.
*
*/
private void validateExpressedRelations() throws MetadataImportException {
for (String targetUUID : entityRelationMap.keySet()) {
String targetType = null;
try {
// Get the type of reference. Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(targetUUID)) != null) {
targetType = entityTypeService.
findByEntityType(c, entityTypeMap.get(UUID.fromString(targetUUID))).getLabel();
} else {
// Target item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived
Item targetItem = null;
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
targetItem = itemService.find(c, UUID.fromString(targetUUID));
List<MetadataValue> relTypes = itemService.
getMetadata(targetItem, "relationship", "type", null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
targetType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
} else {
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
targetUUID);
}
} else {
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
targetUUID);
}
}
if (targetType == null) {
continue;
}
// Get typeNames for each origin referer of this target.
for (String typeName : entityRelationMap.get(targetUUID).keySet()) {
// Resolve Entity Type for each origin referer.
for (String originRefererUUID : entityRelationMap.get(targetUUID).get(typeName)) {
// Evaluate row number for origin referer.
String originRow = "N/A";
if (csvRowMap.containsValue(UUID.fromString(originRefererUUID))) {
for (int key : csvRowMap.keySet()) {
if (csvRowMap.get(key).toString().equalsIgnoreCase(originRefererUUID)) {
originRow = key + "";
break;
}
}
}
String originType = "";
// Validate target type and origin type pairing with typeName or add to errors.
// Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(originRefererUUID)) != null) {
originType = entityTypeMap.get(UUID.fromString(originRefererUUID));
validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
} else {
// Origin item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived.
Item originItem = null;
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
originItem = itemService.find(c, UUID.fromString(originRefererUUID));
List<MetadataValue> relTypes = itemService.
getMetadata(originItem, "relationship", "type", null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
originType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
} else {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
"Cannot resolve Entity type for reference: "
+ originRefererUUID);
}
} else {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
"Cannot resolve Entity type for reference: "
+ originRefererUUID + " in row: " + originRow );
}
}
}
}
} catch (SQLException sqle) {
throw new MetadataImportException("Error interacting with database!", sqle);
}
} // If relationValidationErrors is empty all described relationships are valid.
if (!relationValidationErrors.isEmpty()) {
StringBuilder errors = new StringBuilder();
for (String error : relationValidationErrors) {
errors.append(error + "\n");
}
throw new MetadataImportException("Error validating relationships: \n" + errors);
}
}
/**
* Generates a list of potenital Relationship Types given a typeName and attempts to match the given
* targetType and originType to a Relationship Type in the list.
*
* @param targetType entity type of target.
* @param originType entity type of origin referer.
* @param typeName left or right typeName of the respective Relationship.
* @return the UUID of the item.
*/
private void validateTypesByTypeByTypeName(String targetType, String originType, String typeName, String originRow)
throws MetadataImportException {
try {
RelationshipType foundRelationshipType = null;
List<RelationshipType> relationshipTypeList = relationshipTypeService.
findByLeftwardOrRightwardTypeName(c, typeName.split("\\.")[1]);
// Validate described relationship form the CSV.
foundRelationshipType = matchRelationshipType(relationshipTypeList, targetType, originType, typeName);
if (foundRelationshipType == null) {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
"No Relationship type found for:\n" +
"Target type: " + targetType + "\n" +
"Origin referer type: " + originType + "\n" +
"with typeName: " + typeName + " for type: " + originType);
}
} catch (SQLException sqle) {
throw new MetadataImportException("Error interacting with database!", sqle);
}
}
/**
* Matches two Entity types to a Relationship Type from a set of Relationship Types.
*
* @param relTypes set of Relationship Types.
* @param targetType entity type of target.
* @param originType entity type of origin referer.
* @return null or matched Relationship Type.
*/
private RelationshipType matchRelationshipType(List<RelationshipType> relTypes,
String targetType, String originType, String originTypeName) {
RelationshipType foundRelationshipType = null;
if (originTypeName.split("\\.").length > 1) {
originTypeName = originTypeName.split("\\.")[1];
}
for (RelationshipType relationshipType : relTypes) {
// Is origin type leftward or righward
boolean isLeft = false;
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType)) {
isLeft = true;
}
if (isLeft) {
// Validate typeName reference
if (!relationshipType.getLeftwardType().equalsIgnoreCase(originTypeName)) {
continue;
}
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) &&
relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) {
foundRelationshipType = relationshipType;
}
} else {
if (!relationshipType.getRightwardType().equalsIgnoreCase(originTypeName)) {
continue;
}
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) &&
relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) {
foundRelationshipType = relationshipType;
}
}
}
return foundRelationshipType;
}
}

View File

@@ -272,9 +272,8 @@ public class Harvest {
targetCollection = (Collection) dso;
}
} else {
// not a handle, try and treat it as an integer collection database ID
System.out.println("Looking up by id: " + collectionID + ", parsed as '" + Integer
.parseInt(collectionID) + "', " + "in context: " + context);
// not a handle, try and treat it as an collection database UUID
System.out.println("Looking up by UUID: " + collectionID + ", " + "in context: " + context);
targetCollection = collectionService.find(context, UUID.fromString(collectionID));
}
}
@@ -460,7 +459,7 @@ public class Harvest {
List<String> errors;
System.out.print("Testing basic PMH access: ");
errors = OAIHarvester.verifyOAIharvester(server, set,
errors = harvestedCollectionService.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", false);
if (errors.isEmpty()) {
System.out.println("OK");
@@ -471,7 +470,7 @@ public class Harvest {
}
System.out.print("Testing ORE support: ");
errors = OAIHarvester.verifyOAIharvester(server, set,
errors = harvestedCollectionService.verifyOAIharvester(server, set,
(null != metadataFormat) ? metadataFormat : "dc", true);
if (errors.isEmpty()) {
System.out.println("OK");

View File

@@ -42,7 +42,7 @@ import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.CommunityService;
@@ -214,7 +214,7 @@ public class ItemExportServiceImpl implements ItemExportService {
protected void writeMetadata(Context c, String schema, Item i,
File destDir, boolean migrate) throws Exception {
String filename;
if (schema.equals(MetadataSchema.DC_SCHEMA)) {
if (schema.equals(MetadataSchemaEnum.DC.getName())) {
filename = "dublin_core.xml";
} else {
filename = "metadata_" + schema + ".xml";

View File

@@ -74,6 +74,7 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
@@ -677,7 +678,7 @@ public class ItemImportServiceImpl implements ItemImportService, InitializingBea
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem(
"schema");
if (schemaAttr == null) {
schema = MetadataSchema.DC_SCHEMA;
schema = MetadataSchemaEnum.DC.getName();
} else {
schema = schemaAttr.getNodeValue();
}

View File

@@ -34,6 +34,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
@@ -189,7 +190,7 @@ public class MetadataUtilities {
NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core");
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema");
if (schemaAttr == null) {
schema = MetadataSchema.DC_SCHEMA;
schema = MetadataSchemaEnum.DC.getName();
} else {
schema = schemaAttr.getNodeValue();
}

View File

@@ -13,6 +13,12 @@ import java.lang.reflect.Method;
import java.util.List;
import java.util.TreeMap;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService;
@@ -27,6 +33,9 @@ import org.jdom.input.SAXBuilder;
* @author Mark Diggory
*/
public class ScriptLauncher {
private static final Logger log = Logger.getLogger(ScriptLauncher.class);
/**
* The service manager kernel
*/
@@ -76,8 +85,9 @@ public class ScriptLauncher {
}
// Look up command in the configuration, and execute.
int status;
status = runOneCommand(commandConfigs, args);
CommandLineDSpaceRunnableHandler commandLineDSpaceRunnableHandler = new CommandLineDSpaceRunnableHandler();
int status = handleScript(args, commandConfigs, commandLineDSpaceRunnableHandler, kernelImpl);
// Destroy the service kernel if it is still alive
if (kernelImpl != null) {
@@ -86,6 +96,50 @@ public class ScriptLauncher {
}
System.exit(status);
}
/**
* This method will take the arguments from a commandline input and it'll find the script that the first argument
* refers to and it'll execute this script.
* It can return a 1 or a 0 depending on whether the script failed or passed respectively
* @param args The arguments for the script and the script as first one in the array
* @param commandConfigs The Document
* @param dSpaceRunnableHandler The DSpaceRunnableHandler for this execution
* @param kernelImpl The relevant DSpaceKernelImpl
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
public static int handleScript(String[] args, Document commandConfigs,
DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceKernelImpl kernelImpl) {
int status;
DSpaceRunnable script = ScriptServiceFactory.getInstance().getScriptService().getScriptForName(args[0]);
if (script != null) {
status = executeScript(args, dSpaceRunnableHandler, script);
} else {
status = runOneCommand(commandConfigs, args, kernelImpl);
}
return status;
}
/**
* This method will simply execute the script
* @param args The arguments of the script with the script name as first place in the array
* @param dSpaceRunnableHandler The relevant DSpaceRunnableHandler
* @param script The script to be executed
* @return A 1 or 0 depending on whether the script failed or passed respectively
*/
private static int executeScript(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceRunnable script) {
try {
script.initialize(args, dSpaceRunnableHandler);
script.run();
return 0;
} catch (ParseException e) {
script.printHelp();
e.printStackTrace();
return 1;
}
}
protected static int runOneCommand(Document commandConfigs, String[] args) {
@@ -98,7 +152,7 @@ public class ScriptLauncher {
* @param commandConfigs Document
* @param args the command line arguments given
*/
public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
protected static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
String request = args[0];
Element root = commandConfigs.getRootElement();
List<Element> commands = root.getChildren("command");

View File

@@ -11,7 +11,9 @@ import java.awt.image.BufferedImage;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.apache.logging.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.dspace.content.Item;
@@ -26,6 +28,8 @@ import org.dspace.content.Item;
* @author Jason Sherman jsherman@usao.edu
*/
public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFormats {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(PDFBoxThumbnail.class);
@Override
public String getFilteredName(String oldFilename) {
return oldFilename + ".jpg";
@@ -65,12 +69,19 @@ public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFor
@Override
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
throws Exception {
PDDocument doc = PDDocument.load(source);
PDFRenderer renderer = new PDFRenderer(doc);
BufferedImage buf = renderer.renderImage(0);
// ImageIO.write(buf, "PNG", new File("custom-render.png"));
doc.close();
BufferedImage buf;
// Render the page image.
try ( PDDocument doc = PDDocument.load(source); ) {
PDFRenderer renderer = new PDFRenderer(doc);
buf = renderer.renderImage(0);
} catch (InvalidPasswordException ex) {
log.error("PDF is encrypted. Cannot create thumbnail (item: {})",
() -> currentItem.getHandle());
return null;
}
// Generate thumbnail derivative and return as IO stream.
JPEGFilter jpegFilter = new JPEGFilter();
return jpegFilter.getThumb(currentItem, buf, verbose);
}

View File

@@ -18,6 +18,7 @@ import java.io.Writer;
import org.apache.logging.log4j.Logger;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
import org.apache.pdfbox.text.PDFTextStripper;
import org.dspace.content.Item;
import org.dspace.core.ConfigurationManager;
@@ -95,6 +96,10 @@ public class PDFFilter extends MediaFilter {
try {
pdfDoc = PDDocument.load(source);
pts.writeText(pdfDoc, writer);
} catch (InvalidPasswordException ex) {
log.error("PDF is encrypted. Cannot extract text (item: {})",
() -> currentItem.getHandle());
return null;
} finally {
try {
if (pdfDoc != null) {

View File

@@ -78,7 +78,7 @@ public class RequestItem implements ReloadableEntity<Integer> {
private Date request_date = null;
@Column(name = "accept_request")
private Boolean accept_request = null;
private boolean accept_request;
/**
* Protected constructor, create object using:
@@ -88,6 +88,7 @@ public class RequestItem implements ReloadableEntity<Integer> {
protected RequestItem() {
}
@Override
public Integer getID() {
return requestitem_id;
}

View File

@@ -15,6 +15,9 @@ import java.util.List;
* @author Andrea Bollini
*/
public class SHERPAPublisher {
private String id;
private String name;
private String alias;
@@ -49,7 +52,7 @@ public class SHERPAPublisher {
private String dateupdated;
public SHERPAPublisher(String name, String alias, String homeurl,
public SHERPAPublisher(String id, String name, String alias, String homeurl,
String prearchiving, List<String> prerestriction,
String postarchiving, List<String> postrestriction,
String pubarchiving, List<String> pubrestriction,
@@ -57,6 +60,8 @@ public class SHERPAPublisher {
String paidaccessname, String paidaccessnotes,
List<String[]> copyright, String romeocolour, String datedded,
String dateupdated) {
this.id = id;
this.name = name;
this.alias = alias;
@@ -160,4 +165,11 @@ public class SHERPAPublisher {
return dateupdated;
}
/**
* Generic getter for the id
* @return the id value of this SHERPAPublisher
*/
public String getId() {
return id;
}
}

View File

@@ -14,6 +14,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -24,7 +25,9 @@ import org.w3c.dom.Element;
* @author Andrea Bollini
*/
public class SHERPAResponse {
private boolean error;
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPAResponse.class);
private int numHits;
private String message;
@@ -57,12 +60,13 @@ public class SHERPAResponse {
Element publishersElement = XMLUtils.getSingleElement(xmlRoot,
"publishers");
message = XMLUtils.getElementValue(headersElement, "message");
if (StringUtils.isNotBlank(message)) {
error = true;
return;
String numhitsString = XMLUtils.getElementValue(headersElement, "numhits");
if (StringUtils.isNotBlank(numhitsString)) {
numHits = Integer.parseInt(numhitsString);
} else {
numHits = 0;
}
message = XMLUtils.getElementValue(headersElement, "message");
license = XMLUtils.getElementValue(headersElement, "license");
licenseURL = XMLUtils.getElementValue(headersElement, "licenseurl");
@@ -112,9 +116,8 @@ public class SHERPAResponse {
Element copyrightlinksElement = XMLUtils.getSingleElement(
publisherElement, "copyrightlinks");
publishers
.add(new SHERPAPublisher(XMLUtils.getElementValue(
.add(new SHERPAPublisher(publisherElement.getAttribute("id"), XMLUtils.getElementValue(
publisherElement, "name"),
XMLUtils.getElementValue(publisherElement,
"alias"), XMLUtils.getElementValue(
@@ -162,17 +165,12 @@ public class SHERPAResponse {
}
}
} catch (Exception e) {
error = true;
log.error("Error parsing SHERPA API Response", e);
}
}
public SHERPAResponse(String message) {
this.message = message;
this.error = true;
}
public boolean isError() {
return error;
}
public String getMessage() {
@@ -198,4 +196,8 @@ public class SHERPAResponse {
public List<SHERPAPublisher> getPublishers() {
return publishers;
}
public int getNumHits() {
return numHits;
}
}

View File

@@ -28,7 +28,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
@@ -763,9 +763,10 @@ public class ReportGenerator {
// build the referece
// FIXME: here we have blurred the line between content and presentation
// and it should probably be un-blurred
List<MetadataValue> title = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
List<MetadataValue> title = itemService.getMetadata(item, MetadataSchemaEnum.DC.getName(),
"title", null, Item.ANY);
List<MetadataValue> author = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "contributor", "author", Item.ANY);
StringBuffer authors = new StringBuffer();
if (author.size() > 0) {

View File

@@ -0,0 +1,58 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.app.util;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import org.dspace.core.Context;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.CachingService;
/**
* List all EhCache CacheManager and Cache instances.
*
* <p>This is a debugging tool, not used in the daily operation of DSpace.
* Just run it from the installed instance using
* {@code bin/dspace dsrun org.dspace.app.util.CacheSnooper}
* to check that the cache configuration is what you expect it to be,
* given your configuration.
*
* <p>This was created to prove a specific cache configuration patch,
* but I leave it here in the hope that it may be useful to others.
*
* @author Mark H. Wood <mwood@iupui.edu>
*/
public class CacheSnooper {
private CacheSnooper() { }
public static void main(String[] argv) {
// Ensure that the DSpace kernel is started.
DSpaceKernelImpl kernel = DSpaceKernelInit.getKernel(null);
// Ensure that the services cache manager is started.
CachingService serviceCaches = kernel.getServiceManager()
.getServiceByName(null, CachingService.class);
// Ensure that the database layer is started.
Context ctx = new Context();
// List those caches!
for (CacheManager manager : CacheManager.ALL_CACHE_MANAGERS) {
System.out.format("CacheManager: %s%n", manager);
for (String cacheName : manager.getCacheNames()) {
Cache cache = manager.getCache(cacheName);
System.out.format(" Cache: '%s'; maxHeap: %d; maxDisk: %d%n",
cacheName,
cache.getCacheConfiguration().getMaxEntriesLocalHeap(),
cache.getCacheConfiguration().getMaxEntriesLocalDisk());
}
}
}
}

View File

@@ -14,7 +14,7 @@ import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.commons.lang3.StringUtils;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.core.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -89,6 +89,11 @@ public class DCInput {
*/
private boolean repeatable = false;
/**
* should name-variants be used?
*/
private boolean nameVariants = false;
/**
* 'hint' text to display
*/
@@ -134,6 +139,12 @@ public class DCInput {
*/
private List<String> typeBind = null;
private boolean isRelationshipField = false;
private boolean isMetadataField = false;
private String relationshipType = null;
private String searchConfiguration = null;
private String filter;
/**
* The scope of the input sets, this restricts hidden metadata fields from
* view during workflow processing.
@@ -160,7 +171,7 @@ public class DCInput {
// Default the schema to dublin core
dcSchema = fieldMap.get("dc-schema");
if (dcSchema == null) {
dcSchema = MetadataSchema.DC_SCHEMA;
dcSchema = MetadataSchemaEnum.DC.getName();
}
//check if the input have a language tag
@@ -177,6 +188,9 @@ public class DCInput {
String repStr = fieldMap.get("repeatable");
repeatable = "true".equalsIgnoreCase(repStr)
|| "yes".equalsIgnoreCase(repStr);
String nameVariantsString = fieldMap.get("name-variants");
nameVariants = (StringUtils.isNotBlank(nameVariantsString)) ?
nameVariantsString.equalsIgnoreCase("true") : false;
label = fieldMap.get("label");
inputType = fieldMap.get("input-type");
// these types are list-controlled
@@ -206,6 +220,11 @@ public class DCInput {
}
}
style = fieldMap.get("style");
isRelationshipField = fieldMap.containsKey("relationship-type");
isMetadataField = fieldMap.containsKey("dc-schema");
relationshipType = fieldMap.get("relationship-type");
searchConfiguration = fieldMap.get("search-configuration");
filter = fieldMap.get("filter");
}
/**
@@ -258,6 +277,15 @@ public class DCInput {
return isRepeatable();
}
/**
* Get the nameVariants flag for this row
*
* @return the nameVariants flag
*/
public boolean areNameVariantsAllowed() {
return nameVariants;
}
/**
* Get the input type for this row
*
@@ -481,6 +509,18 @@ public class DCInput {
return Utils.standardize(this.getSchema(), this.getElement(), this.getQualifier(), ".");
}
public String getRelationshipType() {
return relationshipType;
}
public String getSearchConfiguration() {
return searchConfiguration;
}
public String getFilter() {
return filter;
}
public boolean isQualdropValue() {
if ("qualdrop_value".equals(getInputType())) {
return true;
@@ -505,4 +545,22 @@ public class DCInput {
return true;
}
/**
* Verify whether the current field contains an entity relationship
* This also implies a relationship type is defined for this field
* The field can contain both an entity relationship and a metadata field simultaneously
*/
public boolean isRelationshipField() {
return isRelationshipField;
}
/**
* Verify whether the current field contains a metadata field
* This also implies a field type is defined for this field
* The field can contain both an entity relationship and a metadata field simultaneously
*/
public boolean isMetadataField() {
return isMetadataField;
}
}

View File

@@ -21,7 +21,7 @@ import javax.xml.parsers.FactoryConfigurationError;
import org.apache.commons.lang3.StringUtils;
import org.dspace.content.Collection;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.core.Utils;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.w3c.dom.Document;
@@ -366,11 +366,15 @@ public class DCInputsReader {
metadataField += "." + qualifier;
}
}
// we omit the duplicate validation, allowing multiple
// fields definition for
// the same metadata and different visibility/type-bind
} else if (StringUtils.equalsIgnoreCase(npg.getNodeName(), "relation-field")) {
Map<String, String> relationField = new HashMap<>();
processField(formName, npg, relationField);
fields.add(relationField);
}
}
// sanity check number of fields
if (fields.size() < 1) {
@@ -396,19 +400,7 @@ public class DCInputsReader {
String value = getValue(nd);
field.put(tagName, value);
if (tagName.equals("input-type")) {
if (value.equals("dropdown")
|| value.equals("qualdrop_value")
|| value.equals("list")) {
String pairTypeName = getAttribute(nd, PAIR_TYPE_NAME);
if (pairTypeName == null) {
throw new SAXException("Form " + formName + ", field " +
field.get("dc-element") +
"." + field.get("dc-qualifier") +
" has no name attribute");
} else {
field.put(PAIR_TYPE_NAME, pairTypeName);
}
}
handleInputTypeTagName(formName, field, nd, value);
} else if (tagName.equals("vocabulary")) {
String closedVocabularyString = getAttribute(nd, "closed");
field.put("closedVocabulary", closedVocabularyString);
@@ -424,17 +416,30 @@ public class DCInputsReader {
field.put(PAIR_TYPE_NAME, pairTypeName);
}
}
} else if (StringUtils.equalsIgnoreCase(tagName, "linked-metadata-field")) {
for (int j = 0; j < nd.getChildNodes().getLength(); j ++) {
Node nestedNode = nd.getChildNodes().item(j);
String nestedTagName = nestedNode.getNodeName();
String nestedValue = getValue(nestedNode);
field.put(nestedTagName, nestedValue);
if (nestedTagName.equals("input-type")) {
handleInputTypeTagName(formName, field, nestedNode, nestedValue);
}
}
}
}
}
String missing = null;
if (field.get("dc-element") == null) {
String nodeName = n.getNodeName();
if (field.get("dc-element") == null &&
(nodeName.equals("field") || field.containsKey("linked-metadata-field"))) {
missing = "dc-element";
}
if (field.get("label") == null) {
missing = "label";
}
if (field.get("input-type") == null) {
if (field.get("input-type") == null &&
(nodeName.equals("field") || field.containsKey("linked-metadata-field"))) {
missing = "input-type";
}
if (missing != null) {
@@ -442,7 +447,7 @@ public class DCInputsReader {
throw new SAXException(msg);
}
String type = field.get("input-type");
if (type.equals("twobox") || type.equals("qualdrop_value")) {
if (StringUtils.isNotBlank(type) && (type.equals("twobox") || type.equals("qualdrop_value"))) {
String rpt = field.get("repeatable");
if ((rpt == null) ||
((!rpt.equalsIgnoreCase("yes")) &&
@@ -453,6 +458,23 @@ public class DCInputsReader {
}
}
private void handleInputTypeTagName(String formName, Map<String, String> field, Node nd, String value)
throws SAXException {
if (value.equals("dropdown")
|| value.equals("qualdrop_value")
|| value.equals("list")) {
String pairTypeName = getAttribute(nd, PAIR_TYPE_NAME);
if (pairTypeName == null) {
throw new SAXException("Form " + formName + ", field " +
field.get("dc-element") +
"." + field.get("dc-qualifier") +
" has no name attribute");
} else {
field.put(PAIR_TYPE_NAME, pairTypeName);
}
}
}
/**
* Check that this is the only field with the name dc-element.dc-qualifier
* If there is a duplicate, return an error message, else return null;
@@ -464,7 +486,7 @@ public class DCInputsReader {
String elem = field.get("dc-element");
String qual = field.get("dc-qualifier");
if ((schema == null) || (schema.equals(""))) {
schema = MetadataSchema.DC_SCHEMA;
schema = MetadataSchemaEnum.DC.getName();
}
String schemaTest;
@@ -474,7 +496,7 @@ public class DCInputsReader {
Map<String, String> fld = pg.get(j);
if ((fld.get("dc-schema") == null) ||
((fld.get("dc-schema")).equals(""))) {
schemaTest = MetadataSchema.DC_SCHEMA;
schemaTest = MetadataSchemaEnum.DC.getName();
} else {
schemaTest = fld.get("dc-schema");
}
@@ -584,9 +606,9 @@ public class DCInputsReader {
Map<String, String> fld = fields.get(i);
// verify reference in certain input types
String type = fld.get("input-type");
if (type.equals("dropdown")
if (StringUtils.isNotBlank(type) && (type.equals("dropdown")
|| type.equals("qualdrop_value")
|| type.equals("list")) {
|| type.equals("list"))) {
String pairsName = fld.get(PAIR_TYPE_NAME);
List<String> v = valuePairs.get(pairsName);
if (v == null) {

View File

@@ -0,0 +1,227 @@
/**
* 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.util;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.EntityType;
import org.dspace.content.RelationshipType;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.core.Context;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* This script is used to initialize the database with a set of relationshiptypes that are written
* in an xml file that is given to this script.
* This XML file needs to have a proper XML structure and needs to define the variables of the RelationshipType object
*/
public class InitializeEntities {
private final static Logger log = LogManager.getLogger();
private RelationshipTypeService relationshipTypeService;
private RelationshipService relationshipService;
private EntityTypeService entityTypeService;
private InitializeEntities() {
relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
}
/**
* The main method for this script
*
* @param argv The commandline arguments given with this command
* @throws SQLException If something goes wrong with the database
* @throws AuthorizeException If something goes wrong with permissions
* @throws ParseException If something goes wrong with the parsing
*/
public static void main(String[] argv) throws SQLException, AuthorizeException, ParseException {
InitializeEntities initializeEntities = new InitializeEntities();
CommandLineParser parser = new PosixParser();
Options options = createCommandLineOptions();
CommandLine line = parser.parse(options,argv);
String fileLocation = getFileLocationFromCommandLine(line);
checkHelpEntered(options, line);
initializeEntities.run(fileLocation);
}
private static void checkHelpEntered(Options options, CommandLine line) {
if (line.hasOption("h")) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("Intialize Entities", options);
System.exit(0);
}
}
private static String getFileLocationFromCommandLine(CommandLine line) {
String query = line.getOptionValue("f");
if (StringUtils.isEmpty(query)) {
System.out.println("No file location was entered");
log.info("No file location was entered");
System.exit(1);
}
return query;
}
protected static Options createCommandLineOptions() {
Options options = new Options();
options.addOption("f", "file", true, "the location for the file containing the xml data");
return options;
}
private void run(String fileLocation) throws SQLException, AuthorizeException {
Context context = new Context();
context.turnOffAuthorisationSystem();
this.parseXMLToRelations(context, fileLocation);
context.complete();
}
private void parseXMLToRelations(Context context, String fileLocation) throws AuthorizeException {
try {
File fXmlFile = new File(fileLocation);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = null;
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("type");
List<RelationshipType> relationshipTypes = new LinkedList<>();
for (int i = 0; i < nList.getLength(); i++) {
Node nNode = nList.item(i);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
String leftType = eElement.getElementsByTagName("leftType").item(0).getTextContent();
String rightType = eElement.getElementsByTagName("rightType").item(0).getTextContent();
String leftwardType = eElement.getElementsByTagName("leftwardType").item(0).getTextContent();
String rightwardType = eElement.getElementsByTagName("rightwardType").item(0).getTextContent();
NodeList leftCardinalityList = eElement.getElementsByTagName("leftCardinality");
NodeList rightCardinalityList = eElement.getElementsByTagName("rightCardinality");
String leftCardinalityMin = "";
String leftCardinalityMax = "";
String rightCardinalityMin = "";
String rightCardinalityMax = "";
for (int j = 0; j < leftCardinalityList.getLength(); j++) {
Node node = leftCardinalityList.item(j);
leftCardinalityMin = getString(leftCardinalityMin,(Element) node, "min");
leftCardinalityMax = getString(leftCardinalityMax,(Element) node, "max");
}
for (int j = 0; j < rightCardinalityList.getLength(); j++) {
Node node = rightCardinalityList.item(j);
rightCardinalityMin = getString(rightCardinalityMin,(Element) node, "min");
rightCardinalityMax = getString(rightCardinalityMax,(Element) node, "max");
}
populateRelationshipType(context, leftType, rightType, leftwardType, rightwardType,
leftCardinalityMin, leftCardinalityMax,
rightCardinalityMin, rightCardinalityMax);
}
}
} catch (ParserConfigurationException | SAXException | IOException | SQLException e) {
log.error("An error occurred while parsing the XML file to relations", e);
}
}
private String getString(String leftCardinalityMin,Element node, String minOrMax) {
if (node.getElementsByTagName(minOrMax).getLength() > 0) {
leftCardinalityMin = node.getElementsByTagName(minOrMax).item(0).getTextContent();
}
return leftCardinalityMin;
}
private void populateRelationshipType(Context context, String leftType, String rightType, String leftwardType,
String rightwardType, String leftCardinalityMin, String leftCardinalityMax,
String rightCardinalityMin, String rightCardinalityMax)
throws SQLException, AuthorizeException {
EntityType leftEntityType = entityTypeService.findByEntityType(context,leftType);
if (leftEntityType == null) {
leftEntityType = entityTypeService.create(context, leftType);
}
EntityType rightEntityType = entityTypeService.findByEntityType(context, rightType);
if (rightEntityType == null) {
rightEntityType = entityTypeService.create(context, rightType);
}
Integer leftCardinalityMinInteger;
Integer leftCardinalityMaxInteger;
Integer rightCardinalityMinInteger;
Integer rightCardinalityMaxInteger;
if (StringUtils.isNotBlank(leftCardinalityMin)) {
leftCardinalityMinInteger = Integer.parseInt(leftCardinalityMin);
} else {
leftCardinalityMinInteger = null;
}
if (StringUtils.isNotBlank(leftCardinalityMax)) {
leftCardinalityMaxInteger = Integer.parseInt(leftCardinalityMax);
} else {
leftCardinalityMaxInteger = null;
}
if (StringUtils.isNotBlank(rightCardinalityMin)) {
rightCardinalityMinInteger = Integer.parseInt(rightCardinalityMin);
} else {
rightCardinalityMinInteger = null;
}
if (StringUtils.isNotBlank(rightCardinalityMax)) {
rightCardinalityMaxInteger = Integer.parseInt(rightCardinalityMax);
} else {
rightCardinalityMaxInteger = null;
}
RelationshipType relationshipType = relationshipTypeService
.findbyTypesAndTypeName(context, leftEntityType, rightEntityType, leftwardType, rightwardType);
if (relationshipType == null) {
relationshipTypeService.create(context, leftEntityType, rightEntityType, leftwardType, rightwardType,
leftCardinalityMinInteger, leftCardinalityMaxInteger,
rightCardinalityMinInteger, rightCardinalityMaxInteger);
} else {
relationshipType.setLeftMinCardinality(leftCardinalityMinInteger);
relationshipType.setLeftMaxCardinality(leftCardinalityMaxInteger);
relationshipType.setRightMinCardinality(rightCardinalityMinInteger);
relationshipType.setRightMaxCardinality(rightCardinalityMaxInteger);
relationshipTypeService.update(context, relationshipType);
}
}
}

View File

@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.Logger;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
@@ -39,9 +40,9 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho
/**
* Non-Static CommonsHttpSolrServer for processing indexing events.
*/
protected HttpSolrClient solr = null;
protected SolrClient solr = null;
protected HttpSolrClient getSolr()
protected SolrClient getSolr()
throws MalformedURLException, SolrServerException, IOException {
if (solr == null) {
@@ -49,12 +50,14 @@ public class AuthoritySolrServiceImpl implements AuthorityIndexingService, Autho
log.debug("Solr authority URL: " + solrService);
solr = new HttpSolrClient.Builder(solrService).build();
solr.setBaseURL(solrService);
HttpSolrClient solrServer = new HttpSolrClient.Builder(solrService).build();
solrServer.setBaseURL(solrService);
SolrQuery solrQuery = new SolrQuery().setQuery("*:*");
solr.query(solrQuery);
solrServer.query(solrQuery);
solr = solrServer;
}
return solr;

View File

@@ -8,6 +8,7 @@
package org.dspace.authority;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@@ -23,6 +24,7 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Context;
import org.dspace.util.SolrUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
@@ -34,8 +36,6 @@ import org.joda.time.format.ISODateTimeFormat;
* @author Mark Diggory (markd at atmire dot com)
*/
public class AuthorityValue {
/**
* The id of the record in solr
*/
@@ -150,12 +150,13 @@ public class AuthorityValue {
public SolrInputDocument getSolrInputDocument() {
SolrInputDocument doc = new SolrInputDocument();
DateFormat solrDateFormatter = SolrUtils.getDateFormatter();
doc.addField("id", getId());
doc.addField("field", getField());
doc.addField("value", getValue());
doc.addField("deleted", isDeleted());
doc.addField("creation_date", getCreationDate());
doc.addField("last_modified_date", getLastModified());
doc.addField("creation_date", solrDateFormatter.format(getCreationDate()));
doc.addField("last_modified_date", solrDateFormatter.format(getLastModified()));
doc.addField("authority_type", getAuthorityType());
return doc;
}
@@ -196,12 +197,12 @@ public class AuthorityValue {
* @return map
*/
public Map<String, String> choiceSelectMap() {
return new HashMap<String, String>();
return new HashMap<>();
}
public List<DateTimeFormatter> getDateFormatters() {
List<DateTimeFormatter> list = new ArrayList<DateTimeFormatter>();
List<DateTimeFormatter> list = new ArrayList<>();
list.add(ISODateTimeFormat.dateTime());
list.add(ISODateTimeFormat.dateTimeNoMillis());
return list;

View File

@@ -35,6 +35,7 @@ public abstract class AuthorityServiceFactory {
public abstract AuthorityService getAuthorityService();
public abstract List<AuthorityIndexerInterface> getAuthorityIndexers();
public static AuthorityServiceFactory getInstance() {

View File

@@ -1,191 +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.authority.orcid;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.SolrAuthorityInterface;
import org.dspace.authority.orcid.xml.XMLtoBio;
import org.dspace.authority.rest.RESTConnector;
import org.json.JSONObject;
import org.orcid.jaxb.model.record_v2.Person;
/**
* @author Jonas Van Goolen (jonas at atmire dot com)
* This class contains all methods for retrieving "Person" objects calling the ORCID (version 2) endpoints.
* Additionally, this can also create AuthorityValues based on these returned Person objects
*/
public class Orcidv2 implements SolrAuthorityInterface {
private static Logger log = LogManager.getLogger(Orcidv2.class);
public RESTConnector restConnector;
private String OAUTHUrl;
private String clientId;
private String clientSecret;
private String accessToken;
/**
* Initialize the accessToken that is required for all subsequent calls to ORCID.
*
* @throws java.io.IOException passed through from HTTPclient.
*/
public void init() throws IOException {
if (StringUtils.isNotBlank(accessToken) && StringUtils.isNotBlank(clientSecret)) {
String authenticationParameters = "?client_id=" + clientId +
"&client_secret=" + clientSecret +
"&scope=/read-public&grant_type=client_credentials";
HttpPost httpPost = new HttpPost(OAUTHUrl + authenticationParameters);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse getResponse = httpClient.execute(httpPost);
InputStream is = getResponse.getEntity().getContent();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
JSONObject responseObject = null;
String inputStr;
while ((inputStr = streamReader.readLine()) != null && responseObject == null) {
if (inputStr.startsWith("{") && inputStr.endsWith("}") && inputStr.contains("access_token")) {
try {
responseObject = new JSONObject(inputStr);
} catch (Exception e) {
//Not as valid as I'd hoped, move along
responseObject = null;
}
}
}
if (responseObject != null && responseObject.has("access_token")) {
accessToken = (String) responseObject.get("access_token");
}
}
}
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private Orcidv2(String url, String OAUTHUrl, String clientId, String clientSecret) {
this.restConnector = new RESTConnector(url);
this.OAUTHUrl = OAUTHUrl;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
/**
* Makes an instance of the Orcidv2 class based on the provided parameters.
* This constructor is called through the spring bean initialization
*/
private Orcidv2(String url) {
this.restConnector = new RESTConnector(url);
}
/**
* Makes an instance of the AuthorityValue with the given information.
* @param text search string
* @return List<AuthorityValue>
*/
@Override
public List<AuthorityValue> queryAuthorities(String text, int max) {
List<Person> bios = queryBio(text, max);
List<AuthorityValue> result = new ArrayList<>();
for (Person person : bios) {
AuthorityValue orcidAuthorityValue = Orcidv2AuthorityValue.create(person);
if (orcidAuthorityValue != null) {
result.add(orcidAuthorityValue);
}
}
return result;
}
/**
* Create an AuthorityValue from a Person retrieved using the given orcid identifier.
* @param id orcid identifier
* @return AuthorityValue
*/
public AuthorityValue queryAuthorityID(String id) {
Person person = getBio(id);
AuthorityValue valueFromPerson = Orcidv2AuthorityValue.create(person);
return valueFromPerson;
}
/**
* Retrieve a Person object based on a given orcid identifier
* @param id orcid identifier
* @return Person
*/
public Person getBio(String id) {
log.debug("getBio called with ID=" + id);
if (!isValid(id)) {
return null;
}
InputStream bioDocument = restConnector.get(id + ((id.endsWith("/person")) ? "" : "/person"), accessToken);
XMLtoBio converter = new XMLtoBio();
Person person = converter.convertSinglePerson(bioDocument);
return person;
}
/**
* Retrieve a list of Person objects.
* @param text search string
* @param start offset to use
* @param rows how many rows to return
* @return List<Person>
*/
public List<Person> queryBio(String text, int start, int rows) {
if (rows > 100) {
throw new IllegalArgumentException("The maximum number of results to retrieve cannot exceed 100.");
}
String searchPath = "search?q=" + URLEncoder.encode(text) + "&start=" + start + "&rows=" + rows;
log.debug("queryBio searchPath=" + searchPath + " accessToken=" + accessToken);
InputStream bioDocument = restConnector.get(searchPath, accessToken);
XMLtoBio converter = new XMLtoBio();
List<Person> bios = converter.convert(bioDocument);
return bios;
}
/**
* Retrieve a list of Person objects.
* @param text search string
* @param max how many rows to return
* @return List<Person>
*/
public List<Person> queryBio(String text, int max) {
return queryBio(text, 0, max);
}
/**
* Check to see if the provided text has the correct ORCID syntax.
* Since only searching on ORCID id is allowed, this way, we filter out any queries that would return a
* blank result anyway
*/
private boolean isValid(String text) {
return StringUtils.isNotBlank(text) && text.matches(Orcidv2AuthorityValue.ORCID_ID_SYNTAX);
}
}

View File

@@ -1,342 +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.authority.orcid;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrInputDocument;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.AuthorityValueServiceImpl;
import org.dspace.authority.PersonAuthorityValue;
import org.dspace.utils.DSpace;
import org.orcid.jaxb.model.common_v2.ExternalId;
import org.orcid.jaxb.model.record_v2.ExternalIdentifiers;
import org.orcid.jaxb.model.record_v2.KeywordType;
import org.orcid.jaxb.model.record_v2.NameType;
import org.orcid.jaxb.model.record_v2.Person;
import org.orcid.jaxb.model.record_v2.ResearcherUrlType;
/**
* @author Jonas Van Goolen (jonas at atmire dot com)
*/
public class Orcidv2AuthorityValue extends PersonAuthorityValue {
/*
* The ORCID identifier
*/
private String orcid_id;
/*
* Map containing key-value pairs filled in by "setValues(Person person)".
* This represents all dynamic information of the object.
*/
private Map<String, List<String>> otherMetadata = new HashMap<String, List<String>>();
/**
* The syntax that the ORCID id needs to conform to
*/
public static final String ORCID_ID_SYNTAX = "\\d{4}-\\d{4}-\\d{4}-(\\d{3}X|\\d{4})";
/**
* Creates an instance of Orcidv2AuthorityValue with only uninitialized fields.
* This is meant to be filled in with values from an existing record.
* To create a brand new Orcidv2AuthorityValue, use create()
*/
public Orcidv2AuthorityValue() {
}
public Orcidv2AuthorityValue(SolrDocument document) {
super(document);
}
public String getOrcid_id() {
return orcid_id;
}
public void setOrcid_id(String orcid_id) {
this.orcid_id = orcid_id;
}
/**
* Create an empty authority.
* @return OrcidAuthorityValue
*/
public static Orcidv2AuthorityValue create() {
Orcidv2AuthorityValue orcidAuthorityValue = new Orcidv2AuthorityValue();
orcidAuthorityValue.setId(UUID.randomUUID().toString());
orcidAuthorityValue.updateLastModifiedDate();
orcidAuthorityValue.setCreationDate(new Date());
return orcidAuthorityValue;
}
/**
* Create an authority based on a given orcid bio
* @return OrcidAuthorityValue
*/
public static Orcidv2AuthorityValue create(Person person) {
if (person == null) {
return null;
}
Orcidv2AuthorityValue authority = Orcidv2AuthorityValue.create();
authority.setValues(person);
return authority;
}
/**
* Initialize this instance based on a Person object
* @param person Person
*/
protected void setValues(Person person) {
NameType name = person.getName();
if (!StringUtils.equals(name.getPath(), this.getOrcid_id())) {
this.setOrcid_id(name.getPath());
}
if (!StringUtils.equals(name.getFamilyName().getValue(), this.getLastName())) {
this.setLastName(name.getFamilyName().getValue());
}
if (!StringUtils.equals(name.getGivenNames().getValue(), this.getFirstName())) {
this.setFirstName(name.getGivenNames().getValue());
}
if (name.getCreditName() != null && StringUtils.isNotBlank(name.getCreditName().getValue())) {
if (!this.getNameVariants().contains(name.getCreditName().getValue())) {
this.addNameVariant(name.getCreditName().getValue());
}
}
if (person.getKeywords() != null) {
for (KeywordType keyword : person.getKeywords().getKeyword()) {
if (this.isNewMetadata("keyword", keyword.getContent())) {
this.addOtherMetadata("keyword", keyword.getContent());
}
}
}
ExternalIdentifiers externalIdentifiers = person.getExternalIdentifiers();
if (externalIdentifiers != null) {
for (ExternalId externalIdentifier : externalIdentifiers.getExternalIdentifier()) {
if (this.isNewMetadata("external_identifier", externalIdentifier.getExternalIdValue())) {
this.addOtherMetadata("external_identifier", externalIdentifier.getExternalIdValue());
}
}
}
if (person.getResearcherUrls() != null) {
for (ResearcherUrlType researcherUrl : person.getResearcherUrls().getResearcherUrl()) {
if (this.isNewMetadata("researcher_url", researcherUrl.getUrl().getValue())) {
this.addOtherMetadata("researcher_url", researcherUrl.getUrl().getValue());
}
}
}
if (person.getBiography() != null) {
if (this.isNewMetadata("biography", person.getBiography().getContent())) {
this.addOtherMetadata("biography", person.getBiography().getContent());
}
}
this.setValue(this.getName());
}
/**
* Makes an instance of the AuthorityValue with the given information.
* @param info string info
* @return AuthorityValue
*/
@Override
public AuthorityValue newInstance(String info) {
AuthorityValue authorityValue = null;
if (StringUtils.isNotBlank(info)) {
Orcidv2 orcid = new DSpace().getServiceManager().getServiceByName("AuthoritySource", Orcidv2.class);
authorityValue = orcid.queryAuthorityID(info);
} else {
authorityValue = this.create();
}
return authorityValue;
}
@Override
public void setValue(String value) {
super.setValue(value);
}
/**
* Check to see if the provided label / data pair is already present in the "otherMetadata" or not
* */
public boolean isNewMetadata(String label, String data) {
List<String> strings = getOtherMetadata().get(label);
boolean update;
if (strings == null) {
update = StringUtils.isNotBlank(data);
} else {
update = !strings.contains(data);
}
return update;
}
/**
* Add additional metadata to the otherMetadata map*/
public void addOtherMetadata(String label, String data) {
List<String> strings = otherMetadata.get(label);
if (strings == null) {
strings = new ArrayList<>();
}
strings.add(data);
otherMetadata.put(label, strings);
}
public Map<String, List<String>> getOtherMetadata() {
return otherMetadata;
}
/**
* Generate a solr record from this instance
* @return SolrInputDocument
*/
@Override
public SolrInputDocument getSolrInputDocument() {
SolrInputDocument doc = super.getSolrInputDocument();
if (StringUtils.isNotBlank(getOrcid_id())) {
doc.addField("orcid_id", getOrcid_id());
}
for (String t : otherMetadata.keySet()) {
List<String> data = otherMetadata.get(t);
for (String data_entry : data) {
doc.addField("label_" + t, data_entry);
}
}
return doc;
}
/**
* Information that can be used the choice ui
* @return map
*/
@Override
public Map<String, String> choiceSelectMap() {
Map<String, String> map = super.choiceSelectMap();
String orcid_id = getOrcid_id();
if (StringUtils.isNotBlank(orcid_id)) {
map.put("orcid", orcid_id);
}
return map;
}
@Override
public String getAuthorityType() {
return "orcid";
}
/**
* Provides a string that will allow this AuthorityType to be recognized and provides information to create a new
* instance to be created using public Orcidv2AuthorityValue newInstance(String info).
* @return see {@link org.dspace.authority.service.AuthorityValueService#GENERATE AuthorityValueService.GENERATE}
*/
@Override
public String generateString() {
String generateString = AuthorityValueServiceImpl.GENERATE + getAuthorityType() +
AuthorityValueServiceImpl.SPLIT;
if (StringUtils.isNotBlank(getOrcid_id())) {
generateString += getOrcid_id();
}
return generateString;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return orcid_id != null ? orcid_id.hashCode() : 0;
}
/**
* The regular equals() only checks if both AuthorityValues describe the same authority.
* This method checks if the AuthorityValues have different information
* E.g. it is used to decide when lastModified should be updated.
* @param o object
* @return true or false
*/
@Override
public boolean hasTheSameInformationAs(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.hasTheSameInformationAs(o)) {
return false;
}
Orcidv2AuthorityValue that = (Orcidv2AuthorityValue) o;
if (orcid_id != null ? !orcid_id.equals(that.orcid_id) : that.orcid_id != null) {
return false;
}
for (String key : otherMetadata.keySet()) {
if (otherMetadata.get(key) != null) {
List<String> metadata = otherMetadata.get(key);
List<String> otherMetadata = that.otherMetadata.get(key);
if (otherMetadata == null) {
return false;
} else {
HashSet<String> metadataSet = new HashSet<String>(metadata);
HashSet<String> otherMetadataSet = new HashSet<String>(otherMetadata);
if (!metadataSet.equals(otherMetadataSet)) {
return false;
}
}
} else {
if (that.otherMetadata.get(key) != null) {
return false;
}
}
}
return true;
}
}

View File

@@ -8,6 +8,7 @@
package org.dspace.authority.rest;
import org.dspace.authority.SolrAuthorityInterface;
import org.dspace.external.OrcidRestConnector;
/**
* @author Antoine Snyers (antoine at atmire.com)
@@ -17,9 +18,9 @@ import org.dspace.authority.SolrAuthorityInterface;
*/
public abstract class RestSource implements SolrAuthorityInterface {
protected RESTConnector restConnector;
protected OrcidRestConnector restConnector;
public RestSource(String url) {
this.restConnector = new RESTConnector(url);
this.restConnector = new OrcidRestConnector(url);
}
}

View File

@@ -67,7 +67,7 @@ public class DailyReportEmailer {
email.setSubject(
"Checksum checker Report - " + numberOfBitstreams + " Bitstreams found with POSSIBLE issues on " +
hostname);
email.setContent("report is attached ...");
email.setContent("Checker Report", "report is attached ...");
email.addAttachment(attachment, "checksum_checker_report.txt");
email.addRecipient(ConfigurationManager.getProperty("mail.admin"));
email.send();

View File

@@ -99,8 +99,12 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
}
/**
* Get the sequence ID of this bitstream
* Get the sequence ID of this bitstream. The sequence ID is a unique (within an Item) integer that references
* this bitstream. It acts as a "persistent" identifier within the Item for this Bitstream (as Bitstream names
* are not persistent). Because it is unique within an Item, sequence IDs are assigned by the ItemService.update()
* method.
*
* @see org.dspace.content.ItemServiceImpl#update(Context, Item)
* @return the sequence ID
*/
public int getSequenceID() {
@@ -112,8 +116,12 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
}
/**
* Set the sequence ID of this bitstream
* Set the sequence ID of this bitstream. The sequence ID is a unique (within an Item) integer that references
* this bitstream. While this method is public, it should only be used by ItemService.update() or other methods
* which validate the uniqueness of the ID within the associated Item. This method itself does not validate
* uniqueness of the ID, nor does the underlying database table.
*
* @see org.dspace.content.ItemServiceImpl#update(Context, Item)
* @param sid the ID
*/
public void setSequenceID(int sid) {
@@ -130,7 +138,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
*/
@Override
public String getName() {
return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(),
"title", null, Item.ANY);
}
/**
@@ -141,7 +150,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
* @throws SQLException if database error
*/
public void setName(Context context, String n) throws SQLException {
getBitstreamService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "title", null, null, n);
getBitstreamService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(),
"title", null, null, n);
}
/**
@@ -152,7 +162,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
* @return the source of the bitstream
*/
public String getSource() {
return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "source", null, Item.ANY);
return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(),
"source", null, Item.ANY);
}
/**
@@ -163,7 +174,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
* @throws SQLException if database error
*/
public void setSource(Context context, String n) throws SQLException {
getBitstreamService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "source", null, null, n);
getBitstreamService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(),
"source", null, null, n);
}
/**
@@ -174,7 +186,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
*/
public String getDescription() {
return getBitstreamService()
.getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "description", null, Item.ANY);
.getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "description",
null, Item.ANY);
}
/**
@@ -186,7 +199,7 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
*/
public void setDescription(Context context, String n) throws SQLException {
getBitstreamService()
.setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "description", null, null, n);
.setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(), "description", null, null, n);
}
/**
@@ -235,7 +248,8 @@ public class Bitstream extends DSpaceObject implements DSpaceObjectLegacySupport
* @return the user's format description.
*/
public String getUserFormatDescription() {
return getBitstreamService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY);
return getBitstreamService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(),
"format", null, Item.ANY);
}
protected BitstreamFormat getBitstreamFormat() {

View File

@@ -71,7 +71,7 @@ public class BitstreamFormat implements Serializable, ReloadableEntity<Integer>
@Column(name = "internal")
private boolean internal = false;
@ElementCollection(fetch = FetchType.LAZY)
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "fileextension", joinColumns = @JoinColumn(name = "bitstream_format_id"))
@CollectionId(
columns = @Column(name = "file_extension_id"),
@@ -275,7 +275,7 @@ public class BitstreamFormat implements Serializable, ReloadableEntity<Integer>
return false;
}
final BitstreamFormat otherBitstreamFormat = (BitstreamFormat) other;
if (this.getID() != otherBitstreamFormat.getID()) {
if (!this.getID().equals(otherBitstreamFormat.getID())) {
return false;
}

View File

@@ -270,4 +270,4 @@ public class BitstreamFormatServiceImpl implements BitstreamFormatService {
}
return null;
}
}
}

View File

@@ -205,7 +205,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
@Override
public void setUserFormatDescription(Context context, Bitstream bitstream, String desc) throws SQLException {
setFormat(context, bitstream, null);
setMetadataSingleValue(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, null, desc);
setMetadataSingleValue(context, bitstream, MetadataSchemaEnum.DC.getName(), "format", null, null, desc);
}
@Override
@@ -235,7 +235,7 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
}
// Remove user type description
clearMetadata(context, bitstream, MetadataSchema.DC_SCHEMA, "format", null, Item.ANY);
clearMetadata(context, bitstream, MetadataSchemaEnum.DC.getName(), "format", null, Item.ANY);
// Update the ID in the table row
bitstream.setFormat(bitstreamFormat);

View File

@@ -88,7 +88,7 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport {
*/
@Override
public String getName() {
return getBundleService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
return getBundleService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY);
}
/**
@@ -100,7 +100,8 @@ public class Bundle extends DSpaceObject implements DSpaceObjectLegacySupport {
* @throws SQLException if database error
*/
public void setName(Context context, String name) throws SQLException {
getBundleService().setMetadataSingleValue(context, this, MetadataSchema.DC_SCHEMA, "title", null, null, name);
getBundleService().setMetadataSingleValue(context, this, MetadataSchemaEnum.DC.getName(),
"title", null, null, name);
}
/**

View File

@@ -7,6 +7,10 @@
*/
package org.dspace.content;
import static org.dspace.core.Constants.ADD;
import static org.dspace.core.Constants.REMOVE;
import static org.dspace.core.Constants.WRITE;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
@@ -268,6 +272,81 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl<Bundle> implement
return authorizeService.getPolicies(context, bundle);
}
@Override
public void updateBitstreamOrder(Context context, Bundle bundle, int from, int to)
throws AuthorizeException, SQLException {
List<Bitstream> bitstreams = bundle.getBitstreams();
if (bitstreams.size() < 1 || from >= bitstreams.size() || to >= bitstreams.size() || from < 0 || to < 0) {
throw new IllegalArgumentException(
"Invalid 'from' and 'to' arguments supplied for moving a bitstream within bundle " +
bundle.getID() + ". from: " + from + "; to: " + to
);
}
List<UUID> bitstreamIds = new LinkedList<>();
for (Bitstream bitstream : bitstreams) {
bitstreamIds.add(bitstream.getID());
}
if (from < to) {
bitstreamIds.add(to + 1, bitstreamIds.get(from));
bitstreamIds.remove(from);
} else {
bitstreamIds.add(to, bitstreamIds.get(from));
bitstreamIds.remove(from + 1);
}
setOrder(context, bundle, bitstreamIds.toArray(new UUID[bitstreamIds.size()]));
}
@Override
public void moveBitstreamToBundle(Context context, Bundle targetBundle, Bitstream bitstream)
throws SQLException, AuthorizeException, IOException {
List<Bundle> bundles = new LinkedList<>();
bundles.addAll(bitstream.getBundles());
if (hasSufficientMovePermissions(context, bundles, targetBundle)) {
this.addBitstream(context, targetBundle, bitstream);
this.update(context, targetBundle);
for (Bundle bundle : bundles) {
this.removeBitstream(context, bundle, bitstream);
this.update(context, bundle);
}
}
}
/**
* Verifies if the context (user) has sufficient rights to the bundles in order to move a bitstream
*
* @param context The context
* @param bundles The current bundles in which the bitstream resides
* @param targetBundle The target bundle
* @return true when the context has sufficient rights
* @throws AuthorizeException When one of the necessary rights is not present
*/
private boolean hasSufficientMovePermissions(final Context context, final List<Bundle> bundles,
final Bundle targetBundle) throws SQLException, AuthorizeException {
for (Bundle bundle : bundles) {
if (!authorizeService.authorizeActionBoolean(context, bundle, WRITE) || !authorizeService
.authorizeActionBoolean(context, bundle, REMOVE)) {
throw new AuthorizeException(
"The current user does not have WRITE and REMOVE access to the current bundle: " + bundle
.getID());
}
}
if (!authorizeService.authorizeActionBoolean(context, targetBundle, WRITE) || !authorizeService
.authorizeActionBoolean(context, targetBundle, ADD)) {
throw new AuthorizeException(
"The current user does not have WRITE and ADD access to the target bundle: " + targetBundle
.getID());
}
for (Item item : targetBundle.getItems()) {
if (!authorizeService.authorizeActionBoolean(context, item, WRITE)) {
throw new AuthorizeException(
"The current user does not have WRITE access to the target bundle's item: " + item.getID());
}
}
return true;
}
@Override
public void setOrder(Context context, Bundle bundle, UUID[] bitstreamIds) throws AuthorizeException, SQLException {
authorizeService.authorizeAction(context, bundle, Constants.WRITE);

View File

@@ -120,7 +120,7 @@ public class Collection extends DSpaceObject implements DSpaceObjectLegacySuppor
@Override
public String getName() {
String value = getCollectionService()
.getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
.getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY);
return value == null ? "" : value;
}

View File

@@ -154,10 +154,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
@Override
public List<Collection> findAll(Context context) throws SQLException {
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null);
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(),
"title", null);
if (nameField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!");
}
return collectionDAO.findAll(context, nameField);
@@ -165,10 +166,11 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
@Override
public List<Collection> findAll(Context context, Integer limit, Integer offset) throws SQLException {
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null);
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(),
"title", null);
if (nameField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!");
}
return collectionDAO.findAll(context, nameField, limit, offset);
@@ -760,6 +762,8 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
// Remove any workflow roles
collectionRoleService.deleteByCollection(context, collection);
collection.getResourcePolicies().clear();
// Remove default administrators group
Group g = collection.getAdministrators();
@@ -903,4 +907,4 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
throws SQLException {
return collectionDAO.getCollectionsWithBitstreamSizesTotal(context);
}
}
}

View File

@@ -262,7 +262,7 @@ public class Community extends DSpaceObject implements DSpaceObjectLegacySupport
@Override
public String getName() {
String value = getCommunityService()
.getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
.getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY);
return value == null ? "" : value;
}

View File

@@ -148,10 +148,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
@Override
public List<Community> findAll(Context context) throws SQLException {
MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null);
MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(),
"title", null);
if (sortField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!");
}
return communityDAO.findAll(context, sortField);
@@ -159,10 +160,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
@Override
public List<Community> findAll(Context context, Integer limit, Integer offset) throws SQLException {
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null);
MetadataField nameField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(),
"title", null);
if (nameField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!");
}
return communityDAO.findAll(context, nameField, limit, offset);
@@ -171,10 +173,11 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
@Override
public List<Community> findAllTop(Context context) throws SQLException {
// get all communities that are not children
MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchema.DC_SCHEMA, "title", null);
MetadataField sortField = metadataFieldService.findByElement(context, MetadataSchemaEnum.DC.getName(),
"title", null);
if (sortField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".title' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".title' doesn't exist!");
}
return communityDAO.findAllNoParent(context, sortField);

View File

@@ -10,8 +10,10 @@ package org.dspace.content;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
@@ -27,6 +29,7 @@ import org.dspace.content.authority.service.MetadataAuthorityService;
import org.dspace.content.service.DSpaceObjectService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.service.HandleService;
@@ -60,6 +63,8 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
protected MetadataFieldService metadataFieldService;
@Autowired(required = true)
protected MetadataAuthorityService metadataAuthorityService;
@Autowired(required = true)
protected RelationshipService relationshipService;
public DSpaceObjectServiceImpl() {
@@ -67,7 +72,7 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
@Override
public String getName(T dso) {
String value = getMetadataFirstValue(dso, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
String value = getMetadataFirstValue(dso, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY);
return value == null ? "" : value;
}
@@ -141,7 +146,7 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
public List<MetadataValue> getMetadataByMetadataString(T dso, String mdString) {
StringTokenizer dcf = new StringTokenizer(mdString, ".");
String[] tokens = { "", "", "" };
String[] tokens = {"", "", ""};
int i = 0;
while (dcf.hasMoreTokens()) {
tokens[i] = dcf.nextToken().trim();
@@ -235,12 +240,22 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
throws SQLException {
boolean authorityControlled = metadataAuthorityService.isAuthorityControlled(metadataField);
boolean authorityRequired = metadataAuthorityService.isAuthorityRequired(metadataField);
// We will not verify that they are valid entries in the registry
// until update() is called.
for (int i = 0; i < values.size(); i++) {
if (authorities != null && authorities.size() >= i) {
if (StringUtils.startsWith(authorities.get(i), Constants.VIRTUAL_AUTHORITY_PREFIX)) {
continue;
}
}
MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField);
//Set place to list length of all metadatavalues for the given schema.element.qualifier combination.
// Subtract one to adhere to the 0 as first element rule
metadataValue.setPlace(
this.getMetadata(dso, metadataField.getMetadataSchema().getName(), metadataField.getElement(),
metadataField.getQualifier(), Item.ANY).size() - 1);
metadataValue.setLanguage(lang == null ? null : lang.trim());
// Logic to set Authority and Confidence:
@@ -521,7 +536,7 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
protected String[] getMDValueByField(String field) {
StringTokenizer dcf = new StringTokenizer(field, ".");
String[] tokens = { "", "", "" };
String[] tokens = {"", "", ""};
int i = 0;
while (dcf.hasMoreTokens()) {
tokens[i] = dcf.nextToken().trim();
@@ -543,11 +558,50 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
*/
// A map created to store the latest place for each metadata field
Map<MetadataField, Integer> fieldToLastPlace = new HashMap<>();
List<MetadataValue> metadataValues = dso.getMetadata();
List<MetadataValue> metadataValues = new LinkedList<>();
if (dso.getType() == Constants.ITEM) {
metadataValues = getMetadata(dso, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
} else {
metadataValues = dso.getMetadata();
}
//This inline sort function will sort the MetadataValues based on their place in ascending order
//If two places are the same then the MetadataValue instance will be placed before the
//RelationshipMetadataValue instance.
//This is done to ensure that the order is correct.
metadataValues.sort(new Comparator<MetadataValue>() {
public int compare(MetadataValue o1, MetadataValue o2) {
int compare = o1.getPlace() - o2.getPlace();
if (compare == 0) {
if (o1 instanceof RelationshipMetadataValue) {
return 1;
} else if (o2 instanceof RelationshipMetadataValue) {
return -1;
}
}
return compare;
}
});
for (MetadataValue metadataValue : metadataValues) {
//Retrieve & store the place for each metadata value
int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue);
metadataValue.setPlace(mvPlace);
if (StringUtils.startsWith(metadataValue.getAuthority(), Constants.VIRTUAL_AUTHORITY_PREFIX) &&
((RelationshipMetadataValue) metadataValue).isUseForPlace()) {
int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue);
metadataValue.setPlace(mvPlace);
String authority = metadataValue.getAuthority();
String relationshipId = StringUtils.split(authority, "::")[1];
Relationship relationship = relationshipService.find(context, Integer.parseInt(relationshipId));
if (relationship.getLeftItem() == (Item) dso) {
relationship.setLeftPlace(mvPlace);
} else {
relationship.setRightPlace(mvPlace);
}
relationshipService.update(context, relationship);
} else if (!StringUtils.startsWith(metadataValue.getAuthority(),
Constants.VIRTUAL_AUTHORITY_PREFIX)) {
int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue);
metadataValue.setPlace(mvPlace);
}
}
}
}
@@ -557,7 +611,7 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
*
* @param fieldToLastPlace the map containing the latest place of each metadata field
* @param metadataValue the metadata value that needs to get a place
* @return The new place for the metadata valu
* @return The new place for the metadata value
*/
protected int getMetadataValuePlace(Map<MetadataField, Integer> fieldToLastPlace, MetadataValue metadataValue) {
MetadataField metadataField = metadataValue.getMetadataField();
@@ -573,23 +627,23 @@ public abstract class DSpaceObjectServiceImpl<T extends DSpaceObject> implements
protected String[] getMDValueByLegacyField(String field) {
switch (field) {
case "introductory_text":
return new String[] {MetadataSchema.DC_SCHEMA, "description", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "description", null};
case "short_description":
return new String[] {MetadataSchema.DC_SCHEMA, "description", "abstract"};
return new String[] {MetadataSchemaEnum.DC.getName(), "description", "abstract"};
case "side_bar_text":
return new String[] {MetadataSchema.DC_SCHEMA, "description", "tableofcontents"};
return new String[] {MetadataSchemaEnum.DC.getName(), "description", "tableofcontents"};
case "copyright_text":
return new String[] {MetadataSchema.DC_SCHEMA, "rights", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "rights", null};
case "name":
return new String[] {MetadataSchema.DC_SCHEMA, "title", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "title", null};
case "provenance_description":
return new String[] {MetadataSchema.DC_SCHEMA, "provenance", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "provenance", null};
case "license":
return new String[] {MetadataSchema.DC_SCHEMA, "rights", "license"};
return new String[] {MetadataSchemaEnum.DC.getName(), "rights", "license"};
case "user_format_description":
return new String[] {MetadataSchema.DC_SCHEMA, "format", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "format", null};
case "source":
return new String[] {MetadataSchema.DC_SCHEMA, "source", null};
return new String[] {MetadataSchemaEnum.DC.getName(), "source", null};
case "firstname":
return new String[] {"eperson", "firstname", null};
case "lastname":

View File

@@ -0,0 +1,68 @@
/**
* 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.content;
import java.util.List;
/**
* This class represents an Entity object. An Entity object has an Item that it describes with a list
* of relationships that it includes as well.
*/
public class Entity {
/**
* The Item that is being described by this Entity
*/
private Item item;
/**
* The relationships for the Item that is included in this Entity
*/
private List<Relationship> relationships;
/**
* constructor for the Entity object
* @param item The Item to be included in this Entity object as a property
* @param relationshipList The list of relationships
*/
public Entity(Item item,List<Relationship> relationshipList) {
setItem(item);
setRelationships(relationshipList);
}
/**
* Standard getter for the Item for this Entity object
* @return The Item that is described in this Entity object
*/
public Item getItem() {
return item;
}
/**
* Standard setter for the Item for this Entity object
* @param item The Item to be set
*/
public void setItem(Item item) {
this.item = item;
}
/**
* Standard getter for the list of relationships for the Item in this Entity object
* @return the list of relationships
*/
public List<Relationship> getRelationships() {
return relationships;
}
/**
* Standard setter for the list of relationships for the Item in this Entity object
* @param relationships The list of relationships to be set
*/
public void setRelationships(List<Relationship> relationships) {
this.relationships = relationships;
}
}

View File

@@ -0,0 +1,144 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import org.dspace.content.service.EntityService;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
public class EntityServiceImpl implements EntityService {
@Autowired(required = true)
protected EntityTypeService entityTypeService;
@Autowired(required = true)
protected RelationshipService relationshipService;
@Autowired(required = true)
protected RelationshipTypeService relationshipTypeService;
@Autowired(required = true)
protected ItemService itemService;
@Override
public Entity findByItemId(Context context, UUID itemId) throws SQLException {
return findByItemId(context, itemId, -1, -1);
}
@Override
public Entity findByItemId(Context context, UUID itemId, Integer limit, Integer offset) throws SQLException {
Item item = itemService.find(context, itemId);
List<Relationship> relationshipList = relationshipService.findByItem(context, item, limit, offset);
return new Entity(item, relationshipList);
}
@Override
public EntityType getType(Context context, Entity entity) throws SQLException {
Item item = entity.getItem();
List<MetadataValue> list = itemService.getMetadata(item, "relationship", "type", null, Item.ANY);
if (!list.isEmpty()) {
return entityTypeService.findByEntityType(context, list.get(0).getValue());
} else {
return null;
}
}
@Override
public List<Relationship> getLeftRelations(Context context, Entity entity) {
List<Relationship> fullList = entity.getRelationships();
List<Relationship> listToReturn = new LinkedList<>();
for (Relationship relationship : fullList) {
if (relationship.getLeftItem().getID() == entity.getItem().getID()) {
listToReturn.add(relationship);
}
}
return listToReturn;
}
@Override
public List<Relationship> getRightRelations(Context context, Entity entity) {
List<Relationship> fullList = entity.getRelationships();
List<Relationship> listToReturn = new LinkedList<>();
for (Relationship relationship : fullList) {
if (relationship.getRightItem().getID() == entity.getItem().getID()) {
listToReturn.add(relationship);
}
}
return listToReturn;
}
@Override
public List<Relationship> getRelationsByTypeName(Context context, String typeName) throws SQLException {
return getRelationsByTypeName(context, typeName, -1, -1);
}
@Override
public List<Relationship> getRelationsByTypeName(Context context, String typeName, Integer limit, Integer offset)
throws SQLException {
return relationshipService.findByTypeName(context, typeName, limit, offset);
}
@Override
public List<RelationshipType> getAllRelationshipTypes(Context context, Entity entity) throws SQLException {
return getAllRelationshipTypes(context, entity, -1, -1);
}
@Override
public List<RelationshipType> getAllRelationshipTypes(Context context, Entity entity, Integer limit, Integer offset)
throws SQLException {
return relationshipTypeService.findByEntityType(context, this.getType(context, entity), limit, offset);
}
@Override
public List<RelationshipType> getLeftRelationshipTypes(Context context, Entity entity) throws SQLException {
return getLeftRelationshipTypes(context, entity, true, -1, -1);
}
@Override
public List<RelationshipType> getLeftRelationshipTypes(Context context, Entity entity, boolean isLeft,
Integer limit, Integer offset) throws SQLException {
return relationshipTypeService.findByEntityType(context, this.getType(context, entity), isLeft, limit, offset);
}
@Override
public List<RelationshipType> getRightRelationshipTypes(Context context, Entity entity) throws SQLException {
return getRightRelationshipTypes(context, entity, false, -1, -1);
}
@Override
public List<RelationshipType> getRightRelationshipTypes(Context context, Entity entity, boolean isLeft,
Integer limit, Integer offset) throws SQLException {
return relationshipTypeService.findByEntityType(context, this.getType(context, entity), isLeft, limit, offset);
}
@Override
public List<RelationshipType> getRelationshipTypesByTypeName(Context context, String type) throws SQLException {
return getRelationshipTypesByTypeName(context, type, -1, -1);
}
@Override
public List<RelationshipType> getRelationshipTypesByTypeName(Context context, String typeName,
Integer limit, Integer offset) throws SQLException {
return relationshipTypeService.findByLeftwardOrRightwardTypeName(context, typeName, limit, offset);
}
}

View File

@@ -0,0 +1,77 @@
/**
* 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.content;
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 org.dspace.core.ReloadableEntity;
/**
* Class representing an EntityType
* This class contains an Integer ID that will be the unique value for this class and also the primary key
* This also has a label that will be used to identify what kind of EntityType this object is
*/
@Entity
@Table(name = "entity_type")
public class EntityType implements ReloadableEntity<Integer> {
/**
* The Integer ID used as a primary key for this database object.
* This is generated by a sequence
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "entity_type_id_seq")
@SequenceGenerator(name = "entity_type_id_seq", sequenceName = "entity_type_id_seq", allocationSize = 1)
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
protected Integer id;
/**
* The String label field for the entity type
* This cannot be null
*/
@Column(name = "label", nullable = false)
private String label;
/**
* The standard setter for the ID of this EntityType
* @param id The ID that this EntityType's ID will be set to
*/
public void setId(Integer id) {
this.id = id;
}
/**
* The standard getter for the label of this EntityType
* @return The label for this EntityType
*/
public String getLabel() {
return label;
}
/**
* 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) {
this.label = label;
}
/**
* The standard getter for the ID of this EntityType
* @return The ID for this EntityType
*/
public Integer getID() {
return id;
}
}

View File

@@ -0,0 +1,101 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.dao.EntityTypeDAO;
import org.dspace.content.service.EntityTypeService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
public class EntityTypeServiceImpl implements EntityTypeService {
@Autowired(required = true)
protected EntityTypeDAO entityTypeDAO;
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Override
public EntityType findByEntityType(Context context, String entityType) throws SQLException {
return entityTypeDAO.findByEntityType(context, entityType);
}
@Override
public List<EntityType> findAll(Context context) throws SQLException {
return findAll(context, -1, -1);
}
@Override
public List<EntityType> findAll(Context context, Integer limit, Integer offset) throws SQLException {
return entityTypeDAO.findAll(context, EntityType.class, limit, offset);
}
@Override
public EntityType create(Context context) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify entityType");
}
return entityTypeDAO.create(context, new EntityType());
}
@Override
public EntityType create(Context context, String entityTypeString) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify entityType");
}
EntityType entityType = new EntityType();
entityType.setLabel(entityTypeString);
return entityTypeDAO.create(context, entityType);
}
@Override
public EntityType find(Context context,int id) throws SQLException {
EntityType entityType = entityTypeDAO.findByID(context, EntityType.class, id);
return entityType;
}
@Override
public void update(Context context,EntityType entityType) throws SQLException, AuthorizeException {
update(context,Collections.singletonList(entityType));
}
@Override
public void update(Context context,List<EntityType> entityTypes) throws SQLException, AuthorizeException {
if (CollectionUtils.isNotEmpty(entityTypes)) {
// Check authorisation - only administrators can change formats
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify entityType");
}
for (EntityType entityType : entityTypes) {
entityTypeDAO.save(context, entityType);
}
}
}
@Override
public void delete(Context context,EntityType entityType) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can delete entityType");
}
entityTypeDAO.delete(context, entityType);
}
}

View File

@@ -104,9 +104,10 @@ public class InstallItemServiceImpl implements InstallItemService {
// If the item doesn't have a date.accessioned, set it to today
List<MetadataValue> dateAccessioned = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "accessioned", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "accessioned", Item.ANY);
if (dateAccessioned.isEmpty()) {
itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString());
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
"date", "accessioned", null, now.toString());
}
// If issue date is set as "today" (literal string), then set it to current date
@@ -114,8 +115,8 @@ public class InstallItemServiceImpl implements InstallItemService {
// replacing "today" with today's date.
// NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default
List<MetadataValue> currentDateIssued = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY);
itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY);
itemService.clearMetadata(c, item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY);
for (MetadataValue dcv : currentDateIssued) {
if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) {
DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1);
@@ -127,7 +128,8 @@ public class InstallItemServiceImpl implements InstallItemService {
// Record that the item was restored
String provDescription = "Restored into DSpace on " + now + " (GMT).";
itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription);
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
"description", "provenance", "en", provDescription);
return finishItem(c, item, is);
}
@@ -137,14 +139,16 @@ public class InstallItemServiceImpl implements InstallItemService {
throws SQLException, AuthorizeException {
// create accession date
DCDate now = DCDate.getCurrent();
itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "accessioned", null, now.toString());
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
"date", "accessioned", null, now.toString());
// add date available if not under embargo, otherwise it will
// be set when the embargo is lifted.
// this will flush out fatal embargo metadata
// problems before we set inArchive.
if (embargoService.getEmbargoTermsAsDate(c, item) == null) {
itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "available", null, now.toString());
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
"date", "available", null, now.toString());
}
// If issue date is set as "today" (literal string), then set it to current date
@@ -152,8 +156,8 @@ public class InstallItemServiceImpl implements InstallItemService {
// replacing "today" with today's date.
// NOTE: As of DSpace 4.0, DSpace no longer sets an issue date by default
List<MetadataValue> currentDateIssued = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY);
itemService.clearMetadata(c, item, MetadataSchema.DC_SCHEMA, "date", "issued", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY);
itemService.clearMetadata(c, item, MetadataSchemaEnum.DC.getName(), "date", "issued", Item.ANY);
for (MetadataValue dcv : currentDateIssued) {
if (dcv.getValue() != null && dcv.getValue().equalsIgnoreCase("today")) {
DCDate issued = new DCDate(now.getYear(), now.getMonth(), now.getDay(), -1, -1, -1);
@@ -178,7 +182,8 @@ public class InstallItemServiceImpl implements InstallItemService {
}
// Add provenance description
itemService.addMetadata(c, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", provDescription);
itemService.addMetadata(c, item, MetadataSchemaEnum.DC.getName(),
"description", "provenance", "en", provDescription);
}
/**

View File

@@ -362,7 +362,7 @@ public class Item extends DSpaceObject implements DSpaceObjectLegacySupport, Ind
@Override
public String getName() {
return getItemService().getMetadataFirstValue(this, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
return getItemService().getMetadataFirstValue(this, MetadataSchemaEnum.DC.getName(), "title", null, Item.ANY);
}
@Override

View File

@@ -174,7 +174,7 @@ public class ItemComparator implements Comparator, Serializable {
protected String getValue(Item item) {
// The overall array and each element are guaranteed non-null
List<MetadataValue> dcvalues = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, element, qualifier, language);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), element, qualifier, language);
if (dcvalues.isEmpty()) {
return null;

View File

@@ -11,10 +11,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@@ -36,7 +40,9 @@ import org.dspace.content.service.CommunityService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.content.virtual.VirtualMetadataPopulator;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
@@ -102,6 +108,14 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
@Autowired(required = true)
protected WorkflowItemService workflowItemService;
@Autowired(required = true)
protected RelationshipService relationshipService;
@Autowired(required = true)
protected VirtualMetadataPopulator virtualMetadataPopulator;
@Autowired(required = true)
private RelationshipMetadataService relationshipMetadataService;
protected ItemServiceImpl() {
super();
@@ -230,10 +244,10 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
throws SQLException {
MetadataField metadataField = metadataFieldService
.findByElement(context, MetadataSchema.DC_SCHEMA, "date", "accessioned");
.findByElement(context, MetadataSchemaEnum.DC.getName(), "date", "accessioned");
if (metadataField == null) {
throw new IllegalArgumentException(
"Required metadata field '" + MetadataSchema.DC_SCHEMA + ".date.accessioned' doesn't exist!");
"Required metadata field '" + MetadataSchemaEnum.DC.getName() + ".date.accessioned' doesn't exist!");
}
return itemDAO.findBySubmitter(context, eperson, metadataField, limit);
@@ -250,6 +264,17 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
return itemDAO.findArchivedByCollection(context, collection, limit, offset);
}
@Override
public Iterator<Item> findByCollectionMapping(Context context, Collection collection, Integer limit, Integer offset)
throws SQLException {
return itemDAO.findArchivedByCollectionExcludingOwning(context, collection, limit, offset);
}
@Override
public int countByCollectionMapping(Context context, Collection collection) throws SQLException {
return itemDAO.countArchivedByCollectionExcludingOwning(context, collection);
}
@Override
public Iterator<Item> findAllByCollection(Context context, Collection collection) throws SQLException {
return itemDAO.findAllByCollection(context, collection);
@@ -471,7 +496,8 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
super.update(context, item);
// Set sequence IDs for bitstreams in item
// Set sequence IDs for bitstreams in Item. To guarantee uniqueness,
// sequence IDs are assigned in sequential order (starting with 1)
int sequence = 0;
List<Bundle> bunds = item.getBundles();
@@ -488,8 +514,6 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
// start sequencing bitstreams without sequence IDs
sequence++;
for (Bundle bund : bunds) {
List<Bitstream> streams = bund.getBitstreams();
@@ -554,7 +578,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
prov.append(installItemService.getBitstreamProvenanceMessage(context, item));
addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", prov.toString());
addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", prov.toString());
// Update item in DB
update(context, item);
@@ -609,7 +633,7 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
// bitstream checksums
prov.append(installItemService.getBitstreamProvenanceMessage(context, item));
addMetadata(context, item, MetadataSchema.DC_SCHEMA, "description", "provenance", "en", prov.toString());
addMetadata(context, item, MetadataSchemaEnum.DC.getName(), "description", "provenance", "en", prov.toString());
// Update item in DB
update(context, item);
@@ -671,6 +695,11 @@ public class ItemServiceImpl extends DSpaceObjectServiceImpl<Item> implements It
log.info(LogManager.getHeader(context, "delete_item", "item_id="
+ item.getID()));
// Remove relationships
for (Relationship relationship : relationshipService.findByItem(context, item)) {
relationshipService.delete(context, relationship, false, false);
}
// Remove bundles
removeAllBundles(context, item);
@@ -1206,7 +1235,7 @@ prevent the generation of resource policy entry values with null dspace_object a
@Override
public int countAllItems(Context context, Collection collection) throws SQLException {
return itemDAO.countItems(context, collection, true, false) + itemDAO.countItems(context, collection,
false, true);
false, true);
}
@Override
@@ -1225,7 +1254,7 @@ prevent the generation of resource policy entry values with null dspace_object a
// Now, lets count unique items across that list of collections
return itemDAO.countItems(context, collections, true, false) + itemDAO.countItems(context, collections,
false, true);
false, true);
}
@Override
@@ -1294,4 +1323,94 @@ prevent the generation of resource policy entry values with null dspace_object a
return false;
}
/**
* This method will return a list of MetadataValue objects that contains all the regular
* metadata of the item passed along in the parameters as well as all the virtual metadata
* which will be generated and processed together with the {@link VirtualMetadataPopulator}
* by processing the item's relationships
* @param item the Item to be processed
* @param schema the schema for the metadata field. <em>Must</em> match
* the <code>name</code> of an existing metadata schema.
* @param element the element name. <code>DSpaceObject.ANY</code> matches any
* element. <code>null</code> doesn't really make sense as all
* metadata must have an element.
* @param qualifier the qualifier. <code>null</code> means unqualified, and
* <code>DSpaceObject.ANY</code> means any qualifier (including
* unqualified.)
* @param lang the ISO639 language code, optionally followed by an underscore
* and the ISO3166 country code. <code>null</code> means only
* values with no language are returned, and
* <code>DSpaceObject.ANY</code> means values with any country code or
* no country code are returned.
* @return
*/
@Override
public List<MetadataValue> getMetadata(Item item, String schema, String element, String qualifier, String lang) {
return this.getMetadata(item, schema, element, qualifier, lang, true);
}
@Override
public List<MetadataValue> getMetadata(Item item, String schema, String element, String qualifier, String lang,
boolean enableVirtualMetadata) {
//Fields of the relation schema are virtual metadata
//except for relation.type which is the type of item in the model
if (StringUtils.equals(schema, MetadataSchemaEnum.RELATION.getName()) && !StringUtils.equals(element, "type")) {
List<RelationshipMetadataValue> relationMetadata = relationshipMetadataService
.getRelationshipMetadata(item, false);
List<MetadataValue> listToReturn = new LinkedList<>();
for (MetadataValue metadataValue : relationMetadata) {
if (StringUtils.equals(metadataValue.getMetadataField().getElement(), element)) {
listToReturn.add(metadataValue);
}
}
listToReturn = sortMetadataValueList(listToReturn);
return listToReturn;
} else {
List<MetadataValue> dbMetadataValues = super.getMetadata(item, schema, element, qualifier, lang);
List<MetadataValue> fullMetadataValueList = new LinkedList<>();
if (enableVirtualMetadata) {
fullMetadataValueList.addAll(relationshipMetadataService.getRelationshipMetadata(item, true));
}
fullMetadataValueList.addAll(dbMetadataValues);
List<MetadataValue> finalList = new LinkedList<>();
for (MetadataValue metadataValue : fullMetadataValueList) {
if (match(schema, element, qualifier, lang, metadataValue)) {
finalList.add(metadataValue);
}
}
finalList = sortMetadataValueList(finalList);
return finalList;
}
}
/**
* This method will sort the List of MetadataValue objects based on the MetadataSchema, MetadataField Element,
* MetadataField Qualifier and MetadataField Place in that order.
* @param listToReturn The list to be sorted
* @return The list sorted on those criteria
*/
private List<MetadataValue> sortMetadataValueList(List<MetadataValue> listToReturn) {
Comparator<MetadataValue> comparator = Comparator.comparing(
metadataValue -> metadataValue.getMetadataField().getMetadataSchema().getName(),
Comparator.nullsFirst(Comparator.naturalOrder()));
comparator = comparator.thenComparing(metadataValue -> metadataValue.getMetadataField().getElement(),
Comparator.nullsFirst(Comparator.naturalOrder()));
comparator = comparator.thenComparing(metadataValue -> metadataValue.getMetadataField().getQualifier(),
Comparator.nullsFirst(Comparator.naturalOrder()));
comparator = comparator.thenComparing(metadataValue -> metadataValue.getPlace(),
Comparator.nullsFirst(Comparator.naturalOrder()));
Stream<MetadataValue> metadataValueStream = listToReturn.stream().sorted(comparator);
listToReturn = metadataValueStream.collect(Collectors.toList());
return listToReturn;
}
}

View File

@@ -39,10 +39,6 @@ import org.hibernate.proxy.HibernateProxyHelper;
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "metadataschemaregistry")
public class MetadataSchema implements ReloadableEntity<Integer> {
/**
* Short Name of built-in Dublin Core schema.
*/
public static final String DC_SCHEMA = "dc";
@Id
@Column(name = "metadata_schema_id")

View File

@@ -0,0 +1,39 @@
/**
* 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.content;
/**
* This is an enum that holds track of a few special MetadataSchema types.
* It is important to note that this list is not exhaustive for the MetadataSchema
* types and different MetadataSchema can easily be made.
* These MetadataSchema objects are simply required.
*/
public enum MetadataSchemaEnum {
DC("dc"), RELATION("relation");
/**
* The String representation of the MetadataSchemaEnum
*/
private String name;
/**
* Default constructor with the name parameter
* @param name The name parameter
*/
MetadataSchemaEnum(String name) {
this.name = name;
}
/**
* Generic getter for the String representation of the enum object
* @return The name of the enum object
*/
public String getName() {
return name;
}
}

View File

@@ -71,6 +71,12 @@ public class MetadataValueServiceImpl implements MetadataValueService {
return metadataValueDAO.findByField(context, metadataField);
}
@Override
public Iterator<MetadataValue> findByFieldAndValue(Context context, MetadataField metadataField, String value)
throws SQLException {
return metadataValueDAO.findItemValuesByFieldAndValue(context, metadataField, value);
}
@Override
public void update(Context context, MetadataValue metadataValue) throws SQLException {
metadataValueDAO.save(context, metadataValue);

View File

@@ -0,0 +1,19 @@
/**
* 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.content;
/**
* This Enum holds a representation of all the possible states that a Process can be in
*/
public enum ProcessStatus {
SCHEDULED,
RUNNING,
COMPLETED,
FAILED
}

View File

@@ -0,0 +1,224 @@
/**
* 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.content;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.dspace.core.Context;
import org.dspace.core.ReloadableEntity;
/**
* This class represents a relationship
* It has a leftItem and a rightItem which are both DSpaceObjects
* that have a specified RelationshipType that links them together
* It also has a left and right place column that works just like a normal DSpace metadata place column
*/
@Entity
@Table(name = "relationship")
public class Relationship implements ReloadableEntity<Integer> {
/**
* The Integer ID field for this object
* This is automatically generated
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "relationship_id_seq")
@SequenceGenerator(name = "relationship_id_seq", sequenceName = "relationship_id_seq", allocationSize = 1)
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
protected Integer id;
/**
* The leftItem property for the Relationship object.
* This leftItem is a DSpaceObject and is stored as an ID
*/
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "left_id", nullable = false)
private Item leftItem;
/**
* The relationshipType property for this Relationship object
* This is stored as an ID in the database
*/
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "type_id", nullable = false)
private RelationshipType relationshipType;
/**
* The rightItem property for the Relationship object.
* This rightItem is a DSpaceObject and is stored as an ID
*/
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "right_id", nullable = false)
private Item rightItem;
/**
* An Integer to describe the left place for this relationship
*/
@Column(name = "left_place")
private int leftPlace;
/**
* An Integer to describe the right place for this relationship
*/
@Column(name = "right_place")
private int rightPlace;
/**
* A String containing an alternative value (name variant) for the left side
*/
@Column(name = "leftward_value")
private String leftwardValue;
/**
* A String containing an alternative value (name variant) for the right side
*/
@Column(name = "rightward_value")
private String rightwardValue;
/**
* Protected constructor, create object using:
* {@link org.dspace.content.service.RelationshipService#create(Context)} }
*/
protected Relationship() {}
/**
* Standard setter for the ID field
* @param id The ID to be set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* Standard getter for the leftItem field
* @return The leftItem Item object in this relationship
*/
public Item getLeftItem() {
return leftItem;
}
/**
* Standard setter for the leftItem field
* @param leftItem The leftItem Item object that the leftItem field should be set to
*/
public void setLeftItem(Item leftItem) {
this.leftItem = leftItem;
}
/**
* Standard getter for the relationshipType field
* @return The relationshipType RelationshipType object in this relationship
*/
public RelationshipType getRelationshipType() {
return relationshipType;
}
/**
* Standard setter for the relationshipType field for the Relationship
* @param relationshipType The relationshipType that will be set in this Relationship
*/
public void setRelationshipType(RelationshipType relationshipType) {
this.relationshipType = relationshipType;
}
/**
* Standard getter for the rightItem Item object in this Relationship
* @return the rightItem Item object
*/
public Item getRightItem() {
return rightItem;
}
/**
* Standard setter for the rightItem Item object in this Relationship
* @param rightItem The rightItem Item object that will be used in this relationship
*/
public void setRightItem(Item rightItem) {
this.rightItem = rightItem;
}
/**
* Standard getter for the leftPlace Integer in this Relationship
* @return The leftPlace integer for this relationship
*/
public int getLeftPlace() {
return leftPlace;
}
/**
* Standard setter for the leftPlace Integer in this Relationship
* @param leftPlace the leftPlace Integer that will be used in this relationship
*/
public void setLeftPlace(int leftPlace) {
this.leftPlace = leftPlace;
}
/**
* Standard getter for the rightPlace Integer in this Relationship
* @return the rightPlace integer for this relationship
*/
public int getRightPlace() {
return rightPlace;
}
/**
* Standard setter for the rightPlace Integer in this Relationship
* @param rightPlace the rightPlace Integer that will be used in this relationship
*/
public void setRightPlace(int rightPlace) {
this.rightPlace = rightPlace;
}
/**
* Standard getter for the leftwardValue String in this Relationship
* @return the leftwardValue String for this relationship
*/
public String getLeftwardValue() {
return leftwardValue;
}
/**
* Standard setter for the leftwardValue String in this Relationship
* @param leftwardValue the leftwardValue String that will be used in this relationship
*/
public void setLeftwardValue(String leftwardValue) {
this.leftwardValue = leftwardValue;
}
/**
* Standard getter for the rightwardValue String in this Relationship
* @return the rightwardValue string for this relationship
*/
public String getRightwardValue() {
return rightwardValue;
}
/**
* Standard setter for the rightwardValue String in this Relationship
* @param rightwardValue the rightwardValue String that will be used in this relationship
*/
public void setRightwardValue(String rightwardValue) {
this.rightwardValue = rightwardValue;
}
/**
* Standard getter for the ID for this Relationship
* @return The ID of this relationship
*/
public Integer getID() {
return id;
}
}

View File

@@ -0,0 +1,62 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.virtual.VirtualMetadataPopulator;
import org.dspace.core.Context;
/**
* Interface used for the {@link RelationshipMetadataServiceImpl}
* This will define methods regarding the RelationshipMetadata
*/
public interface RelationshipMetadataService {
/**
* This method retrieves a list of MetadataValue objects that get constructed from processing
* the given Item's Relationships through the config given to the {@link VirtualMetadataPopulator}
* @param item The Item that will be processed through it's Relationships
* @param enableVirtualMetadata This parameter will determine whether the list of Relationship metadata
* should be populated with metadata that is being generated through the
* VirtualMetadataPopulator functionality or not
* @return The list of MetadataValue objects constructed through the Relationships
*/
public List<RelationshipMetadataValue> getRelationshipMetadata(Item item, boolean enableVirtualMetadata);
/**
* Retrieves the list of RelationshipMetadataValue objects specific to only one Relationship of the item.
*
* This method processes one Relationship of an Item and will return a list of RelationshipMetadataValue objects
* that are generated for this specific relationship for the item through the config in VirtualMetadataPopulator
*
* It returns a combination of the output of the findVirtualMetadataFromConfiguration method and
* the getRelationMetadataFromOtherItem method.
*
* @param context The context
* @param item The item whose virtual metadata is requested
* @param entityType The entity type of the given item
* @param relationship The relationship whose virtual metadata is requested
* @param enableVirtualMetadata Determines whether the VirtualMetadataPopulator should be used.
* If false, only the relation."relationname" metadata is populated
* If true, fields from the spring config virtual metadata is included as well
* @return The list of virtual metadata values
*/
public List<RelationshipMetadataValue> findRelationshipMetadataValueForItemRelationship(
Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata)
throws SQLException;
/**
* This method will retrieve the EntityType String from an item
* @param item The Item for which the entityType String will be returned
* @return A String value indicating the entityType
*/
public String getEntityTypeStringFromMetadata(Item item);
}

View File

@@ -0,0 +1,276 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.virtual.VirtualMetadataConfiguration;
import org.dspace.content.virtual.VirtualMetadataPopulator;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
public class RelationshipMetadataServiceImpl implements RelationshipMetadataService {
/**
* log4j category
*/
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger();
@Autowired(required = true)
protected RelationshipService relationshipService;
@Autowired(required = true)
protected VirtualMetadataPopulator virtualMetadataPopulator;
@Autowired(required = true)
protected MetadataFieldService metadataFieldService;
@Override
public List<RelationshipMetadataValue> getRelationshipMetadata(Item item, boolean enableVirtualMetadata) {
Context context = new Context();
List<RelationshipMetadataValue> fullMetadataValueList = new LinkedList<>();
try {
String entityType = getEntityTypeStringFromMetadata(item);
if (StringUtils.isNotBlank(entityType)) {
List<Relationship> relationships = relationshipService.findByItem(context, item);
for (Relationship relationship : relationships) {
fullMetadataValueList
.addAll(findRelationshipMetadataValueForItemRelationship(context, item, entityType,
relationship, enableVirtualMetadata));
}
}
} catch (SQLException e) {
log.error("Lookup for Relationships for item with uuid: " + item.getID() + " caused DSpace to crash", e);
}
return fullMetadataValueList;
}
public String getEntityTypeStringFromMetadata(Item item) {
List<MetadataValue> list = item.getMetadata();
for (MetadataValue mdv : list) {
if (StringUtils.equals(mdv.getMetadataField().getMetadataSchema().getName(),
"relationship")
&& StringUtils.equals(mdv.getMetadataField().getElement(),
"type")) {
return mdv.getValue();
}
}
return null;
}
@Override
public List<RelationshipMetadataValue> findRelationshipMetadataValueForItemRelationship(
Context context, Item item, String entityType, Relationship relationship, boolean enableVirtualMetadata)
throws SQLException {
List<RelationshipMetadataValue> resultingMetadataValueList = new LinkedList<>();
RelationshipType relationshipType = relationship.getRelationshipType();
HashMap<String, VirtualMetadataConfiguration> hashMaps;
String relationName;
Item otherItem;
int place = 0;
boolean isLeftwards;
if (StringUtils.equals(relationshipType.getLeftType().getLabel(), entityType)) {
hashMaps = virtualMetadataPopulator.getMap().get(relationshipType.getLeftwardType());
otherItem = relationship.getRightItem();
relationName = relationship.getRelationshipType().getLeftwardType();
place = relationship.getLeftPlace();
isLeftwards = false; //if the current item is stored on the left,
// the name variant is retrieved from the rightwards label
} else if (StringUtils.equals(relationshipType.getRightType().getLabel(), entityType)) {
hashMaps = virtualMetadataPopulator.getMap().get(relationshipType.getRightwardType());
otherItem = relationship.getLeftItem();
relationName = relationship.getRelationshipType().getRightwardType();
place = relationship.getRightPlace();
isLeftwards = true; //if the current item is stored on the right,
// the name variant is retrieved from the leftwards label
} else {
//No virtual metadata can be created
return resultingMetadataValueList;
}
if (hashMaps != null && enableVirtualMetadata) {
resultingMetadataValueList.addAll(findVirtualMetadataFromConfiguration(context, item, hashMaps,
otherItem, relationName,
relationship, place, isLeftwards));
}
RelationshipMetadataValue relationMetadataFromOtherItem =
getRelationMetadataFromOtherItem(context, otherItem, relationName, relationship.getID(), place);
if (relationMetadataFromOtherItem != null) {
resultingMetadataValueList.add(relationMetadataFromOtherItem);
}
return resultingMetadataValueList;
}
/**
* This method will retrieve a list of RelationshipMetadataValue objects based on the config passed along in the
* hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects
* and the keys of the hashmap will be used to construct the RelationshipMetadataValue object.
*
* @param context The context
* @param item The item whose virtual metadata is requested
* @param hashMaps The list of VirtualMetadataConfiguration objects which will generate the
* virtual metadata. These configurations are applicable for a relationship
* between both items
* @param otherItem The related item whose actual metadata is requested
* @param relationName The name of the relationship
* @param relationship The relationship whose virtual metadata is requested
* @param place The place to use in the virtual metadata
* @param isLeftwards Determines the direction of the virtual metadata
* @return The list of virtual metadata values
*/
private List<RelationshipMetadataValue> findVirtualMetadataFromConfiguration(Context context, Item item,
HashMap<String, VirtualMetadataConfiguration> hashMaps, Item otherItem, String relationName,
Relationship relationship, int place, boolean isLeftwards) throws SQLException {
List<RelationshipMetadataValue> resultingMetadataValueList = new LinkedList<>();
for (Map.Entry<String, VirtualMetadataConfiguration> entry : hashMaps.entrySet()) {
String key = entry.getKey();
VirtualMetadataConfiguration virtualBean = entry.getValue();
if (virtualBean.getPopulateWithNameVariant()) {
String wardLabel = isLeftwards ? relationship.getLeftwardValue() : relationship.getRightwardValue();
if (wardLabel != null) {
resultingMetadataValueList.add(
constructRelationshipMetadataValue(context, item, relationship.getID(), place, key, virtualBean,
wardLabel));
} else {
resultingMetadataValueList.addAll(
findRelationshipMetadataValueFromBean(context, item, otherItem, relationship, place, key,
virtualBean));
}
} else {
resultingMetadataValueList.addAll(
findRelationshipMetadataValueFromBean(context, item, otherItem, relationship, place, key,
virtualBean));
}
}
return resultingMetadataValueList;
}
/**
* This method will retrieve a list of RelationshipMetadataValue objects based on the config passed along in the
* hashmaps parameter. The beans will be used to retrieve the values for the RelationshipMetadataValue objects
* and the keys of the hashmap will be used to construct the RelationshipMetadataValue object.
*
* @param context The context
* @param item The item whose virtual metadata is requested
* @param otherItem The related item whose actual metadata is requested
* @param relationship The relationship whose virtual metadata is requested
* @param place The place to use in the virtual metadata
* @param key The key corresponding to the VirtualMetadataConfiguration
* @param virtualBean The VirtualMetadataConfiguration object which will generate the
* virtual metadata. This configuration is applicable for a relationship
* between both items
* @return The list of virtual metadata values
*/
private List<RelationshipMetadataValue> findRelationshipMetadataValueFromBean(
Context context, Item item, Item otherItem, Relationship relationship, int place,
String key, VirtualMetadataConfiguration virtualBean) throws SQLException {
List<RelationshipMetadataValue> resultingMetadataValueList = new LinkedList<>();
for (String value : virtualBean.getValues(context, otherItem)) {
RelationshipMetadataValue relationshipMetadataValue = constructRelationshipMetadataValue(context, item,
relationship
.getID(),
place,
key, virtualBean,
value);
if (relationshipMetadataValue != null) {
resultingMetadataValueList.add(relationshipMetadataValue);
}
}
return resultingMetadataValueList;
}
//This method will construct a RelationshipMetadataValue object with proper schema, element, qualifier,
//authority, item, place and useForPlace based on the key String parameter passed along to it
private RelationshipMetadataValue constructRelationshipMetadataValue(Context context, Item item,
Integer relationshipId, int place,
String key,
VirtualMetadataConfiguration virtualBean,
String value) {
RelationshipMetadataValue metadataValue = constructMetadataValue(context, key);
if (metadataValue != null) {
metadataValue = constructResultingMetadataValue(item, value, metadataValue, relationshipId);
metadataValue.setUseForPlace(virtualBean.getUseForPlace());
metadataValue.setPlace(place);
if (StringUtils.isNotBlank(metadataValue.getValue())) {
return metadataValue;
}
}
return null;
}
//This method will construct a RelationshipMetadataValue object with proper schema, element and qualifier based
//on the key String parameter passed along to it
private RelationshipMetadataValue constructMetadataValue(Context context, String key) {
String[] splittedKey = key.split("\\.");
RelationshipMetadataValue metadataValue = new RelationshipMetadataValue();
String metadataSchema = splittedKey.length > 0 ? splittedKey[0] : null;
String metadataElement = splittedKey.length > 1 ? splittedKey[1] : null;
String metadataQualifier = splittedKey.length > 2 ? splittedKey[2] : null;
MetadataField metadataField = null;
try {
metadataField = metadataFieldService
.findByElement(context, metadataSchema, metadataElement, metadataQualifier);
} catch (SQLException e) {
log.error("Could not find element with MetadataSchema: " + metadataSchema +
", MetadataElement: " + metadataElement + " and MetadataQualifier: " + metadataQualifier, e);
return null;
}
if (metadataField == null) {
log.error("A MetadataValue was attempted to construct with MetadataField for parameters: " +
"metadataschema: {}, metadataelement: {}, metadataqualifier: {}",
metadataSchema, metadataElement, metadataQualifier);
return null;
}
metadataValue.setMetadataField(metadataField);
metadataValue.setLanguage(Item.ANY);
return metadataValue;
}
//This method will update a RelationshipMetadataValue object with authority info and relation to the item
private RelationshipMetadataValue constructResultingMetadataValue(Item item, String value,
RelationshipMetadataValue metadataValue,
Integer relationshipId) {
metadataValue.setValue(value);
metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId);
metadataValue.setConfidence(-1);
metadataValue.setDSpaceObject(item);
return metadataValue;
}
// This method will create the Relationship Metadatavalue that describes the relationship type and has the ID
// of the other item as value
private RelationshipMetadataValue getRelationMetadataFromOtherItem(Context context, Item otherItem,
String relationName,
Integer relationshipId, int place) {
RelationshipMetadataValue metadataValue = constructMetadataValue(context,
MetadataSchemaEnum.RELATION
.getName() + "." + relationName);
if (metadataValue != null) {
metadataValue.setAuthority(Constants.VIRTUAL_AUTHORITY_PREFIX + relationshipId);
metadataValue.setValue(otherItem.getID().toString());
metadataValue.setPlace(place);
return metadataValue;
}
return null;
}
}

View File

@@ -0,0 +1,60 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content;
/**
* This class is used as a representation of MetadataValues for the MetadataValues that are derived from the
* Relationships that the item has. This includes the useForPlace property which we'll have to use to determine
* whether these Values should be counted for place calculation on both the native MetadataValues and the
* Relationship's place attributes.
*/
public class RelationshipMetadataValue extends MetadataValue {
/**
* This property determines whether this RelationshipMetadataValue should be used in place calculation or not
*/
private boolean useForPlace;
/**
* This property determines whether this RelationshipMetadataValue should be used in place calculation or not.
* This is retrieved from Spring configuration when constructing RelationshipMetadataValues. This Spring
* configuration is located in the core-services.xml configuration file.
* Putting this property on true will imply that we're now mixing plain-text metadatavalues with the
* metadatavalues that are constructed through Relationships with regards to the place attribute.
* For example, currently the RelationshipMetadataValue dc.contributor.author that is constructed through a
* Relationship for a Publication will have its useForPlace set to true. This means that the place
* calculation will take both these RelationshipMetadataValues into account together with the normal
* plain text metadatavalues.
* On the other hand, the journal name, volume and issue number which are constructed through a
* Relationship from a Publication to a journal issue will have its useForPlace set to false.
* This would typically be set to false for any singular metadata, and for any relationship where no mixing
* with plain text variables is applicable
*/
public boolean isUseForPlace() {
return useForPlace;
}
public void setUseForPlace(boolean useForPlace) {
this.useForPlace = useForPlace;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (! (obj instanceof RelationshipMetadataValue)) {
return false;
}
final RelationshipMetadataValue other = (RelationshipMetadataValue) obj;
if (this.isUseForPlace() != other.isUseForPlace()) {
return false;
}
return super.equals(obj);
}
}

View File

@@ -0,0 +1,540 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.dao.RelationshipDAO;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.virtual.VirtualMetadataPopulator;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
public class RelationshipServiceImpl implements RelationshipService {
private static final Logger log = LogManager.getLogger();
@Autowired(required = true)
protected RelationshipDAO relationshipDAO;
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Autowired(required = true)
protected ItemService itemService;
@Autowired(required = true)
protected RelationshipTypeService relationshipTypeService;
@Autowired
private RelationshipMetadataService relationshipMetadataService;
@Autowired
private VirtualMetadataPopulator virtualMetadataPopulator;
@Override
public Relationship create(Context context) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify relationship");
}
return relationshipDAO.create(context, new Relationship());
}
@Override
public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType,
int leftPlace, int rightPlace) throws AuthorizeException, SQLException {
return create(c, leftItem, rightItem, relationshipType, leftPlace, rightPlace, null, null);
}
@Override
public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType,
int leftPlace, int rightPlace, String leftwardValue, String rightwardValue)
throws AuthorizeException, SQLException {
Relationship relationship = new Relationship();
relationship.setLeftItem(leftItem);
relationship.setRightItem(rightItem);
relationship.setRelationshipType(relationshipType);
relationship.setLeftPlace(leftPlace);
relationship.setRightPlace(rightPlace);
relationship.setLeftwardValue(leftwardValue);
relationship.setRightwardValue(rightwardValue);
return create(c, relationship);
}
@Override
public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException {
if (isRelationshipValidToCreate(context, relationship)) {
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
// This order of execution should be handled in the creation (create, updateplace, update relationship)
// for a proper place allocation
Relationship relationshipToReturn = relationshipDAO.create(context, relationship);
updatePlaceInRelationship(context, relationshipToReturn);
update(context, relationshipToReturn);
return relationshipToReturn;
} else {
throw new AuthorizeException(
"You do not have write rights on this relationship's items");
}
} else {
throw new IllegalArgumentException("The relationship given was not valid");
}
}
@Override
public void updatePlaceInRelationship(Context context, Relationship relationship)
throws SQLException, AuthorizeException {
Item leftItem = relationship.getLeftItem();
// Max value is used to ensure that these will get added to the back of the list and thus receive the highest
// (last) place as it's set to a -1 for creation
if (relationship.getLeftPlace() == -1) {
relationship.setLeftPlace(Integer.MAX_VALUE);
}
Item rightItem = relationship.getRightItem();
if (relationship.getRightPlace() == -1) {
relationship.setRightPlace(Integer.MAX_VALUE);
}
List<Relationship> leftRelationships = findByItemAndRelationshipType(context,
leftItem,
relationship.getRelationshipType(), true);
List<Relationship> rightRelationships = findByItemAndRelationshipType(context,
rightItem,
relationship.getRelationshipType(),
false);
// These relationships are only deleted from the temporary lists incase they're present in them so that we can
// properly perform our place calculation later down the line in this method.
if (leftRelationships.contains(relationship)) {
leftRelationships.remove(relationship);
}
if (rightRelationships.contains(relationship)) {
rightRelationships.remove(relationship);
}
context.turnOffAuthorisationSystem();
//If useForPlace for the leftwardType is false for the relationshipType,
// we need to sort the relationships here based on leftplace.
if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), true)) {
if (!leftRelationships.isEmpty()) {
leftRelationships.sort(Comparator.comparingInt(Relationship::getLeftPlace));
for (int i = 0; i < leftRelationships.size(); i++) {
leftRelationships.get(i).setLeftPlace(i);
}
relationship.setLeftPlace(leftRelationships.size());
} else {
relationship.setLeftPlace(0);
}
} else {
updateItem(context, leftItem);
}
//If useForPlace for the rightwardType is false for the relationshipType,
// we need to sort the relationships here based on the rightplace.
if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), false)) {
if (!rightRelationships.isEmpty()) {
rightRelationships.sort(Comparator.comparingInt(Relationship::getRightPlace));
for (int i = 0; i < rightRelationships.size(); i++) {
rightRelationships.get(i).setRightPlace(i);
}
relationship.setRightPlace(rightRelationships.size());
} else {
relationship.setRightPlace(0);
}
} else {
updateItem(context, rightItem);
}
context.restoreAuthSystemState();
}
@Override
public void updateItem(Context context, Item relatedItem)
throws SQLException, AuthorizeException {
relatedItem.setMetadataModified();
itemService.update(context, relatedItem);
}
@Override
public int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException {
return relationshipDAO.findNextLeftPlaceByLeftItem(context, item);
}
@Override
public int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException {
return relationshipDAO.findNextRightPlaceByRightItem(context, item);
}
private boolean isRelationshipValidToCreate(Context context, Relationship relationship) throws SQLException {
RelationshipType relationshipType = relationship.getRelationshipType();
if (!verifyEntityTypes(relationship.getLeftItem(), relationshipType.getLeftType())) {
log.warn("The relationship has been deemed invalid since the leftItem" +
" and leftType do no match on entityType");
logRelationshipTypeDetailsForError(relationshipType);
return false;
}
if (!verifyEntityTypes(relationship.getRightItem(), relationshipType.getRightType())) {
log.warn("The relationship has been deemed invalid since the rightItem" +
" and rightType do no match on entityType");
logRelationshipTypeDetailsForError(relationshipType);
return false;
}
if (!verifyMaxCardinality(context, relationship.getLeftItem(),
relationshipType.getLeftMaxCardinality(), relationshipType)) {
log.warn("The relationship has been deemed invalid since the left item has more" +
" relationships than the left max cardinality allows after we'd store this relationship");
logRelationshipTypeDetailsForError(relationshipType);
return false;
}
if (!verifyMaxCardinality(context, relationship.getRightItem(),
relationshipType.getRightMaxCardinality(), relationshipType)) {
log.warn("The relationship has been deemed invalid since the right item has more" +
" relationships than the right max cardinality allows after we'd store this relationship");
logRelationshipTypeDetailsForError(relationshipType);
return false;
}
return true;
}
private void logRelationshipTypeDetailsForError(RelationshipType relationshipType) {
log.warn("The relationshipType's ID is: " + relationshipType.getID());
log.warn("The relationshipType's leftward type is: " + relationshipType.getLeftwardType());
log.warn("The relationshipType's rightward type is: " + relationshipType.getRightwardType());
log.warn("The relationshipType's left entityType label is: " + relationshipType.getLeftType().getLabel());
log.warn("The relationshipType's right entityType label is: " + relationshipType.getRightType().getLabel());
log.warn("The relationshipType's left min cardinality is: " + relationshipType.getLeftMinCardinality());
log.warn("The relationshipType's left max cardinality is: " + relationshipType.getLeftMaxCardinality());
log.warn("The relationshipType's right min cardinality is: " + relationshipType.getRightMinCardinality());
log.warn("The relationshipType's right max cardinality is: " + relationshipType.getRightMaxCardinality());
}
private boolean verifyMaxCardinality(Context context, Item itemToProcess,
Integer maxCardinality,
RelationshipType relationshipType) throws SQLException {
List<Relationship> rightRelationships = findByItemAndRelationshipType(context, itemToProcess, relationshipType,
false);
if (maxCardinality != null && rightRelationships.size() >= maxCardinality) {
return false;
}
return true;
}
private boolean verifyEntityTypes(Item itemToProcess, EntityType entityTypeToProcess) {
List<MetadataValue> list = itemService.getMetadata(itemToProcess, "relationship", "type", null, Item.ANY);
if (list.isEmpty()) {
return false;
}
String leftEntityType = list.get(0).getValue();
return StringUtils.equals(leftEntityType, entityTypeToProcess.getLabel());
}
public Relationship find(Context context, int id) throws SQLException {
Relationship relationship = relationshipDAO.findByID(context, Relationship.class, id);
return relationship;
}
@Override
public List<Relationship> findByItem(Context context, Item item) throws SQLException {
return findByItem(context, item, -1, -1);
}
@Override
public List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset)
throws SQLException {
List<Relationship> list = relationshipDAO.findByItem(context, item, limit, offset);
list.sort((o1, o2) -> {
int relationshipType = o1.getRelationshipType().getLeftwardType()
.compareTo(o2.getRelationshipType().getLeftwardType());
if (relationshipType != 0) {
return relationshipType;
} else {
if (o1.getLeftItem() == item) {
return o1.getLeftPlace() - o2.getLeftPlace();
} else {
return o1.getRightPlace() - o2.getRightPlace();
}
}
});
return list;
}
@Override
public List<Relationship> findAll(Context context) throws SQLException {
return findAll(context, -1, -1);
}
@Override
public List<Relationship> findAll(Context context, Integer limit, Integer offset) throws SQLException {
return relationshipDAO.findAll(context, Relationship.class, limit, offset);
}
@Override
public void update(Context context, Relationship relationship) throws SQLException, AuthorizeException {
update(context, Collections.singletonList(relationship));
}
@Override
public void update(Context context, List<Relationship> relationships) throws SQLException, AuthorizeException {
if (CollectionUtils.isNotEmpty(relationships)) {
for (Relationship relationship : relationships) {
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
if (isRelationshipValidToCreate(context, relationship)) {
relationshipDAO.save(context, relationship);
}
} else {
throw new AuthorizeException("You do not have write rights on this relationship's items");
}
}
}
}
@Override
public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException {
//TODO: retrieve default settings from configuration
delete(context, relationship, false, false);
}
@Override
public void delete(Context context, Relationship relationship, boolean copyToLeftItem, boolean copyToRightItem)
throws SQLException, AuthorizeException {
log.info(org.dspace.core.LogManager.getHeader(context, "delete_relationship",
"relationship_id=" + relationship.getID() + "&" +
"copyMetadataValuesToLeftItem=" + copyToLeftItem + "&" +
"copyMetadataValuesToRightItem=" + copyToRightItem));
if (isRelationshipValidToDelete(context, relationship) &&
copyToItemPermissionCheck(context, relationship, copyToLeftItem, copyToRightItem)) {
// To delete a relationship, a user must have WRITE permissions on one of the related Items
copyMetadataValues(context, relationship, copyToLeftItem, copyToRightItem);
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
relationshipDAO.delete(context, relationship);
updatePlaceInRelationship(context, relationship);
} else {
throw new AuthorizeException(
"You do not have write rights on this relationship's items");
}
} else {
throw new IllegalArgumentException("The relationship given was not valid");
}
}
/**
* Converts virtual metadata from RelationshipMetadataValue objects to actual item metadata.
*
* @param context The relevant DSpace context
* @param relationship The relationship containing the left and right items
* @param copyToLeftItem The boolean indicating whether we want to write to left item or not
* @param copyToRightItem The boolean indicating whether we want to write to right item or not
*/
private void copyMetadataValues(Context context, Relationship relationship, boolean copyToLeftItem,
boolean copyToRightItem)
throws SQLException, AuthorizeException {
if (copyToLeftItem) {
String entityTypeString = relationshipMetadataService
.getEntityTypeStringFromMetadata(relationship.getLeftItem());
List<RelationshipMetadataValue> relationshipMetadataValues =
relationshipMetadataService.findRelationshipMetadataValueForItemRelationship(context,
relationship.getLeftItem(), entityTypeString, relationship, true);
for (RelationshipMetadataValue relationshipMetadataValue : relationshipMetadataValues) {
itemService.addMetadata(context, relationship.getLeftItem(),
relationshipMetadataValue.getMetadataField(), null,
relationshipMetadataValue.getValue() );
}
itemService.update(context, relationship.getLeftItem());
}
if (copyToRightItem) {
String entityTypeString = relationshipMetadataService
.getEntityTypeStringFromMetadata(relationship.getRightItem());
List<RelationshipMetadataValue> relationshipMetadataValues =
relationshipMetadataService.findRelationshipMetadataValueForItemRelationship(context,
relationship.getRightItem(), entityTypeString, relationship, true);
for (RelationshipMetadataValue relationshipMetadataValue : relationshipMetadataValues) {
itemService.addMetadata(context, relationship.getRightItem(),
relationshipMetadataValue.getMetadataField(), null,
relationshipMetadataValue.getValue() );
}
itemService.update(context, relationship.getRightItem());
}
}
/**
* This method will check if the current user has sufficient rights to write to the respective items if requested
* @param context The relevant DSpace context
* @param relationship The relationship containing the left and right items
* @param copyToLeftItem The boolean indicating whether we want to write to left item or not
* @param copyToRightItem The boolean indicating whether we want to write to right item or not
* @return A boolean indicating whether the permissions are okay for this request
* @throws AuthorizeException If something goes wrong
* @throws SQLException If something goes wrong
*/
private boolean copyToItemPermissionCheck(Context context, Relationship relationship,
boolean copyToLeftItem, boolean copyToRightItem) throws SQLException {
boolean isPermissionCorrect = true;
if (copyToLeftItem) {
if (!authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE)) {
isPermissionCorrect = false;
}
}
if (copyToRightItem) {
if (!authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
isPermissionCorrect = false;
}
}
return isPermissionCorrect;
}
private boolean isRelationshipValidToDelete(Context context, Relationship relationship) throws SQLException {
if (relationship == null) {
log.warn("The relationship has been deemed invalid since the relation was null");
return false;
}
if (relationship.getID() == null) {
log.warn("The relationship has been deemed invalid since the ID" +
" off the given relationship was null");
return false;
}
if (this.find(context, relationship.getID()) == null) {
log.warn("The relationship has been deemed invalid since the relationship" +
" is not present in the DB with the current ID");
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
return false;
}
if (!checkMinCardinality(context, relationship.getLeftItem(),
relationship, relationship.getRelationshipType().getLeftMinCardinality(), true)) {
log.warn("The relationship has been deemed invalid since the leftMinCardinality" +
" constraint would be violated upon deletion");
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
return false;
}
if (!checkMinCardinality(context, relationship.getRightItem(),
relationship, relationship.getRelationshipType().getRightMinCardinality(), false)) {
log.warn("The relationship has been deemed invalid since the rightMinCardinality" +
" constraint would be violated upon deletion");
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
return false;
}
return true;
}
private boolean checkMinCardinality(Context context, Item item,
Relationship relationship,
Integer minCardinality, boolean isLeft) throws SQLException {
List<Relationship> list = this.findByItemAndRelationshipType(context, item, relationship.getRelationshipType(),
isLeft, -1, -1);
if (minCardinality != null && !(list.size() > minCardinality)) {
return false;
}
return true;
}
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType, boolean isLeft)
throws SQLException {
return this.findByItemAndRelationshipType(context, item, relationshipType, isLeft, -1, -1);
}
@Override
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType)
throws SQLException {
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, -1, -1);
}
@Override
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType, int limit, int offset)
throws SQLException {
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, limit, offset);
}
@Override
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType, boolean isLeft,
int limit, int offset)
throws SQLException {
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, isLeft, limit, offset);
}
@Override
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType)
throws SQLException {
return findByRelationshipType(context, relationshipType, -1, -1);
}
@Override
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType, Integer limit,
Integer offset)
throws SQLException {
return relationshipDAO.findByRelationshipType(context, relationshipType, limit, offset);
}
@Override
public List<Relationship> findByTypeName(Context context, String typeName)
throws SQLException {
return this.findByTypeName(context, typeName, -1, -1);
}
@Override
public List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset)
throws SQLException {
return relationshipDAO.findByTypeName(context, typeName, limit, offset);
}
@Override
public int countTotal(Context context) throws SQLException {
return relationshipDAO.countRows(context);
}
@Override
public int countByItem(Context context, Item item) throws SQLException {
return relationshipDAO.countByItem(context, item);
}
@Override
public int countByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException {
return relationshipDAO.countByRelationshipType(context, relationshipType);
}
@Override
public int countByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType)
throws SQLException {
return relationshipDAO.countByItemAndRelationshipType(context, item, relationshipType);
}
@Override
public int countByTypeName(Context context, String typeName)
throws SQLException {
return relationshipDAO.countByTypeName(context, typeName);
}
}

View File

@@ -0,0 +1,254 @@
/**
* 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.content;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.dspace.core.Context;
import org.dspace.core.ReloadableEntity;
/**
* Class representing a RelationshipType
* This class contains an Integer ID that will be the unique value and primary key in the database.
* This key is automatically generated
* It also has a leftType and rightType EntityType that describes the relationshipType together with a leftwardType and
* rightwardType.
* The cardinality properties describe how many of each relations this relationshipType can support
*/
@Entity
@Table(name = "relationship_type")
public class RelationshipType implements ReloadableEntity<Integer> {
/**
* The Integer ID used as a primary key for this database object.
* This is generated by a sequence
*/
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "relationship_type_id_seq")
@SequenceGenerator(name = "relationship_type_id_seq", sequenceName = "relationship_type_id_seq", allocationSize = 1)
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
protected Integer id;
/**
* The leftType EntityType field for the relationshipType
* This is stored as an ID and cannot be null
*/
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST})
@JoinColumn(name = "left_type", nullable = false)
private EntityType leftType;
/**
* The rightType EntityType field for the relationshipType
* This is stored as an ID and cannot be null
*/
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST})
@JoinColumn(name = "right_type", nullable = false)
private EntityType rightType;
/**
* The leftwardType String field for the relationshipType
* This is stored as a String and cannot be null
* This is a textual representation of the name of the relationship that this RelationshipType is connected to
*/
@Column(name = "leftward_type", nullable = false)
private String leftwardType;
/**
* The rightwardType String field for the relationshipType
* This is stored as a String and cannot be null
* This is a textual representation of the name of the relationship that this RelationshipType is connected to
*/
@Column(name = "rightward_type", nullable = false)
private String rightwardType;
/**
* The minimum amount of relations for the leftItem that need to be present at all times
* This is stored as an Integer
*/
@Column(name = "left_min_cardinality")
private Integer leftMinCardinality;
/**
* The maximum amount of relations for the leftItem that can to be present at all times
* This is stored as an Integer
*/
@Column(name = "left_max_cardinality")
private Integer leftMaxCardinality;
/**
* The minimum amount of relations for the rightItem that need to be present at all times
*/
@Column(name = "right_min_cardinality")
private Integer rightMinCardinality;
/**
* Tha maximum amount of relations for the rightItem that can be present at all times
*/
@Column(name = "right_max_cardinality")
private Integer rightMaxCardinality;
/**
* Protected constructor, create object using:
* {@link org.dspace.content.service.RelationshipTypeService#create(Context)} }
*/
protected RelationshipType() {}
/**
* Standard getter for the ID of this RelationshipType
* @param id The ID that this RelationshipType should receive
*/
public void setId(Integer id) {
this.id = id;
}
/**
* Standard getter for The leftType EntityType for this RelationshipType
* @return The leftType EntityType of this RelationshipType
*/
public EntityType getLeftType() {
return leftType;
}
/**
* Standard setter for the leftType EntityType for this RelationshipType
* @param leftType The leftType EntityType that this RelationshipType should receive
*/
public void setLeftType(EntityType leftType) {
this.leftType = leftType;
}
/**
* Standard getter for The rightType EntityType for this RelationshipType
* @return The rightType EntityType of this RelationshipType
*/
public EntityType getRightType() {
return rightType;
}
/**
* Standard setter for the rightType EntityType for this RelationshipType
* @param rightType The rightType EntityType that this RelationshipType should receive
*/
public void setRightType(EntityType rightType) {
this.rightType = rightType;
}
/**
* Standard getter for the leftwardType String for this RelationshipType
* @return The leftwardType String of this RelationshipType
*/
public String getLeftwardType() {
return leftwardType;
}
/**
* Standard setter for the leftwardType String for this RelationshipType
* @param leftwardType The leftwardType String that this RelationshipType should receive
*/
public void setLeftwardType(String leftwardType) {
this.leftwardType = leftwardType;
}
/**
* Standard getter for the rightwardType String for this RelationshipType
* @return The rightwardType String of this RelationshipType
*/
public String getRightwardType() {
return rightwardType;
}
/**
* Standard setter for the rightwardType String for this RelationshipType
* @param rightwardType The rightwardType String that this RelationshipType should receive
*/
public void setRightwardType(String rightwardType) {
this.rightwardType = rightwardType;
}
/**
* Standard getter for the leftMinCardinality Integer for this RelationshipType
* @return the leftMinCardinality Integer of this RelationshipType
*/
public Integer getLeftMinCardinality() {
return leftMinCardinality;
}
/**
* Standard setter for the leftMinCardinality Integer for this RelationshipType
* @param leftMinCardinality The leftMinCardinality Integer that this RelationshipType should recieve
*/
public void setLeftMinCardinality(Integer leftMinCardinality) {
this.leftMinCardinality = leftMinCardinality;
}
/**
* Standard getter for the leftMaxCardinality Integer for this RelationshipType
* @return the leftMaxCardinality Integer of this RelationshipType
*/
public Integer getLeftMaxCardinality() {
return leftMaxCardinality;
}
/**
* Standard setter for the leftMaxCardinality Integer for this RelationshipType
* @param leftMaxCardinality The leftMaxCardinality Integer that this RelationshipType should recieve
*/
public void setLeftMaxCardinality(Integer leftMaxCardinality) {
this.leftMaxCardinality = leftMaxCardinality;
}
/**
* Standard getter for the rightMinCardinality Integer for this RelationshipType
* @return the rightMinCardinality Integer of this RelationshipType
*/
public Integer getRightMinCardinality() {
return rightMinCardinality;
}
/**
* Standard setter for the rightMinCardinality Integer for this RelationshipType
* @param rightMinCardinality The rightMinCardinality Integer that this RelationshipType should recieve
*/
public void setRightMinCardinality(Integer rightMinCardinality) {
this.rightMinCardinality = rightMinCardinality;
}
/**
* Standard getter for the rightMaxCardinality Integer for this RelationshipType
* @return the rightMaxCardinality Integer of this RelationshipType
*/
public Integer getRightMaxCardinality() {
return rightMaxCardinality;
}
/**
* Standard setter for the rightMaxCardinality Integer for this RelationshipType
* @param rightMaxCardinality The rightMaxCardinality Integer that this RelationshipType should recieve
*/
public void setRightMaxCardinality(Integer rightMaxCardinality) {
this.rightMaxCardinality = rightMaxCardinality;
}
/**
* Standard getter for the ID of this RelationshipType
* @return The ID of this RelationshipType
*/
public Integer getID() {
return id;
}
}

View File

@@ -0,0 +1,155 @@
/**
* 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.content;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.dao.RelationshipTypeDAO;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
public class RelationshipTypeServiceImpl implements RelationshipTypeService {
@Autowired(required = true)
protected RelationshipTypeDAO relationshipTypeDAO;
@Autowired(required = true)
protected AuthorizeService authorizeService;
@Override
public RelationshipType create(Context context) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify relationshipType");
}
return relationshipTypeDAO.create(context, new RelationshipType());
}
@Override
public RelationshipType create(Context context, RelationshipType relationshipType)
throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify relationshipType");
}
return relationshipTypeDAO.create(context, relationshipType);
}
@Override
public RelationshipType findbyTypesAndTypeName(Context context,EntityType leftType,EntityType rightType,
String leftwardType,String rightwardType) throws SQLException {
return relationshipTypeDAO.findbyTypesAndTypeName(context, leftType, rightType, leftwardType, rightwardType);
}
@Override
public List<RelationshipType> findAll(Context context) throws SQLException {
return findAll(context, -1, -1);
}
@Override
public List<RelationshipType> findAll(Context context, Integer limit, Integer offset) throws SQLException {
return relationshipTypeDAO.findAll(context, RelationshipType.class, limit, offset);
}
@Override
public List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String typeName)
throws SQLException {
return findByLeftwardOrRightwardTypeName(context, typeName, -1, -1);
}
@Override
public List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String typeName, Integer limit,
Integer offset)
throws SQLException {
return relationshipTypeDAO.findByLeftwardOrRightwardTypeName(context, typeName, limit, offset);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType) throws SQLException {
return findByEntityType(context, entityType, -1, -1);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType,
Integer limit, Integer offset) throws SQLException {
return relationshipTypeDAO.findByEntityType(context, entityType, limit, offset);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType, boolean isLeft)
throws SQLException {
return findByEntityType(context, entityType, isLeft, -1, -1);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType, boolean isLeft,
Integer limit, Integer offset) throws SQLException {
return relationshipTypeDAO.findByEntityType(context, entityType, isLeft, limit, offset);
}
@Override
public RelationshipType create(Context context, EntityType leftEntityType, EntityType rightEntityType,
String leftwardType, String rightwardType, Integer leftCardinalityMinInteger,
Integer leftCardinalityMaxInteger, Integer rightCardinalityMinInteger,
Integer rightCardinalityMaxInteger)
throws SQLException, AuthorizeException {
RelationshipType relationshipType = new RelationshipType();
relationshipType.setLeftType(leftEntityType);
relationshipType.setRightType(rightEntityType);
relationshipType.setLeftwardType(leftwardType);
relationshipType.setRightwardType(rightwardType);
relationshipType.setLeftMinCardinality(leftCardinalityMinInteger);
relationshipType.setLeftMaxCardinality(leftCardinalityMaxInteger);
relationshipType.setRightMinCardinality(rightCardinalityMinInteger);
relationshipType.setRightMaxCardinality(rightCardinalityMaxInteger);
return create(context, relationshipType);
}
@Override
public RelationshipType find(Context context,int id) throws SQLException {
return relationshipTypeDAO.findByID(context, RelationshipType.class, id);
}
@Override
public void update(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException {
update(context,Collections.singletonList(relationshipType));
}
@Override
public void update(Context context,List<RelationshipType> relationshipTypes)
throws SQLException, AuthorizeException {
if (CollectionUtils.isNotEmpty(relationshipTypes)) {
// Check authorisation - only administrators can change formats
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can modify RelationshipType");
}
for (RelationshipType relationshipType : relationshipTypes) {
relationshipTypeDAO.save(context, relationshipType);
}
}
}
@Override
public void delete(Context context,RelationshipType relationshipType) throws SQLException, AuthorizeException {
if (!authorizeService.isAdmin(context)) {
throw new AuthorizeException(
"Only administrators can delete entityType");
}
relationshipTypeDAO.delete(context, relationshipType);
}
}

View File

@@ -220,6 +220,11 @@ public final class ChoiceAuthorityServiceImpl implements ChoiceAuthorityService
return controller;
}
@Override
public void clearCache() {
controller.clear();
authorities.clear();
}
private void loadChoiceAuthorityConfigurations() {
// Get all configuration keys starting with a given prefix
List<String> propKeys = configurationService.getPropertyKeys(CHOICES_PLUGIN_PREFIX);

View File

@@ -241,7 +241,7 @@ public class DSpaceControlledVocabulary extends SelfNamedPlugin implements Choic
} catch (XPathExpressionException e) {
log.warn(e.getMessage(), e);
}
return new Choice("", "", "");
return null;
}
private void readNode(String[] authorities, String[] values, String[] labels, String[] parent, String[] notes,

View File

@@ -65,7 +65,7 @@ public class InputFormSelfRegisterWrapperAuthority implements ChoiceAuthority {
}
}
if (!choices.isEmpty()) {
Choice[] results = new Choice[choices.size() - 1];
Choice[] results = new Choice[choices.size()];
choices.toArray(results);
return new Choices(results, 0, choices.size(), Choices.CF_AMBIGUOUS, false);
}

View File

@@ -1,59 +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.content.authority;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import org.dspace.content.Collection;
/**
* Sample Journal-name authority based on SHERPA/RoMEO
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOProtocol
*/
public class SHERPARoMEOJournalTitle extends SHERPARoMEOProtocol {
private static final String RESULT = "journal";
private static final String LABEL = "jtitle";
private static final String AUTHORITY = "issn";
public SHERPARoMEOJournalTitle() {
super();
}
@Override
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
// punt if there is no query text
if (text == null || text.trim().length() == 0) {
return new Choices(true);
}
// query args to add to SHERPA/RoMEO request URL
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("jtitle", text));
args.add(new BasicNameValuePair("qtype", "contains")); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null) {
result = new Choices(true);
}
return result;
}
@Override
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
return getMatches(text, collection, start, limit, locale);
}
}

View File

@@ -1,228 +0,0 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.authority;
import java.io.IOException;
import java.util.List;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.core.ConfigurationManager;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
/**
* Choice Authority based on SHERPA/RoMEO - for Publishers and Journals
* See the subclasses SHERPARoMEOPublisher and SHERPARoMEOJournalTitle
* for actual choice plugin implementations. This is a superclass
* containing all the common protocol logic.
*
* Reads these DSpace Config properties:
*
* # contact URL for server
* sherpa.romeo.url = http://www.sherpa.ac.uk/romeoapi11.php
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOPublisher
* @see SHERPARoMEOJournalTitle
*/
public abstract class SHERPARoMEOProtocol implements ChoiceAuthority {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(SHERPARoMEOProtocol.class);
// contact URL from configuration
private static String url = null;
public SHERPARoMEOProtocol() {
if (url == null) {
url = ConfigurationManager.getProperty("sherpa.romeo.url");
// sanity check
if (url == null) {
throw new IllegalStateException("Missing DSpace configuration keys for SHERPA/RoMEO Query");
}
}
}
// this implements the specific RoMEO API args and XML tag naming
public abstract Choices getMatches(String text, Collection collection, int start, int limit, String locale);
@Override
public Choices getBestMatch(String field, String text, Collection collection, String locale) {
return getMatches(field, text, collection, 0, 2, locale);
}
// XXX FIXME just punt, returning value, never got around to
// implementing a reverse query.
@Override
public String getLabel(String field, String key, String locale) {
return key;
}
// NOTE - ignore limit and start for now
protected Choices query(String result, String label, String authority,
List<BasicNameValuePair> args, int start, int limit) {
HttpClient hc = new DefaultHttpClient();
String srUrl = url + "?" + URLEncodedUtils.format(args, "UTF8");
HttpGet get = new HttpGet(srUrl);
log.debug("Trying SHERPA/RoMEO Query, URL=" + srUrl);
try {
HttpResponse response = hc.execute(get);
if (response.getStatusLine().getStatusCode() == 200) {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
SRHandler handler = new SRHandler(result, label, authority);
// XXX FIXME: should turn off validation here explicitly, but
// it seems to be off by default.
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setContentHandler(handler);
xr.setErrorHandler(handler);
xr.parse(new InputSource(response.getEntity().getContent()));
int confidence;
if (handler.total == 0) {
confidence = Choices.CF_NOTFOUND;
} else if (handler.total == 1) {
confidence = Choices.CF_UNCERTAIN;
} else {
confidence = Choices.CF_AMBIGUOUS;
}
return new Choices(handler.result, start, handler.total, confidence, false);
}
} catch (IOException e) {
log.error("SHERPA/RoMEO query failed: ", e);
return null;
} catch (ParserConfigurationException e) {
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
} catch (SAXException e) {
log.warn("Failed parsing SHERPA/RoMEO result: ", e);
return null;
} finally {
get.releaseConnection();
}
return null;
}
// SAX handler to grab SHERPA/RoMEO (and eventually other details) from result
private static class SRHandler
extends DefaultHandler {
private Choice result[] = null;
int rindex = 0; // result index
int total = 0;
// name of element containing a result, e.g. <journal>
private String resultElement = null;
// name of element containing the label e.g. <name>
private String labelElement = null;
// name of element containing the authority value e.g. <issn>
private String authorityElement = null;
protected String textValue = null;
public SRHandler(String result, String label, String authority) {
super();
resultElement = result;
labelElement = label;
authorityElement = authority;
}
// NOTE: text value MAY be presented in multiple calls, even if
// it all one word, so be ready to splice it together.
// BEWARE: subclass's startElement method should call super()
// to null out 'value'. (Don't you miss the method combination
// options of a real object system like CLOS?)
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String newValue = new String(ch, start, length);
if (newValue.length() > 0) {
if (textValue == null) {
textValue = newValue;
} else {
textValue += newValue;
}
}
}
// if this was the FIRST "numhits" element, it's size of results:
@Override
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException {
if (localName.equals("numhits")) {
String stotal = textValue.trim();
if (stotal.length() > 0) {
total = Integer.parseInt(stotal);
result = new Choice[total];
if (total > 0) {
result[0] = new Choice();
log.debug("Got " + total + " records in results.");
}
}
} else if (localName.equals(resultElement)) {
// after start of result element, get next hit ready
if (++rindex < result.length) {
result[rindex] = new Choice();
}
} else if (localName.equals(labelElement) && textValue != null) {
// plug in label value
result[rindex].value = textValue.trim();
result[rindex].label = result[rindex].value;
} else if (authorityElement != null && localName.equals(authorityElement) && textValue != null) {
// plug in authority value
result[rindex].authority = textValue.trim();
} else if (localName.equals("message") && textValue != null) {
// error message
log.warn("SHERPA/RoMEO response error message: " + textValue.trim());
}
}
// subclass overriding this MUST call it with super()
@Override
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException {
textValue = null;
}
@Override
public void error(SAXParseException exception)
throws SAXException {
throw new SAXException(exception);
}
@Override
public void fatalError(SAXParseException exception)
throws SAXException {
throw new SAXException(exception);
}
}
}

View File

@@ -1,61 +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.content.authority;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.message.BasicNameValuePair;
import org.dspace.content.Collection;
/**
* Sample Publisher name authority based on SHERPA/RoMEO
*
*
* WARNING: This is a very crude and incomplete implementation, done mainly
* as a proof-of-concept. Any site that actually wants to use it will
* probably have to refine it (and give patches back to dspace.org).
*
* @author Larry Stone
* @version $Revision $
* @see SHERPARoMEOProtocol
*/
public class SHERPARoMEOPublisher extends SHERPARoMEOProtocol {
protected static final String RESULT = "publisher";
protected static final String LABEL = "name";
// note: the publisher records have nothing we can use as authority code.
protected static final String AUTHORITY = null;
public SHERPARoMEOPublisher() {
super();
}
@Override
public Choices getMatches(String text, Collection collection, int start, int limit, String locale) {
// punt if there is no query text
if (text == null || text.trim().length() == 0) {
return new Choices(true);
}
// query args to add to SHERPA/RoMEO request URL
List<BasicNameValuePair> args = new ArrayList<BasicNameValuePair>();
args.add(new BasicNameValuePair("pub", text));
args.add(new BasicNameValuePair("qtype", "all")); // OR: starts, exact
Choices result = query(RESULT, LABEL, AUTHORITY, args, start, limit);
if (result == null) {
result = new Choices(true);
}
return result;
}
@Override
public Choices getMatches(String field, String text, Collection collection, int start, int limit, String locale) {
return getMatches(text, collection, start, limit, locale);
}
}

View File

@@ -188,8 +188,8 @@ public class SolrAuthority implements ChoiceAuthority {
}
private String toQuery(String searchField, String text) {
return searchField + ":\"" + text.toLowerCase().replaceAll(":", "\\:") + "*\" or " + searchField + ":\"" + text
.toLowerCase().replaceAll(":", "\\:") + "\"";
return searchField + ":(" + text.toLowerCase().replaceAll(":", "\\:") + "*) or " + searchField + ":(" + text
.toLowerCase().replaceAll(":", "\\:") + ")";
}
@Override

View File

@@ -168,4 +168,9 @@ public interface ChoiceAuthorityService {
public ChoiceAuthority getChoiceAuthorityByAuthorityName(String authorityName);
/**
* This method has been created to have a way of clearing the cache kept inside the service
*/
public void clearCache();
}

View File

@@ -22,6 +22,7 @@ import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.Site;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.packager.DSpaceAIPIngester;
import org.dspace.content.packager.METSManifest;
@@ -195,7 +196,7 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
public Element disseminateElement(Context context, DSpaceObject dso)
throws CrosswalkException, IOException, SQLException,
AuthorizeException {
List<MockMetadataValue> dc = new ArrayList<>();
List<MetadataValueDTO> dc = new ArrayList<>();
if (dso.getType() == Constants.ITEM) {
Item item = (Item) dso;
EPerson is = item.getSubmitter();
@@ -282,8 +283,8 @@ public class AIPTechMDCrosswalk implements IngestionCrosswalk, DisseminationCros
return XSLTDisseminationCrosswalk.createDIM(dso, dc);
}
private static MockMetadataValue makeDC(String element, String qualifier, String value) {
MockMetadataValue dcv = new MockMetadataValue();
private static MetadataValueDTO makeDC(String element, String qualifier, String value) {
MetadataValueDTO dcv = new MetadataValueDTO();
dcv.setSchema("dc");
dcv.setLanguage(null);
dcv.setElement(element);

View File

@@ -29,6 +29,7 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.Site;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
@@ -327,7 +328,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
private List<Element> disseminateListInternal(DSpaceObject dso, boolean addSchema)
throws CrosswalkException, IOException, SQLException, AuthorizeException {
List<MockMetadataValue> dcvs = null;
List<MetadataValueDTO> dcvs = null;
if (dso.getType() == Constants.ITEM) {
dcvs = item2Metadata((Item) dso);
} else if (dso.getType() == Constants.COLLECTION) {
@@ -344,7 +345,7 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
List<Element> result = new ArrayList<Element>(dcvs.size());
for (MockMetadataValue dcv : dcvs) {
for (MetadataValueDTO dcv : dcvs) {
String qdc = dcv.getSchema() + "." + dcv.getElement();
if (dcv.getQualifier() != null) {
qdc += "." + dcv.getQualifier();
@@ -418,8 +419,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param site The site to derive metadata from
* @return list of metadata
*/
protected List<MockMetadataValue> site2Metadata(Site site) {
List<MockMetadataValue> metadata = new ArrayList<>();
protected List<MetadataValueDTO> site2Metadata(Site site) {
List<MetadataValueDTO> metadata = new ArrayList<>();
String identifier_uri = handleService.getCanonicalPrefix()
+ site.getHandle();
@@ -449,8 +450,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param community The community to derive metadata from
* @return list of metadata
*/
protected List<MockMetadataValue> community2Metadata(Community community) {
List<MockMetadataValue> metadata = new ArrayList<>();
protected List<MetadataValueDTO> community2Metadata(Community community) {
List<MetadataValueDTO> metadata = new ArrayList<>();
String description = communityService.getMetadata(community, "introductory_text");
String description_abstract = communityService.getMetadata(community, "short_description");
@@ -492,8 +493,8 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param collection The collection to derive metadata from
* @return list of metadata
*/
protected List<MockMetadataValue> collection2Metadata(Collection collection) {
List<MockMetadataValue> metadata = new ArrayList<>();
protected List<MetadataValueDTO> collection2Metadata(Collection collection) {
List<MetadataValueDTO> metadata = new ArrayList<>();
String description = collectionService.getMetadata(collection, "introductory_text");
String description_abstract = collectionService.getMetadata(collection, "short_description");
@@ -546,19 +547,19 @@ public class MODSDisseminationCrosswalk extends SelfNamedPlugin
* @param item The item to derive metadata from
* @return list of metadata
*/
protected List<MockMetadataValue> item2Metadata(Item item) {
protected List<MetadataValueDTO> item2Metadata(Item item) {
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
Item.ANY);
List<MockMetadataValue> result = new ArrayList<>();
List<MetadataValueDTO> result = new ArrayList<>();
for (MetadataValue metadataValue : dcvs) {
result.add(new MockMetadataValue(metadataValue));
result.add(new MetadataValueDTO(metadataValue));
}
return result;
}
protected MockMetadataValue createDCValue(String element, String qualifier, String value) {
MockMetadataValue dcv = new MockMetadataValue();
protected MetadataValueDTO createDCValue(String element, String qualifier, String value) {
MetadataValueDTO dcv = new MetadataValueDTO();
dcv.setSchema("dc");
dcv.setElement(element);
dcv.setQualifier(qualifier);

View File

@@ -1,101 +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.content.crosswalk;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
/**
* Metadata Value is bound to a database, the dissemination crosswalk require mock metadata just need for desimanation
* This class provides a wrapper for this.
* This class should only be used for the dissemniation metadata values that aren't to be written to the database
*
* @author kevinvandevelde at atmire.com
*/
public class MockMetadataValue {
private String schema;
private String element;
private String qualifier;
private String language;
private String value;
private String authority;
private int confidence;
public MockMetadataValue(MetadataValue metadataValue) {
MetadataField metadataField = metadataValue.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
schema = metadataSchema.getName();
element = metadataField.getElement();
qualifier = metadataField.getQualifier();
language = metadataValue.getLanguage();
value = metadataValue.getValue();
authority = metadataValue.getAuthority();
confidence = metadataValue.getConfidence();
}
public MockMetadataValue() {
}
public String getSchema() {
return schema;
}
public String getElement() {
return element;
}
public String getQualifier() {
return qualifier;
}
public String getValue() {
return value;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setValue(String value) {
this.value = value;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public int getConfidence() {
return confidence;
}
public void setConfidence(int confidence) {
this.confidence = confidence;
}
}

View File

@@ -15,7 +15,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
@@ -67,7 +67,8 @@ public class OAIDCIngestionCrosswalk
lang = element.getAttributeValue("lang");
}
MetadataField metadataField = metadataValidator
.checkMetadata(context, MetadataSchema.DC_SCHEMA, element.getName(), null, createMissingMetadataFields);
.checkMetadata(context, MetadataSchemaEnum.DC.getName(),
element.getName(), null, createMissingMetadataFields);
itemService.addMetadata(context, item, metadataField, lang, element.getText());
}

View File

@@ -22,7 +22,7 @@ import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
@@ -122,7 +122,7 @@ public class OREDisseminationCrosswalk
Element aggLink;
List<MetadataValue> uris = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "identifier", "uri", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "identifier", "uri", Item.ANY);
for (MetadataValue uri : uris) {
aggLink = new Element("link", ATOM_NS);
aggLink.setAttribute("rel", "alternate");
@@ -159,7 +159,8 @@ public class OREDisseminationCrosswalk
// Information about the aggregation (item) itself
Element aggTitle = new Element("title", ATOM_NS);
List<MetadataValue> titles = itemService.getMetadata(item, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
List<MetadataValue> titles = itemService.getMetadata(item, MetadataSchemaEnum.DC.getName(),
"title", null, Item.ANY);
if (titles != null && titles.size() > 0) {
aggTitle.addContent(titles.get(0).getValue());
} else {
@@ -170,7 +171,7 @@ public class OREDisseminationCrosswalk
Element aggAuthor;
Element aggAuthorName;
List<MetadataValue> authors = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, "contributor", "author", Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), "contributor", "author", Item.ANY);
for (MetadataValue author : authors) {
aggAuthor = new Element("author", ATOM_NS);
aggAuthorName = new Element("name", ATOM_NS);

View File

@@ -26,6 +26,7 @@ import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
@@ -353,7 +354,7 @@ public class QDCCrosswalk extends SelfNamedPlugin
// only complain about missing elements in the DC schema:
if (elt == null) {
if (metadataField.getMetadataSchema().getName().equals(MetadataSchema.DC_SCHEMA)) {
if (metadataField.getMetadataSchema().getName().equals(MetadataSchemaEnum.DC.getName())) {
log.warn("WARNING: " + myName + ": No QDC mapping for \"" + qdc + "\"");
}
} else {

View File

@@ -17,7 +17,7 @@ import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
@@ -101,7 +101,7 @@ public class SimpleDCDisseminationCrosswalk extends SelfNamedPlugin
Item item = (Item) dso;
List<MetadataValue> allDC = itemService
.getMetadata(item, MetadataSchema.DC_SCHEMA, Item.ANY, Item.ANY, Item.ANY);
.getMetadata(item, MetadataSchemaEnum.DC.getName(), Item.ANY, Item.ANY, Item.ANY);
List<Element> dcl = new ArrayList<Element>(allDC.size());

View File

@@ -31,6 +31,7 @@ import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.Site;
import org.dspace.content.authority.Choices;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
@@ -307,13 +308,13 @@ public class XSLTDisseminationCrosswalk
* @param dcvs list of metadata
* @return element
*/
public static Element createDIM(DSpaceObject dso, List<MockMetadataValue> dcvs) {
public static Element createDIM(DSpaceObject dso, List<MetadataValueDTO> dcvs) {
Element dim = new Element("dim", DIM_NS);
String type = Constants.typeText[dso.getType()];
dim.setAttribute("dspaceType", type);
for (int i = 0; i < dcvs.size(); i++) {
MockMetadataValue dcv = dcvs.get(i);
MetadataValueDTO dcv = dcvs.get(i);
Element field =
createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(),
dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence());
@@ -390,12 +391,12 @@ public class XSLTDisseminationCrosswalk
}
}
protected static List<MockMetadataValue> item2Metadata(Item item) {
protected static List<MetadataValueDTO> item2Metadata(Item item) {
List<MetadataValue> dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY,
Item.ANY);
List<MockMetadataValue> result = new ArrayList<>();
List<MetadataValueDTO> result = new ArrayList<>();
for (MetadataValue metadataValue : dcvs) {
result.add(new MockMetadataValue(metadataValue));
result.add(new MetadataValueDTO(metadataValue));
}
return result;

View File

@@ -0,0 +1,35 @@
/**
* 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.content.dao;
import java.sql.SQLException;
import org.dspace.content.EntityType;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
/**
* Database Access Object Interface class for the EntityType object
* The implementation of this class is responsible for all database calls for the EntityType 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 EntityTypeDAO extends GenericDAO<EntityType> {
/**
* This method returns the EntityType object that has the given entityType String
* as label
* @param context The relevant DSpace context
* @param entityType The entityType String that will be matched on to find
* the correct EntityType
* @return The EntityType object that has the entityType String as label
* @throws SQLException If something goes wrong
*/
public EntityType findByEntityType(Context context, String entityType) throws SQLException;
}

View File

@@ -63,6 +63,29 @@ public interface ItemDAO extends DSpaceObjectLegacySupportDAO<Item> {
public Iterator<Item> findArchivedByCollection(Context context, Collection collection, Integer limit,
Integer offset) throws SQLException;
/**
* Returns all the Items in an iterator that are archived and for which the given Collection is part of the Item's
* Collections but it is not the owning collection
* @param context The relevant DSpace context
* @param collection The collection to check on
* @param limit The limit for the query
* @param offset The offset for the query
* @return An iterator containing the items for which the constraints hold true
* @throws SQLException If something goes wrong
*/
public Iterator<Item> findArchivedByCollectionExcludingOwning(Context context, Collection collection, Integer limit,
Integer offset) throws SQLException;
/**
* Counts all the items that are archived and for which the given Collection is part of the Item's Collections
* but it is not the owning Collection
* @param context The relevant DSpace context
* @param collection The collection to check on
* @return The total amount of items that fit the constraints
* @throws SQLException If something goes wrong
*/
public int countArchivedByCollectionExcludingOwning(Context context, Collection collection) throws SQLException;
public Iterator<Item> findAllByCollection(Context context, Collection collection) throws SQLException;
public Iterator<Item> findAllByCollection(Context context, Collection collection, Integer limit, Integer offset)

View File

@@ -28,6 +28,10 @@ public interface MetadataValueDAO extends GenericDAO<MetadataValue> {
public List<MetadataValue> findByField(Context context, MetadataField fieldId) throws SQLException;
public Iterator<MetadataValue> findItemValuesByFieldAndValue(Context context,
MetadataField metadataField, String value)
throws SQLException;
public Iterator<MetadataValue> findByValueLike(Context context, String value) throws SQLException;
public void deleteByMetadataField(Context context, MetadataField metadataField) throws SQLException;

View File

@@ -0,0 +1,57 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
import org.dspace.scripts.Process;
/**
* This is the Data Access Object for the {@link Process} object
*/
public interface ProcessDAO extends GenericDAO<Process> {
/**
* This method will return all the Process objects in the database in a list and it'll be sorted by script name
* @param context The relevant DSpace context
* @return The list of all Process objects in the database sorted on scriptname
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByScript(Context context) throws SQLException;
/**
* This method will return all the Process objects in the database in a list and it'll be sorted by start time.
* The most recent one will be shown first
* @param context The relevant DSpace context
* @return The list of all Process objects in the database sorted by starttime
* @throws SQLException If something goes wrong
*/
public List<Process> findAllSortByStartTime(Context context) throws SQLException;
/**
* Returns a list of all Process objects in the database
* @param context The relevant DSpace context
* @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 Process objects in the Database
* @throws SQLException If something goes wrong
*/
List<Process> findAll(Context context, int limit, int offset) throws SQLException;
/**
* Returns the total amount of Process objects in the dataase
* @param context The relevant DSpace context
* @return An integer that describes the amount of Process objects in the database
* @throws SQLException If something goes wrong
*/
int countRows(Context context) throws SQLException;
}

View File

@@ -0,0 +1,213 @@
/**
* 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.content.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Item;
import org.dspace.content.Relationship;
import org.dspace.content.RelationshipType;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
/**
* Database Access Object Interface class for the Relationship object
* The implementation of this class is responsible for all
* database calls for the Relationship 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 RelationshipDAO extends GenericDAO<Relationship> {
/**
* This method returns a list of Relationship objects that have the given Item object
* as a leftItem or a rightItem
* @param context The relevant DSpace context
* @param item The item that should be either a leftItem or a rightItem of all
* the Relationship objects in the returned list
* @return The list of Relationship objects that contain either a left or a
* right item that is equal to the given item
* @throws SQLException If something goes wrong
*/
List<Relationship> findByItem(Context context, Item item) throws SQLException;
/**
* This method returns a list of Relationship objects that have the given Item object
* as a leftItem or a rightItem
* @param context The relevant DSpace context
* @param item The item that should be either a leftItem or a rightItem of all
* the Relationship objects in the returned list
* @param limit paging limit
* @param offset paging offset
* @return The list of Relationship objects that contain either a left or a
* right item that is equal to the given item
* @throws SQLException If something goes wrong
*/
List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset) throws SQLException;
/**
* This method returns the next leftplace integer to use for a relationship with this item as the leftItem
*
* @param context The relevant DSpace context
* @param item The item to be matched on leftItem
* @return The next integer to be used for the leftplace of a relationship with the given item
* as a left item
* @throws SQLException If something goes wrong
*/
int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException;
/**
* This method returns the next rightplace integer to use for a relationship with this item as the rightItem
*
* @param context The relevant DSpace context
* @param item The item to be matched on rightItem
* @return The next integer to be used for the rightplace of a relationship with the given item
* as a right item
* @throws SQLException If something goes wrong
*/
int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException;
/**
* This method returns a list of Relationship objects for the given RelationshipType object.
* It will construct a list of all Relationship objects that have the given RelationshipType object
* as the relationshipType property
* @param context The relevant DSpace context
* @param relationshipType The RelationshipType object to be checked on
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException;
/**
* This method returns a list of Relationship objects for the given RelationshipType object.
* It will construct a list of all Relationship objects that have the given RelationshipType object
* as the relationshipType property
* @param context The relevant DSpace context
* @param relationshipType The RelationshipType object to be checked on
* @param limit paging limit
* @param offset paging offset
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType,
Integer limit, Integer offset) throws SQLException;
/**
* This method returns a list of Relationship objects for the given RelationshipType object.
* It will construct a list of all Relationship objects that have the given RelationshipType object
* as the relationshipType property
* @param context The relevant DSpace context
* @param relationshipType The RelationshipType object to be checked on
* @param limit paging limit
* @param offset paging offset
* @param item item to filter by
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType,
Integer limit, Integer offset) throws SQLException;
/**
* This method returns a list of Relationship objects for the given RelationshipType object.
* It will construct a list of all Relationship objects that have the given RelationshipType object
* as the relationshipType property
* @param context The relevant DSpace context
* @param relationshipType The RelationshipType object to be checked on
* @param limit paging limit
* @param offset paging offset
* @param item item to filter by
* @param isLeft Is item left or right
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType,
boolean isLeft, Integer limit, Integer offset)
throws SQLException;
/**
* This method returns a list of Relationship objects for the given typeName
* @param context The relevant DSpace context
* @param typeName The leftward or rightward typeName of the relationship type
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByTypeName(Context context, String typeName)
throws SQLException;
/**
* This method returns a list of Relationship objects for the given typeName
* @param context The relevant DSpace context
* @param typeName The leftward or rightward typeName of the relationship type
* @param limit paging limit
* @param offset paging offset
* @return A list of Relationship objects that have the given RelationshipType object as the
* relationshipType property
* @throws SQLException If something goes wrong
*/
List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset)
throws SQLException;
/**
* Count total number of relationships (rows in relationship table)
*
* @param context context
* @return total count
* @throws SQLException if database error
*/
int countRows(Context context) throws SQLException;
/**
* Count total number of relationships (rows in relationship table) by a relationship type
*
* @param context context
* @param relationshipType relationship type to filter by
* @return total count
* @throws SQLException if database error
*/
int countByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException;
/**
* This method returns a count of Relationship objects that have the given Item object
* as a leftItem or a rightItem
* @param context The relevant DSpace context
* @param item The item that should be either a leftItem or a rightItem of all
* the Relationship objects in the returned list
* @return The list of Relationship objects that contain either a left or a
* right item that is equal to the given item
* @throws SQLException If something goes wrong
*/
int countByItem(Context context, Item item) throws SQLException;
/**
* Count total number of relationships (rows in relationship table) by an item and a relationship type
*
* @param context context
* @param relationshipType relationship type to filter by
* @param item item to filter by
* @return total count
* @throws SQLException if database error
*/
int countByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType)
throws SQLException;
/**
* Count total number of relationships (rows in relationship table) given a typeName
*
* @param context context
* @param typeName the relationship typeName to filter by
* @return total count
* @throws SQLException if database error
*/
int countByTypeName(Context context, String typeName)
throws SQLException;
}

View File

@@ -0,0 +1,123 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.EntityType;
import org.dspace.content.RelationshipType;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
/**
* Database Access Object Interface class for the RelationshipType object
* The implementation of this class is responsible for all
* database calls for the RelationshipType 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 RelationshipTypeDAO extends GenericDAO<RelationshipType> {
/**
* This method is used to retrieve the RelationshipType object that has the same
* leftType, rightType, leftwardType and rightwardType as given in the parameters
* @param context The relevant DSpace context
* @param leftType The leftType EntityType object to be matched in the query
* @param rightType The rightType EntityType object to be matched in the query
* @param leftwardType The leftwardType String to be matched in the query
* @param rightwardType The rightwardType String to be matched in the query
* @return The RelationshipType object that matches all the given parameters
* @throws SQLException If something goes wrong
*/
RelationshipType findbyTypesAndTypeName(Context context, EntityType leftType,EntityType rightType,
String leftwardType,
String rightwardType)
throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given label is equal to
* either the leftwardType or rightwardType.
* @param context The relevant DSpace context
* @param type The label that will be used to check on
* @return A list of RelationshipType objects that have the given label as either the leftwardType
* or rightwardType
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String type) throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given label is equal to
* either the leftLabel or rightLabel.
* @param context The relevant DSpace context
* @param type The label that will be used to check on
* @param limit paging limit
* @param offset paging offset
* @return A list of RelationshipType objects that have the given label as either the leftLabel or rightLabel
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String type, Integer limit,
Integer offset)
throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given EntityType object is equal
* to the leftType or rightType
* @param context The relevant DSpace context
* @param entityType The EntityType object that will be used to check on
* @return The list of RelationshipType objects that have the given EntityType object
* as either a leftType or rightType
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByEntityType(Context context, EntityType entityType) throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given EntityType object is equal
* to the leftType or rightType
* @param context The relevant DSpace context
* @param entityType The EntityType object that will be used to check on
* @param limit paging limit
* @param offset paging offset
* @return The list of RelationshipType objects that have the given EntityType object
* as either a leftType or rightType
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByEntityType(Context context, EntityType entityType, Integer limit, Integer offset)
throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given EntityType object is equal
* to the leftType or rightType
* @param context The relevant DSpace context
* @param entityType The EntityType object that will be used to check on
* @param isLeft Boolean value used to filter by left_type or right_type. If true left_type results only
* else right_type results.
* @return The list of RelationshipType objects that have the given EntityType object
* as either a leftType or rightType
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByEntityType(Context context, EntityType entityType, Boolean isLeft)
throws SQLException;
/**
* This method will return a list of RelationshipType objects for which the given EntityType object is equal
* to the leftType or rightType
* @param context The relevant DSpace context
* @param entityType The EntityType object that will be used to check on
* @param isLeft Boolean value used to filter by left_type or right_type. If true left_type results only
* else right_type results.
* @param limit paging limit
* @param offset paging offset
* @return The list of RelationshipType objects that have the given EntityType object
* as either a leftType or rightType
* @throws SQLException If something goes wrong
*/
List<RelationshipType> findByEntityType(Context context, EntityType entityType, Boolean isLeft,
Integer limit, Integer offset)
throws SQLException;
}

View File

@@ -9,7 +9,6 @@ package org.dspace.content.dao.impl;
import java.sql.SQLException;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -64,11 +63,20 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> imple
public List<Collection> findAll(Context context, MetadataField order, Integer limit, Integer offset)
throws SQLException {
StringBuilder query = new StringBuilder();
query.append("SELECT ").append(Collection.class.getSimpleName()).append(" FROM Collection as ")
.append(Collection.class.getSimpleName()).append(" ");
addMetadataLeftJoin(query, Collection.class.getSimpleName(), Arrays.asList(order));
addMetadataSortQuery(query, Arrays.asList(order), null);
// The query has to be rather complex because we want to sort the retrieval of Collections based on the title
// We'll join the Collections with the metadata fields on the sortfield specified in the parameters
// then we'll sort on this metadata field (this is usually the title). We're also making sure that the place
// is the lowest place in the metadata fields list so that we avoid the duplication bug
query.append("SELECT c" +
" FROM Collection c" +
" left join c.metadata title on title.metadataField = :sortField and" +
" title.dSpaceObject = c.id and" +
" title.place = (select min(internal.place) " +
"from c.metadata internal " +
"where internal.metadataField = :sortField and" +
" internal.dSpaceObject = c.id)" +
" ORDER BY LOWER(title.value)");
Query hibernateQuery = createQuery(context, query.toString());
if (offset != null) {
hibernateQuery.setFirstResult(offset);
@@ -76,7 +84,7 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO<Collection> imple
if (limit != null) {
hibernateQuery.setMaxResults(limit);
}
hibernateQuery.setParameter(order.toString(), order.getID());
hibernateQuery.setParameter("sortField", order);
return list(hibernateQuery);
}

View File

@@ -8,8 +8,6 @@
package org.dspace.content.dao.impl;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.Query;
@@ -62,11 +60,20 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO<Community> impleme
public List<Community> findAll(Context context, MetadataField sortField, Integer limit, Integer offset)
throws SQLException {
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("SELECT ").append(Community.class.getSimpleName()).append(" FROM Community as ")
.append(Community.class.getSimpleName()).append(" ");
addMetadataLeftJoin(queryBuilder, Community.class.getSimpleName(), Arrays.asList(sortField));
addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), Collections.EMPTY_LIST);
// The query has to be rather complex because we want to sort the retrieval of Communities based on the title
// We'll join the Communities with the metadata fields on the sortfield specified in the parameters
// then we'll sort on this metadata field (this is usually the title). We're also making sure that the place
// is the lowest place in the metadata fields list so that we avoid the duplication bug
queryBuilder.append("SELECT c" +
" FROM Community c" +
" left join c.metadata title on title.metadataField = :sortField and" +
" title.dSpaceObject = c.id and" +
" title.place = (select min(internal.place) " +
"from c.metadata internal " +
"where internal.metadataField = :sortField and" +
" internal.dSpaceObject = c.id)" +
" ORDER BY LOWER(title.value)");
Query query = createQuery(context, queryBuilder.toString());
if (offset != null) {
query.setFirstResult(offset);
@@ -74,7 +81,8 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO<Community> impleme
if (limit != null) {
query.setMaxResults(limit);
}
query.setParameter(sortField.toString(), sortField.getID());
query.setParameter("sortField", sortField);
return list(query);
}
@@ -91,16 +99,26 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO<Community> impleme
@Override
public List<Community> findAllNoParent(Context context, MetadataField sortField) throws SQLException {
StringBuilder queryBuilder = new StringBuilder();
queryBuilder.append("SELECT community FROM Community as community ");
addMetadataLeftJoin(queryBuilder, Community.class.getSimpleName().toLowerCase(), Arrays.asList(sortField));
addMetadataValueWhereQuery(queryBuilder, Collections.EMPTY_LIST, null, " community.parentCommunities IS EMPTY");
addMetadataSortQuery(queryBuilder, Arrays.asList(sortField), Collections.EMPTY_LIST);
// The query has to be rather complex because we want to sort the retrieval of Communities based on the title
// We'll join the Communities with the metadata fields on the sortfield specified in the parameters
// then we'll sort on this metadata field (this is usually the title). We're also making sure that the place
// is the lowest place in the metadata fields list so that we avoid the duplication bug
// This query has the added where clause to enforce that the community cannot have any parent communities
queryBuilder.append("SELECT c" +
" FROM Community c" +
" left join c.metadata title on title.metadataField = :sortField and" +
" title.dSpaceObject = c.id and" +
" title.place = (select min(internal.place) " +
"from c.metadata internal " +
"where internal.metadataField = :sortField and" +
" internal.dSpaceObject = c.id)" +
" WHERE c.parentCommunities IS EMPTY " +
" ORDER BY LOWER(title.value)");
Query query = createQuery(context, queryBuilder.toString());
query.setParameter(sortField.toString(), sortField.getID());
query.setParameter("sortField", sortField);
query.setHint("org.hibernate.cacheable", Boolean.TRUE);
return findMany(context, query);
}

View File

@@ -0,0 +1,33 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.dao.impl;
import java.sql.SQLException;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.EntityType;
import org.dspace.content.EntityType_;
import org.dspace.content.dao.EntityTypeDAO;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
public class EntityTypeDAOImpl extends AbstractHibernateDAO<EntityType> implements EntityTypeDAO {
@Override
public EntityType findByEntityType(Context context, String entityType) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EntityType.class);
Root<EntityType> entityTypeRoot = criteriaQuery.from(EntityType.class);
criteriaQuery.select(entityTypeRoot);
criteriaQuery.where(criteriaBuilder.equal(criteriaBuilder.upper(entityTypeRoot.get(EntityType_.label)),
entityType.toUpperCase()));
return uniqueResult(context, criteriaQuery, true, EntityType.class, -1, -1);
}
}

View File

@@ -15,10 +15,14 @@ import java.util.List;
import java.util.UUID;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.Item_;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.dao.ItemDAO;
@@ -283,6 +287,33 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO<Item> implements ItemDA
return iterate(query);
}
@Override
public Iterator<Item> findArchivedByCollectionExcludingOwning(Context context, Collection collection, Integer limit,
Integer offset) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
criteriaQuery.select(itemRoot);
criteriaQuery.where(criteriaBuilder.and(
criteriaBuilder.notEqual(itemRoot.get(Item_.owningCollection), collection),
criteriaBuilder.isMember(collection, itemRoot.get(Item_.collections)),
criteriaBuilder.isTrue(itemRoot.get(Item_.inArchive))));
return list(context, criteriaQuery, false, Item.class, limit, offset).iterator();
}
@Override
public int countArchivedByCollectionExcludingOwning(Context context, Collection collection) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
criteriaQuery.select(itemRoot);
criteriaQuery.where(criteriaBuilder.and(
criteriaBuilder.notEqual(itemRoot.get(Item_.owningCollection), collection),
criteriaBuilder.isMember(collection, itemRoot.get(Item_.collections)),
criteriaBuilder.isTrue(itemRoot.get(Item_.inArchive))));
return count(context, criteriaQuery, criteriaBuilder, itemRoot);
}
@Override
public Iterator<Item> findAllByCollection(Context context, Collection collection) throws SQLException {
Query query = createQuery(context, "select i from Item i join i.collections c WHERE :collection IN c");

View File

@@ -45,10 +45,22 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO<MetadataValue> im
criteriaQuery.select(metadataValueRoot);
criteriaQuery.where(criteriaBuilder.equal(join.get(MetadataField_.id), metadataField.getID()));
return list(context, criteriaQuery, false, MetadataValue.class, -1, -1);
}
@Override
public Iterator<MetadataValue> findItemValuesByFieldAndValue(Context context,
MetadataField metadataField, String value)
throws SQLException {
String queryString = "SELECT m from MetadataValue m " +
"join Item i on m.dSpaceObject = i.id where m.metadataField.id = :metadata_field_id " +
"and m.value = :text_value";
Query query = createQuery(context, queryString);
query.setParameter("metadata_field_id", metadataField.getID());
query.setParameter("text_value", value);
return iterate(query);
}
@Override
public Iterator<MetadataValue> findByValueLike(Context context, String value) throws SQLException {
String queryString = "SELECT m FROM MetadataValue m JOIN m.metadataField f " +

View File

@@ -0,0 +1,75 @@
/**
* 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.content.dao.impl;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
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.Process_;
/**
* Implementation class for {@link ProcessDAO}
*/
public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements ProcessDAO {
@Override
public List<Process> findAllSortByScript(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.asc(processRoot.get(Process_.name)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
@Override
public List<Process> findAllSortByStartTime(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.desc(processRoot.get(Process_.startTime)),
criteriaBuilder.desc(processRoot.get(Process_.processId)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
@Override
public List<Process> findAll(Context context, 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);
return list(context, criteriaQuery, false, Process.class, limit, offset);
}
@Override
public int countRows(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
return count(context, criteriaQuery, criteriaBuilder, processRoot);
}
}

View File

@@ -0,0 +1,234 @@
/**
* 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.content.dao.impl;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.Item;
import org.dspace.content.Relationship;
import org.dspace.content.RelationshipType;
import org.dspace.content.Relationship_;
import org.dspace.content.dao.RelationshipDAO;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
public class RelationshipDAOImpl extends AbstractHibernateDAO<Relationship> implements RelationshipDAO {
@Override
public List<Relationship> findByItem(Context context, Item item) throws SQLException {
return findByItem(context, item, -1, -1);
}
@Override
public List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.or(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)));
return list(context, criteriaQuery, false, Relationship.class, limit, offset);
}
@Override
public int countByItem(Context context, Item item)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.or(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)));
return count(context, criteriaQuery, criteriaBuilder, relationshipRoot);
}
@Override
public int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item));
List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1);
list.sort((o1, o2) -> o2.getLeftPlace() - o1.getLeftPlace());
if (!list.isEmpty()) {
return list.get(0).getLeftPlace() + 1;
} else {
return 0;
}
}
@Override
public int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item));
List<Relationship> list = list(context, criteriaQuery, false, Relationship.class, -1, -1);
list.sort((o1, o2) -> o2.getRightPlace() - o1.getRightPlace());
if (!list.isEmpty()) {
return list.get(0).getRightPlace() + 1;
} else {
return 0;
}
}
@Override
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType)
throws SQLException {
return findByRelationshipType(context, relationshipType, -1, -1);
}
@Override
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType,
Integer limit, Integer offset) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType), relationshipType));
return list(context, criteriaQuery, true, Relationship.class, limit, offset);
}
@Override
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType, Integer limit,
Integer offset)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType),
relationshipType), criteriaBuilder.or
(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)));
return list(context, criteriaQuery, true, Relationship.class, limit, offset);
}
@Override
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
RelationshipType relationshipType, boolean isLeft,
Integer limit, Integer offset)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
if (isLeft) {
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType),
relationshipType),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item));
} else {
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType),
relationshipType),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item));
}
return list(context, criteriaQuery, true, Relationship.class, limit, offset);
}
@Override
public List<Relationship> findByTypeName(Context context, String typeName)
throws SQLException {
return this.findByTypeName(context, typeName, -1, -1);
}
@Override
public List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset)
throws SQLException {
RelationshipTypeService relationshipTypeService = ContentServiceFactory.getInstance()
.getRelationshipTypeService();
List<RelationshipType> relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName(context, typeName);
List<Integer> ids = new ArrayList<>();
for ( RelationshipType relationshipType : relTypes) {
ids.add(relationshipType.getID());
}
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.where(relationshipRoot.get(Relationship_.relationshipType).in(ids));
return list(context, criteriaQuery, true, Relationship.class, limit, offset);
}
@Override
public int countByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType), relationshipType));
return count(context, criteriaQuery, criteriaBuilder, relationshipRoot);
}
@Override
public int countRows(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
return count(context, criteriaQuery, criteriaBuilder, relationshipRoot);
}
@Override
public int countByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.select(relationshipRoot);
criteriaQuery
.where(criteriaBuilder.equal(relationshipRoot.get(Relationship_.relationshipType),
relationshipType), criteriaBuilder.or
(criteriaBuilder.equal(relationshipRoot.get(Relationship_.leftItem), item),
criteriaBuilder.equal(relationshipRoot.get(Relationship_.rightItem), item)));
return count(context, criteriaQuery, criteriaBuilder, relationshipRoot);
}
@Override
public int countByTypeName(Context context, String typeName)
throws SQLException {
RelationshipTypeService relationshipTypeService = ContentServiceFactory.getInstance()
.getRelationshipTypeService();
List<RelationshipType> relTypes = relationshipTypeService.findByLeftwardOrRightwardTypeName(context, typeName);
List<Integer> ids = new ArrayList<>();
for ( RelationshipType relationshipType : relTypes) {
ids.add(relationshipType.getID());
}
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Relationship.class);
Root<Relationship> relationshipRoot = criteriaQuery.from(Relationship.class);
criteriaQuery.where(relationshipRoot.get(Relationship_.relationshipType).in(ids));
return count(context, criteriaQuery, criteriaBuilder, relationshipRoot);
}
}

View File

@@ -0,0 +1,114 @@
/**
* 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.content.dao.impl;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.EntityType;
import org.dspace.content.RelationshipType;
import org.dspace.content.RelationshipType_;
import org.dspace.content.dao.RelationshipTypeDAO;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
public class RelationshipTypeDAOImpl extends AbstractHibernateDAO<RelationshipType> implements RelationshipTypeDAO {
@Override
public RelationshipType findbyTypesAndTypeName(Context context, EntityType leftType, EntityType rightType,
String leftwardType, String rightwardType)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class);
Root<RelationshipType> relationshipTypeRoot = criteriaQuery.from(RelationshipType.class);
criteriaQuery.select(relationshipTypeRoot);
criteriaQuery.where(
criteriaBuilder.and(
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftType), leftType),
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.rightType), rightType),
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftwardType), leftwardType),
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.rightwardType), rightwardType)));
return uniqueResult(context, criteriaQuery, false, RelationshipType.class, -1, -1);
}
@Override
public List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String type) throws SQLException {
return findByLeftwardOrRightwardTypeName(context, type, -1, -1);
}
@Override
public List<RelationshipType> findByLeftwardOrRightwardTypeName(Context context, String type, Integer limit,
Integer offset)
throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class);
Root<RelationshipType> relationshipTypeRoot = criteriaQuery.from(RelationshipType.class);
criteriaQuery.select(relationshipTypeRoot);
criteriaQuery.where(
criteriaBuilder.or(
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftwardType), type),
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.rightwardType), type)
)
);
return list(context, criteriaQuery, true, RelationshipType.class, limit, offset);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType) throws SQLException {
return findByEntityType(context, entityType, -1, -1);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType,
Integer limit, Integer offset) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class);
Root<RelationshipType> relationshipTypeRoot = criteriaQuery.from(RelationshipType.class);
criteriaQuery.select(relationshipTypeRoot);
criteriaQuery.where(
criteriaBuilder.or(criteriaBuilder.
equal(relationshipTypeRoot.get(RelationshipType_.leftType), entityType),
criteriaBuilder
.equal(relationshipTypeRoot.get(RelationshipType_.rightType), entityType)
)
);
return list(context, criteriaQuery, false, RelationshipType.class, limit, offset);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType, Boolean isLeft)
throws SQLException {
return findByEntityType(context, entityType, isLeft, -1, -1);
}
@Override
public List<RelationshipType> findByEntityType(Context context, EntityType entityType, Boolean isLeft,
Integer limit, Integer offset) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RelationshipType.class);
Root<RelationshipType> relationshipTypeRoot = criteriaQuery.from(RelationshipType.class);
criteriaQuery.select(relationshipTypeRoot);
if (isLeft) {
criteriaQuery.where(
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.leftType), entityType)
);
} else {
criteriaQuery.where(
criteriaBuilder.equal(relationshipTypeRoot.get(RelationshipType_.rightType), entityType)
);
}
return list(context, criteriaQuery, false, RelationshipType.class, limit, offset);
}
}

View File

@@ -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.content.dto;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
/**
* This class acts as Data transfer object in which we can store data like in a regular MetadataValue object, but this
* one isn't saved in the DB. This can freely be used to represent Metadata without it being saved in the database,
* this will typically be used when transferring data
*
* @author kevinvandevelde at atmire.com
*/
public class MetadataValueDTO {
private String schema;
private String element;
private String qualifier;
private String language;
private String value;
private String authority;
private int confidence = Choices.CF_UNSET;
public MetadataValueDTO(MetadataValue metadataValue) {
MetadataField metadataField = metadataValue.getMetadataField();
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
schema = metadataSchema.getName();
element = metadataField.getElement();
qualifier = metadataField.getQualifier();
language = metadataValue.getLanguage();
value = metadataValue.getValue();
authority = metadataValue.getAuthority();
confidence = metadataValue.getConfidence();
}
public MetadataValueDTO() {
}
/**
* Constructor for the MetadataValueDTO class
* @param schema The schema to be assigned to this MetadataValueDTO object
* @param element The element to be assigned to this MetadataValueDTO object
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
* @param language The language to be assigend to this MetadataValueDTO object
* @param value The value to be assigned to this MetadataValueDTO object
* @param authority The authority to be assigned to this MetadataValueDTO object
* @param confidence The confidence to be assigned to this MetadataValueDTO object
*/
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value,
String authority, int confidence) {
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
this.authority = authority;
this.confidence = confidence;
}
/**
* Constructor for the MetadataValueDTO class
* @param schema The schema to be assigned to this MetadataValueDTO object
* @param element The element to be assigned to this MetadataValueDTO object
* @param qualifier The qualifier to be assigned to this MetadataValueDTO object
* @param language The language to be assigend to this MetadataValueDTO object
* @param value The value to be assigned to this MetadataValueDTO object
*/
public MetadataValueDTO(String schema, String element, String qualifier, String language, String value) {
this.schema = schema;
this.element = element;
this.qualifier = qualifier;
this.language = language;
this.value = value;
}
public String getSchema() {
return schema;
}
public String getElement() {
return element;
}
public String getQualifier() {
return qualifier;
}
public String getValue() {
return value;
}
public void setSchema(String schema) {
this.schema = schema;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setValue(String value) {
this.value = value;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public int getConfidence() {
return confidence;
}
public void setConfidence(int confidence) {
this.confidence = confidence;
}
}

View File

@@ -12,6 +12,7 @@ import java.util.List;
import org.dspace.content.DSpaceObject;
import org.dspace.content.InProgressSubmission;
import org.dspace.content.RelationshipMetadataService;
import org.dspace.content.WorkspaceItem;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
@@ -20,6 +21,8 @@ import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.DSpaceObjectLegacySupportService;
import org.dspace.content.service.DSpaceObjectService;
import org.dspace.content.service.EntityService;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.InProgressSubmissionService;
import org.dspace.content.service.IndexableObjectService;
import org.dspace.content.service.InstallItemService;
@@ -27,6 +30,8 @@ import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.SiteService;
import org.dspace.content.service.SupervisedItemService;
import org.dspace.content.service.WorkspaceItemService;
@@ -80,6 +85,36 @@ public abstract class ContentServiceFactory {
public abstract SiteService getSiteService();
/**
* Return the implementation of the RelationshipTypeService interface
*
* @return the RelationshipTypeService
*/
public abstract RelationshipTypeService getRelationshipTypeService();
/**
* Return the implementation of the RelationshipService interface
*
* @return the RelationshipService
*/
public abstract RelationshipService getRelationshipService();
/**
* Return the implementation of the EntityTypeService interface
*
* @return the EntityTypeService
*/
public abstract EntityTypeService getEntityTypeService();
/**
* Return the implementation of the EntityService interface
*
* @return the EntityService
*/
public abstract EntityService getEntityService();
public abstract RelationshipMetadataService getRelationshipMetadataService();
public InProgressSubmissionService getInProgressSubmissionService(InProgressSubmission inProgressSubmission) {
if (inProgressSubmission instanceof WorkspaceItem) {
return getWorkspaceItemService();

View File

@@ -10,6 +10,7 @@ package org.dspace.content.factory;
import java.util.List;
import org.dspace.content.DSpaceObject;
import org.dspace.content.RelationshipMetadataService;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
@@ -17,12 +18,16 @@ import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.DSpaceObjectLegacySupportService;
import org.dspace.content.service.DSpaceObjectService;
import org.dspace.content.service.EntityService;
import org.dspace.content.service.EntityTypeService;
import org.dspace.content.service.IndexableObjectService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.MetadataValueService;
import org.dspace.content.service.RelationshipService;
import org.dspace.content.service.RelationshipTypeService;
import org.dspace.content.service.SiteService;
import org.dspace.content.service.SupervisedItemService;
import org.dspace.content.service.WorkspaceItemService;
@@ -69,6 +74,17 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory {
@Autowired(required = true)
private SiteService siteService;
@Autowired(required = true)
private RelationshipService relationshipService;
@Autowired(required = true)
private RelationshipTypeService relationshipTypeService;
@Autowired(required = true)
private RelationshipMetadataService relationshipMetadataService;
@Autowired(required = true)
private EntityTypeService entityTypeService;
@Autowired(required = true)
private EntityService entityService;
@Override
public List<IndexableObjectService> getIndexableObjectServices() {
return new DSpace().getServiceManager().getServicesByType(IndexableObjectService.class);
@@ -149,4 +165,28 @@ public class ContentServiceFactoryImpl extends ContentServiceFactory {
return siteService;
}
@Override
public RelationshipTypeService getRelationshipTypeService() {
return relationshipTypeService;
}
@Override
public RelationshipService getRelationshipService() {
return relationshipService;
}
@Override
public EntityTypeService getEntityTypeService() {
return entityTypeService;
}
@Override
public EntityService getEntityService() {
return entityService;
}
@Override
public RelationshipMetadataService getRelationshipMetadataService() {
return relationshipMetadataService;
}
}

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