mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-13 21:13:19 +00:00
Compare commits
2 Commits
rest-tutor
...
dspace-1_3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed07696cb5 | ||
|
|
6069330aa8 |
14
.gitattributes
vendored
14
.gitattributes
vendored
@@ -1,14 +0,0 @@
|
|||||||
# Auto detect text files and perform LF normalization
|
|
||||||
* text=auto
|
|
||||||
|
|
||||||
# Standard to msysgit
|
|
||||||
*.doc diff=astextplain
|
|
||||||
*.DOC diff=astextplain
|
|
||||||
*.docx diff=astextplain
|
|
||||||
*.DOCX diff=astextplain
|
|
||||||
*.dot diff=astextplain
|
|
||||||
*.DOT diff=astextplain
|
|
||||||
*.pdf diff=astextplain
|
|
||||||
*.PDF diff=astextplain
|
|
||||||
*.rtf diff=astextplain
|
|
||||||
*.RTF diff=astextplain
|
|
||||||
44
.gitignore
vendored
44
.gitignore
vendored
@@ -1,44 +0,0 @@
|
|||||||
## Ignore the MVN compiled output directories from version tracking
|
|
||||||
target/
|
|
||||||
|
|
||||||
## Ignore tags index files created by Exuberant Ctags
|
|
||||||
tags
|
|
||||||
|
|
||||||
## Ignore project files created by Eclipse
|
|
||||||
.settings/
|
|
||||||
/bin/
|
|
||||||
.project
|
|
||||||
.classpath
|
|
||||||
.checkstyle
|
|
||||||
|
|
||||||
## Ignore project files created by IntelliJ IDEA
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
.idea/
|
|
||||||
overlays/
|
|
||||||
|
|
||||||
## Ignore project files created by NetBeans
|
|
||||||
nbproject/private/
|
|
||||||
build/
|
|
||||||
nbbuild/
|
|
||||||
dist/
|
|
||||||
nbdist/
|
|
||||||
nbactions.xml
|
|
||||||
nb-configuration.xml
|
|
||||||
|
|
||||||
## Ignore all *.properties file in root folder, EXCEPT build.properties (the default)
|
|
||||||
## KEPT FOR BACKWARDS COMPATIBILITY WITH 5.x (build.properties is now replaced with local.cfg)
|
|
||||||
/*.properties
|
|
||||||
!/build.properties
|
|
||||||
|
|
||||||
# Ignore a local.cfg file in root folder, if it exists
|
|
||||||
/local.cfg
|
|
||||||
# Also ignore it under dspace/config
|
|
||||||
/dspace/config/local.cfg
|
|
||||||
|
|
||||||
##Mac noise
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
##Ignore JRebel project configuration
|
|
||||||
rebel.xml
|
|
||||||
44
.travis.yml
44
.travis.yml
@@ -1,44 +0,0 @@
|
|||||||
language: java
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
env:
|
|
||||||
# Give Maven 1GB of memory to work with
|
|
||||||
- MAVEN_OPTS=-Xmx1024M
|
|
||||||
|
|
||||||
jdk:
|
|
||||||
# DS-3384 Oracle JDK 8 has DocLint enabled by default.
|
|
||||||
# Let's use this to catch any newly introduced DocLint issues.
|
|
||||||
- oraclejdk8
|
|
||||||
|
|
||||||
## Should we run into any problems with oraclejdk8 on Travis, we may try the following workaround.
|
|
||||||
## https://docs.travis-ci.com/user/languages/java#Testing-Against-Multiple-JDKs
|
|
||||||
## https://github.com/travis-ci/travis-ci/issues/3259#issuecomment-130860338
|
|
||||||
#addons:
|
|
||||||
# apt:
|
|
||||||
# packages:
|
|
||||||
# - oracle-java8-installer
|
|
||||||
|
|
||||||
# Install prerequisites for building Mirage2 more rapidly
|
|
||||||
before_install:
|
|
||||||
# Remove outdated settings.xml from Travis builds. Workaround for https://github.com/travis-ci/travis-ci/issues/4629
|
|
||||||
- rm ~/.m2/settings.xml
|
|
||||||
|
|
||||||
# Skip install stage, as we'll do it below
|
|
||||||
install: "echo 'Skipping install stage, dependencies will be downloaded during build and test stages.'"
|
|
||||||
|
|
||||||
# Two stage Build and Test
|
|
||||||
# 1. Install & Unit Test APIs
|
|
||||||
# 2. Assemble DSpace
|
|
||||||
script:
|
|
||||||
# 1. [Install & Unit Test] Check source code licenses and run source code Unit Tests
|
|
||||||
# license:check => Validate all source code license headers
|
|
||||||
# -Dmaven.test.skip=false => Enable DSpace Unit Tests
|
|
||||||
# -DskipITs=false => Enable DSpace Integration Tests
|
|
||||||
# -P !assembly => Skip normal assembly (as it can be memory intensive)
|
|
||||||
# -B => Maven batch/non-interactive mode (recommended for CI)
|
|
||||||
# -V => Display Maven version info before build
|
|
||||||
# -Dsurefire.rerunFailingTestsCount=2 => try again for flakey tests, and keep track of/report on number of retries
|
|
||||||
- "mvn clean install license:check -Dmaven.test.skip=false -DskipITs=false -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"
|
|
||||||
# 2. [Assemble DSpace] Ensure overlay & assembly process works (from [src]/dspace/)
|
|
||||||
# -P !assembly => SKIP the actual building of [src]/dspace/dspace-installer (as it can be memory intensive)
|
|
||||||
- "cd dspace && mvn package -P !assembly -B -V -Dsurefire.rerunFailingTestsCount=2"
|
|
||||||
40
LICENSE
40
LICENSE
@@ -1,40 +0,0 @@
|
|||||||
DSpace source code license:
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2002-2016, DuraSpace. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
- Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
- Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
- Neither the name DuraSpace nor the name of the DSpace Foundation
|
|
||||||
nor the names of its contributors may be used to endorse or promote
|
|
||||||
products derived from this software without specific prior written
|
|
||||||
permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
||||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
|
||||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
||||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
||||||
DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
DSpace uses third-party libraries which may be distributed under
|
|
||||||
different licenses to the above. Information about these licenses
|
|
||||||
is detailed in the LICENSES_THIRD_PARTY file at the root of the source
|
|
||||||
tree. You must agree to the terms of these licenses, in addition to
|
|
||||||
the above DSpace source code license, in order to use this software.
|
|
||||||
@@ -1,424 +0,0 @@
|
|||||||
|
|
||||||
DSpace uses third-party libraries which may be distributed under different
|
|
||||||
licenses. We have listed all of these third party libraries and their licenses
|
|
||||||
below. This file can be regenerated at any time by simply running:
|
|
||||||
|
|
||||||
mvn clean verify -Dthird.party.licenses=true
|
|
||||||
|
|
||||||
You must agree to the terms of these licenses, in addition to the DSpace
|
|
||||||
source code license, in order to use this software.
|
|
||||||
|
|
||||||
---------------------------------------------------
|
|
||||||
Third party Java libraries listed by License type.
|
|
||||||
|
|
||||||
PLEASE NOTE: Some dependencies may be listed under multiple licenses if they
|
|
||||||
are dual-licensed. This is especially true of anything listed as
|
|
||||||
"GNU General Public Library" below, as DSpace actually does NOT allow for any
|
|
||||||
dependencies that are solely released under GPL terms. For more info see:
|
|
||||||
https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines
|
|
||||||
---------------------------------------------------
|
|
||||||
|
|
||||||
Apache Software License, Version 2.0:
|
|
||||||
|
|
||||||
* Ant-Contrib Tasks (ant-contrib:ant-contrib:1.0b3 - http://ant-contrib.sourceforge.net)
|
|
||||||
* Code Generation Library (cglib:cglib:2.2.2 - http://cglib.sourceforge.net/)
|
|
||||||
* AWS SDK for Java - Core (com.amazonaws:aws-java-sdk-core:1.10.50 - https://aws.amazon.com/sdkforjava)
|
|
||||||
* AWS Java SDK for AWS KMS (com.amazonaws:aws-java-sdk-kms:1.10.50 - https://aws.amazon.com/sdkforjava)
|
|
||||||
* AWS Java SDK for Amazon S3 (com.amazonaws:aws-java-sdk-s3:1.10.50 - https://aws.amazon.com/sdkforjava)
|
|
||||||
* HPPC Collections (com.carrotsearch:hppc:0.5.2 - http://labs.carrotsearch.com/hppc.html/hppc)
|
|
||||||
* metadata-extractor (com.drewnoakes:metadata-extractor:2.6.2 - http://code.google.com/p/metadata-extractor/)
|
|
||||||
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.5.4 - http://github.com/FasterXML/jackson)
|
|
||||||
* Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.7.0 - http://github.com/FasterXML/jackson)
|
|
||||||
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.5.4 - https://github.com/FasterXML/jackson)
|
|
||||||
* Jackson-core (com.fasterxml.jackson.core:jackson-core:2.7.0 - https://github.com/FasterXML/jackson-core)
|
|
||||||
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.5.4 - http://github.com/FasterXML/jackson)
|
|
||||||
* jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.7.0 - http://github.com/FasterXML/jackson)
|
|
||||||
* Jackson-JAXRS-base (com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-base)
|
|
||||||
* Jackson-JAXRS-JSON (com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.5.4 - http://wiki.fasterxml.com/JacksonHome/jackson-jaxrs-json-provider)
|
|
||||||
* Jackson-module-JAXB-annotations (com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.5.4 - http://wiki.fasterxml.com/JacksonJAXBAnnotations)
|
|
||||||
* Google APIs Client Library for Java (com.google.api-client:google-api-client:1.21.0 - https://github.com/google/google-api-java-client/google-api-client)
|
|
||||||
* Google Analytics API v3-rev123-1.21.0 (com.google.apis:google-api-services-analytics:v3-rev123-1.21.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-analytics)
|
|
||||||
* FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.1 - http://findbugs.sourceforge.net/)
|
|
||||||
* Gson (com.google.code.gson:gson:2.6.1 - https://github.com/google/gson/gson)
|
|
||||||
* Guava: Google Core Libraries for Java (com.google.guava:guava:14.0.1 - http://code.google.com/p/guava-libraries/guava)
|
|
||||||
* Guava: Google Core Libraries for Java (com.google.guava:guava:19.0 - https://github.com/google/guava/guava)
|
|
||||||
* Guava: Google Core Libraries for Java (JDK5 Backport) (com.google.guava:guava-jdk5:17.0 - http://code.google.com/p/guava-libraries/guava-jdk5)
|
|
||||||
* Google HTTP Client Library for Java (com.google.http-client:google-http-client:1.21.0 - https://github.com/google/google-http-java-client/google-http-client)
|
|
||||||
* Jackson 2 extensions to the Google HTTP Client Library for Java. (com.google.http-client:google-http-client-jackson2:1.21.0 - https://github.com/google/google-http-java-client/google-http-client-jackson2)
|
|
||||||
* Google OAuth Client Library for Java (com.google.oauth-client:google-oauth-client:1.21.0 - https://github.com/google/google-oauth-java-client/google-oauth-client)
|
|
||||||
* ConcurrentLinkedHashMap (com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.2 - http://code.google.com/p/concurrentlinkedhashmap)
|
|
||||||
* ISO Parser (com.googlecode.mp4parser:isoparser:1.0-RC-1 - http://code.google.com/p/mp4parser/)
|
|
||||||
* builder-commons (com.lyncode:builder-commons:1.0.2 - http://nexus.sonatype.org/oss-repository-hosting.html/builder-commons)
|
|
||||||
* Jtwig Core (com.lyncode:jtwig-core:2.0.1 - http://www.lyncode.com/jtwig-core)
|
|
||||||
* Jtwig Core Functions (com.lyncode:jtwig-functions:2.0.1 - http://www.lyncode.com/jtwig-functions)
|
|
||||||
* Jtwig Spring (com.lyncode:jtwig-spring:2.0.1 - http://www.lyncode.com/jtwig-spring)
|
|
||||||
* Test Support (com.lyncode:test-support:1.0.3 - http://nexus.sonatype.org/oss-repository-hosting.html/test-support)
|
|
||||||
* Spatial4J (com.spatial4j:spatial4j:0.4.1 - https://github.com/spatial4j/spatial4j)
|
|
||||||
* Apache Commons BeanUtils (commons-beanutils:commons-beanutils:1.9.2 - http://commons.apache.org/proper/commons-beanutils/)
|
|
||||||
* Apache Commons CLI (commons-cli:commons-cli:1.3.1 - http://commons.apache.org/proper/commons-cli/)
|
|
||||||
* Apache Commons Codec (commons-codec:commons-codec:1.10 - http://commons.apache.org/proper/commons-codec/)
|
|
||||||
* Apache Commons Collections (commons-collections:commons-collections:3.2.2 - http://commons.apache.org/collections/)
|
|
||||||
* Apache Commons Configuration (commons-configuration:commons-configuration:1.10 - http://commons.apache.org/configuration/)
|
|
||||||
* Commons Digester (commons-digester:commons-digester:1.8.1 - http://commons.apache.org/digester/)
|
|
||||||
* Apache Commons FileUpload (commons-fileupload:commons-fileupload:1.3.1 - http://commons.apache.org/proper/commons-fileupload/)
|
|
||||||
* HttpClient (commons-httpclient:commons-httpclient:3.1 - http://jakarta.apache.org/httpcomponents/httpclient-3.x/)
|
|
||||||
* Commons IO (commons-io:commons-io:2.4 - http://commons.apache.org/io/)
|
|
||||||
* commons-jexl (commons-jexl:commons-jexl:1.0 - no url defined)
|
|
||||||
* Commons JXPath (commons-jxpath:commons-jxpath:1.3 - http://commons.apache.org/jxpath/)
|
|
||||||
* Commons Lang (commons-lang:commons-lang:2.6 - http://commons.apache.org/lang/)
|
|
||||||
* Apache Commons Logging (commons-logging:commons-logging:1.2 - http://commons.apache.org/proper/commons-logging/)
|
|
||||||
* Apache Commons Validator (commons-validator:commons-validator:1.5.0 - http://commons.apache.org/proper/commons-validator/)
|
|
||||||
* Boilerpipe -- Boilerplate Removal and Fulltext Extraction from HTML pages (de.l3s.boilerpipe:boilerpipe:1.1.0 - http://code.google.com/p/boilerpipe/)
|
|
||||||
* The Netty Project (io.netty:netty:3.7.0.Final - http://netty.io/)
|
|
||||||
* jakarta-regexp (jakarta-regexp:jakarta-regexp:1.4 - no url defined)
|
|
||||||
* javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
|
|
||||||
* Bean Validation API (javax.validation:validation-api:1.1.0.Final - http://beanvalidation.org)
|
|
||||||
* jdbm (jdbm:jdbm:1.0 - no url defined)
|
|
||||||
* Joda time (joda-time:joda-time:2.2 - http://joda-time.sourceforge.net)
|
|
||||||
* Joda-Time (joda-time:joda-time:2.9.2 - http://www.joda.org/joda-time/)
|
|
||||||
* Apache Log4j (log4j:log4j:1.2.17 - http://logging.apache.org/log4j/1.2/)
|
|
||||||
* "Java Concurrency in Practice" book annotations (net.jcip:jcip-annotations:1.0 - http://jcip.net/)
|
|
||||||
* Ehcache Core (net.sf.ehcache:ehcache-core:2.4.3 - http://ehcache.org)
|
|
||||||
* opencsv (net.sf.opencsv:opencsv:2.3 - http://opencsv.sf.net)
|
|
||||||
* Abdera Client (org.apache.abdera:abdera-client:1.1.3 - http://abdera.apache.org/abdera-client)
|
|
||||||
* Abdera Core (org.apache.abdera:abdera-core:1.1.3 - http://abdera.apache.org/abdera-core)
|
|
||||||
* I18N Libraries (org.apache.abdera:abdera-i18n:1.1.3 - http://abdera.apache.org)
|
|
||||||
* Abdera Parser (org.apache.abdera:abdera-parser:1.1.3 - http://abdera.apache.org/abdera-parser)
|
|
||||||
* org.apache.tools.ant (org.apache.ant:ant:1.7.0 - http://ant.apache.org/ant/)
|
|
||||||
* ant-launcher (org.apache.ant:ant-launcher:1.7.0 - http://ant.apache.org/ant-launcher/)
|
|
||||||
* Avalon Framework API (org.apache.avalon.framework:avalon-framework-api:4.3.1 - http://www.apache.org/excalibur/avalon-framework/avalon-framework-api/)
|
|
||||||
* Avalon Framework Implementation (org.apache.avalon.framework:avalon-framework-impl:4.3.1 - http://www.apache.org/excalibur/avalon-framework/avalon-framework-impl/)
|
|
||||||
* Cocoon Configuration API (org.apache.cocoon:cocoon-configuration-api:1.0.2 - http://cocoon.apache.org/subprojects/configuration/1.0/configuration-api/1.0/)
|
|
||||||
* Cocoon Core (org.apache.cocoon:cocoon-core:2.2.0 - http://cocoon.apache.org/2.2/core-modules/core/2.2/)
|
|
||||||
* Cocoon Expression Language API (org.apache.cocoon:cocoon-expression-language-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/expression-language-api/1.0/)
|
|
||||||
* Cocoon Expression Language Implementation. (org.apache.cocoon:cocoon-expression-language-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/expression-language-impl/1.0/)
|
|
||||||
* Cocoon Flowscript Block Implementation (org.apache.cocoon:cocoon-flowscript-impl:1.0.0 - http://cocoon.apache.org/2.2/blocks/flowscript/1.0/)
|
|
||||||
* Cocoon Linkrewriter Block Implementation (org.apache.cocoon:cocoon-linkrewriter-impl:1.0.0 - http://cocoon.apache.org/2.2/blocks/linkrewriter/1.0/)
|
|
||||||
* Cocoon Pipeline API (org.apache.cocoon:cocoon-pipeline-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-api/1.0/)
|
|
||||||
* Cocoon Pipeline Components (org.apache.cocoon:cocoon-pipeline-components:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-components/1.0/)
|
|
||||||
* Cocoon Pipeline Implementation (org.apache.cocoon:cocoon-pipeline-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/pipeline-impl/1.0/)
|
|
||||||
* Cocoon Servlet Service Components (org.apache.cocoon:cocoon-servlet-service-components:1.0.0 - http://cocoon.apache.org/subprojects/servlet-service/1.0/servlet-service-components/1.0/)
|
|
||||||
* Cocoon Sitemap API (org.apache.cocoon:cocoon-sitemap-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-api/1.0/)
|
|
||||||
* Cocoon Sitemap Components (org.apache.cocoon:cocoon-sitemap-components:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-components/1.0/)
|
|
||||||
* Cocoon Sitemap Implementation (org.apache.cocoon:cocoon-sitemap-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/sitemap-impl/1.0/)
|
|
||||||
* Cocoon Spring Configurator (org.apache.cocoon:cocoon-spring-configurator:1.0.2 - http://cocoon.apache.org/cocoon-spring-configurator)
|
|
||||||
* Cocoon Store Implementation (org.apache.cocoon:cocoon-store-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/store-impl/1.0/)
|
|
||||||
* Cocoon Template Framework Block Implementation (org.apache.cocoon:cocoon-template-impl:1.1.0 - http://cocoon.apache.org/2.2/blocks/template/1.0/)
|
|
||||||
* Cocoon Thread API (org.apache.cocoon:cocoon-thread-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/thread-api/1.0/)
|
|
||||||
* Cocoon Thread Implementation (org.apache.cocoon:cocoon-thread-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/thread-impl/1.0/)
|
|
||||||
* Cocoon Util (org.apache.cocoon:cocoon-util:1.0.0 - http://cocoon.apache.org/2.2/core-modules/util/1.0/)
|
|
||||||
* Cocoon XML API (org.apache.cocoon:cocoon-xml-api:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-api/1.0/)
|
|
||||||
* Cocoon XML Implementation (org.apache.cocoon:cocoon-xml-impl:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-impl/1.0/)
|
|
||||||
* Cocoon XML Resolver (org.apache.cocoon:cocoon-xml-resolver:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-resolver/1.0/)
|
|
||||||
* Cocoon XML Utilities (org.apache.cocoon:cocoon-xml-util:1.0.0 - http://cocoon.apache.org/2.2/core-modules/xml-util/1.0/)
|
|
||||||
* Apache Commons Compress (org.apache.commons:commons-compress:1.7 - http://commons.apache.org/proper/commons-compress/)
|
|
||||||
* Apache Commons CSV (org.apache.commons:commons-csv:1.0 - http://commons.apache.org/proper/commons-csv/)
|
|
||||||
* Apache Commons DBCP (org.apache.commons:commons-dbcp2:2.1.1 - http://commons.apache.org/dbcp/)
|
|
||||||
* Apache Commons Lang (org.apache.commons:commons-lang3:3.3.2 - http://commons.apache.org/proper/commons-lang/)
|
|
||||||
* Apache Commons Pool (org.apache.commons:commons-pool2:2.4.2 - http://commons.apache.org/proper/commons-pool/)
|
|
||||||
* Excalibur Pool API (org.apache.excalibur.components:excalibur-pool-api:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-pool-modules/excalibur-pool-api/)
|
|
||||||
* Excalibur Sourceresolve (org.apache.excalibur.components:excalibur-sourceresolve:2.2.3 - http://www.apache.org/excalibur/excalibur-sourceresolve/)
|
|
||||||
* Excalibur Store (org.apache.excalibur.components:excalibur-store:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-store/)
|
|
||||||
* Excalibur XML Utilities (org.apache.excalibur.components:excalibur-xmlutil:2.2.1 - http://www.apache.org/excalibur/excalibur-components-modules/excalibur-xmlutil/)
|
|
||||||
* Excalibur Instrument API (org.apache.excalibur.containerkit:excalibur-instrument-api:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-instrument-modules/excalibur-instrument-api/)
|
|
||||||
* Excalibur Logger (org.apache.excalibur.containerkit:excalibur-logger:2.2.1 - http://www.apache.org/excalibur/excalibur-containerkit/excalibur-logger/)
|
|
||||||
* Activation 1.1 (org.apache.geronimo.specs:geronimo-activation_1.1_spec:1.1 - http://geronimo.apache.org/maven/specs/geronimo-activation_1.1_spec/1.1)
|
|
||||||
* JavaMail 1.4 (org.apache.geronimo.specs:geronimo-javamail_1.4_spec:1.7.1 - http://geronimo.apache.org/maven/specs/geronimo-javamail_1.4_spec/1.7.1)
|
|
||||||
* Streaming API for XML (STAX API 1.0) (org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:1.0.1 - http://geronimo.apache.org/specs/geronimo-stax-api_1.0_spec)
|
|
||||||
* Apache Hadoop Annotations (org.apache.hadoop:hadoop-annotations:2.2.0 - no url defined)
|
|
||||||
* Apache Hadoop Auth (org.apache.hadoop:hadoop-auth:2.2.0 - no url defined)
|
|
||||||
* Apache Hadoop Common (org.apache.hadoop:hadoop-common:2.2.0 - no url defined)
|
|
||||||
* Apache Hadoop HDFS (org.apache.hadoop:hadoop-hdfs:2.2.0 - no url defined)
|
|
||||||
* Apache HttpClient (org.apache.httpcomponents:httpclient:4.5.1 - http://hc.apache.org/httpcomponents-client)
|
|
||||||
* Apache HttpClient Cache (org.apache.httpcomponents:httpclient-cache:4.2.6 - http://hc.apache.org/httpcomponents-client)
|
|
||||||
* Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.4 - http://hc.apache.org/httpcomponents-core-ga)
|
|
||||||
* Apache HttpClient Mime (org.apache.httpcomponents:httpmime:4.3.1 - http://hc.apache.org/httpcomponents-client)
|
|
||||||
* Apache JAMES Mime4j (Core) (org.apache.james:apache-mime4j-core:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-core)
|
|
||||||
* Apache JAMES Mime4j (DOM) (org.apache.james:apache-mime4j-dom:0.7.2 - http://james.apache.org/mime4j/apache-mime4j-dom)
|
|
||||||
* Apache Jena - Libraries POM (org.apache.jena:apache-jena-libs:2.13.0 - http://jena.apache.org/apache-jena-libs/)
|
|
||||||
* Apache Jena - ARQ (SPARQL 1.1 Query Engine) (org.apache.jena:jena-arq:2.13.0 - http://jena.apache.org/jena-arq/)
|
|
||||||
* Apache Jena - Core (org.apache.jena:jena-core:2.13.0 - http://jena.apache.org/jena-core/)
|
|
||||||
* Apache Jena - IRI (org.apache.jena:jena-iri:1.1.2 - http://jena.apache.org/jena-iri/)
|
|
||||||
* Apache Jena - TDB (Native Triple Store) (org.apache.jena:jena-tdb:1.1.2 - http://jena.apache.org/jena-tdb/)
|
|
||||||
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
|
|
||||||
* Lucene Common Analyzers (org.apache.lucene:lucene-analyzers-common:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-common)
|
|
||||||
* Lucene ICU Analysis Components (org.apache.lucene:lucene-analyzers-icu:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-icu)
|
|
||||||
* Lucene Kuromoji Japanese Morphological Analyzer (org.apache.lucene:lucene-analyzers-kuromoji:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-kuromoji)
|
|
||||||
* Lucene Morfologik Polish Lemmatizer (org.apache.lucene:lucene-analyzers-morfologik:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-morfologik)
|
|
||||||
* Lucene Phonetic Filters (org.apache.lucene:lucene-analyzers-phonetic:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-phonetic)
|
|
||||||
* Lucene Smart Chinese Analyzer (org.apache.lucene:lucene-analyzers-smartcn:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-smartcn)
|
|
||||||
* Lucene Stempel Analyzer (org.apache.lucene:lucene-analyzers-stempel:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-analyzers-stempel)
|
|
||||||
* Lucene codecs (org.apache.lucene:lucene-codecs:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-codecs)
|
|
||||||
* Lucene Core (org.apache.lucene:lucene-core:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-core)
|
|
||||||
* Lucene Core (org.apache.lucene:lucene-core:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-core)
|
|
||||||
* Lucene Expressions (org.apache.lucene:lucene-expressions:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-expressions)
|
|
||||||
* Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-grouping)
|
|
||||||
* Lucene Grouping (org.apache.lucene:lucene-grouping:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-grouping)
|
|
||||||
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
|
|
||||||
* Lucene Highlighter (org.apache.lucene:lucene-highlighter:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-highlighter)
|
|
||||||
* Lucene Join (org.apache.lucene:lucene-join:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-join)
|
|
||||||
* Lucene Join (org.apache.lucene:lucene-join:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-join)
|
|
||||||
* Lucene Memory (org.apache.lucene:lucene-memory:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-memory)
|
|
||||||
* Lucene Memory (org.apache.lucene:lucene-memory:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-memory)
|
|
||||||
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-misc)
|
|
||||||
* Lucene Miscellaneous (org.apache.lucene:lucene-misc:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-misc)
|
|
||||||
* Lucene Queries (org.apache.lucene:lucene-queries:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queries)
|
|
||||||
* Lucene Queries (org.apache.lucene:lucene-queries:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queries)
|
|
||||||
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
|
|
||||||
* Lucene QueryParsers (org.apache.lucene:lucene-queryparser:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-queryparser)
|
|
||||||
* Lucene Sandbox (org.apache.lucene:lucene-sandbox:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-sandbox)
|
|
||||||
* Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-spatial)
|
|
||||||
* Lucene Spatial (org.apache.lucene:lucene-spatial:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-spatial)
|
|
||||||
* Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.2 - http://lucene.apache.org/lucene-parent/lucene-suggest)
|
|
||||||
* Lucene Suggest (org.apache.lucene:lucene-suggest:4.10.4 - http://lucene.apache.org/lucene-parent/lucene-suggest)
|
|
||||||
* Apache FontBox (org.apache.pdfbox:fontbox:2.0.2 - http://pdfbox.apache.org/)
|
|
||||||
* Apache JempBox (org.apache.pdfbox:jempbox:1.8.4 - http://www.apache.org/pdfbox-parent/jempbox/)
|
|
||||||
* Apache PDFBox (org.apache.pdfbox:pdfbox:2.0.2 - http://www.apache.org/pdfbox-parent/pdfbox/)
|
|
||||||
* Apache POI (org.apache.poi:poi:3.13 - http://poi.apache.org/)
|
|
||||||
* Apache POI (org.apache.poi:poi-ooxml:3.13 - http://poi.apache.org/)
|
|
||||||
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.10.1 - http://poi.apache.org/)
|
|
||||||
* Apache POI (org.apache.poi:poi-ooxml-schemas:3.13 - http://poi.apache.org/)
|
|
||||||
* Apache POI (org.apache.poi:poi-scratchpad:3.13 - http://poi.apache.org/)
|
|
||||||
* Apache Solr Search Server (org.apache.solr:solr:4.10.4 - http://lucene.apache.org/solr-parent/solr)
|
|
||||||
* Apache Solr Analysis Extras (org.apache.solr:solr-analysis-extras:4.10.4 - http://lucene.apache.org/solr-parent/solr-analysis-extras)
|
|
||||||
* Apache Solr Content Extraction Library (org.apache.solr:solr-cell:4.10.4 - http://lucene.apache.org/solr-parent/solr-cell)
|
|
||||||
* Apache Solr Core (org.apache.solr:solr-core:4.10.4 - http://lucene.apache.org/solr-parent/solr-core)
|
|
||||||
* Apache Solr Solrj (org.apache.solr:solr-solrj:4.10.4 - http://lucene.apache.org/solr-parent/solr-solrj)
|
|
||||||
* Apache Thrift (org.apache.thrift:libthrift:0.9.2 - http://thrift.apache.org)
|
|
||||||
* Apache Tika core (org.apache.tika:tika-core:1.5 - http://tika.apache.org/)
|
|
||||||
* Apache Tika parsers (org.apache.tika:tika-parsers:1.5 - http://tika.apache.org/)
|
|
||||||
* Apache Tika XMP (org.apache.tika:tika-xmp:1.5 - http://tika.apache.org/)
|
|
||||||
* Axiom API (org.apache.ws.commons.axiom:axiom-api:1.2.14 - http://ws.apache.org/axiom/)
|
|
||||||
* Axiom Impl (org.apache.ws.commons.axiom:axiom-impl:1.2.14 - http://ws.apache.org/axiom/)
|
|
||||||
* XmlBeans (org.apache.xmlbeans:xmlbeans:2.6.0 - http://xmlbeans.apache.org)
|
|
||||||
* zookeeper (org.apache.zookeeper:zookeeper:3.4.6 - no url defined)
|
|
||||||
* Evo Inflector (org.atteo:evo-inflector:1.2.1 - http://atteo.org/static/evo-inflector)
|
|
||||||
* TagSoup (org.ccil.cowan.tagsoup:tagsoup:1.2.1 - http://home.ccil.org/~cowan/XML/tagsoup/)
|
|
||||||
* Jackson (org.codehaus.jackson:jackson-core-asl:1.9.13 - http://jackson.codehaus.org)
|
|
||||||
* Data Mapper for Jackson (org.codehaus.jackson:jackson-mapper-asl:1.9.13 - http://jackson.codehaus.org)
|
|
||||||
* Woodstox (org.codehaus.woodstox:woodstox-core-asl:4.1.4 - http://woodstox.codehaus.org)
|
|
||||||
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.0 - http://woodstox.codehaus.org)
|
|
||||||
* Woodstox (org.codehaus.woodstox:wstx-asl:3.2.7 - http://woodstox.codehaus.org)
|
|
||||||
* flyway-core (org.flywaydb:flyway-core:4.0.3 - https://flywaydb.org/flyway-core)
|
|
||||||
* Ogg and Vorbis for Java, Core (org.gagravarr:vorbis-java-core:0.1 - https://github.com/Gagravarr/VorbisJava)
|
|
||||||
* Apache Tika plugin for Ogg, Vorbis and FLAC (org.gagravarr:vorbis-java-tika:0.1 - https://github.com/Gagravarr/VorbisJava)
|
|
||||||
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
|
|
||||||
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty)
|
|
||||||
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester)
|
|
||||||
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
|
|
||||||
* Servlet Specification API (org.mortbay.jetty:servlet-api:2.5-20081211 - http://jetty.mortbay.org/servlet-api)
|
|
||||||
* Noggit (org.noggit:noggit:0.5 - http://noggit.org)
|
|
||||||
* Objenesis (org.objenesis:objenesis:2.1 - http://objenesis.org)
|
|
||||||
* parboiled-core (org.parboiled:parboiled-core:1.1.6 - http://parboiled.org)
|
|
||||||
* parboiled-java (org.parboiled:parboiled-java:1.1.6 - http://parboiled.org)
|
|
||||||
* org.restlet (org.restlet.jee:org.restlet:2.1.1 - no url defined)
|
|
||||||
* org.restlet.ext.servlet (org.restlet.jee:org.restlet.ext.servlet:2.1.1 - no url defined)
|
|
||||||
* rome-modules (org.rometools:rome-modules:1.0 - http://www.rometools.org)
|
|
||||||
* Spring AOP (org.springframework:spring-aop:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring AOP (org.springframework:spring-aop:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Beans (org.springframework:spring-beans:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Beans (org.springframework:spring-beans:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Context (org.springframework:spring-context:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Context (org.springframework:spring-context:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Context Support (org.springframework:spring-context-support:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Core (org.springframework:spring-core:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Core (org.springframework:spring-core:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Expression Language (SpEL) (org.springframework:spring-expression:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring JDBC (org.springframework:spring-jdbc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring JDBC (org.springframework:spring-jdbc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Object/Relational Mapping (org.springframework:spring-orm:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring TestContext Framework (org.springframework:spring-test:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Transaction (org.springframework:spring-tx:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Transaction (org.springframework:spring-tx:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Web (org.springframework:spring-web:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Web (org.springframework:spring-web:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Web MVC (org.springframework:spring-webmvc:3.2.16.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* Spring Web MVC (org.springframework:spring-webmvc:3.2.5.RELEASE - https://github.com/SpringSource/spring-framework)
|
|
||||||
* spring-security-config (org.springframework.security:spring-security-config:3.2.9.RELEASE - http://spring.io/spring-security)
|
|
||||||
* spring-security-core (org.springframework.security:spring-security-core:3.2.9.RELEASE - http://spring.io/spring-security)
|
|
||||||
* spring-security-web (org.springframework.security:spring-security-web:3.2.9.RELEASE - http://spring.io/spring-security)
|
|
||||||
* SWORD Java API, GUI and CLI (org.swordapp:sword-common:1.1 - http://nexus.sonatype.org/oss-repository-hosting.html/sword-common)
|
|
||||||
* SWORD v2 :: Common Server Library (org.swordapp:sword2-server:1.0 - http://www.swordapp.org/)
|
|
||||||
* xml-matchers (org.xmlmatchers:xml-matchers:0.10 - http://code.google.com/p/xml-matchers/)
|
|
||||||
* oro (oro:oro:2.0.8 - no url defined)
|
|
||||||
* JUnitParams (pl.pragmatists:JUnitParams:1.0.2 - http://junitparams.googlecode.com)
|
|
||||||
* Rome A9 OpenSearch (rome:opensearch:0.1 - http://wiki.java.net/bin/view/Javawsxml/OpenSearch)
|
|
||||||
* ROME, RSS and atOM utilitiEs for Java (rome:rome:1.0 - https://rome.dev.java.net/)
|
|
||||||
* oai4j (se.kb:oai4j:0.6b1 - http://oai4j-client.sourceforge.net/)
|
|
||||||
* StAX API (stax:stax-api:1.0.1 - http://stax.codehaus.org/)
|
|
||||||
* standard (taglibs:standard:1.1.2 - no url defined)
|
|
||||||
* Xalan Java Serializer (xalan:serializer:2.7.2 - http://xml.apache.org/xalan-j/)
|
|
||||||
* Xalan Java (xalan:xalan:2.7.2 - http://xml.apache.org/xalan-j/)
|
|
||||||
* Xerces2-j (xerces:xercesImpl:2.11.0 - https://xerces.apache.org/xerces2-j/)
|
|
||||||
* xmlParserAPIs (xerces:xmlParserAPIs:2.6.2 - no url defined)
|
|
||||||
* XML Commons External Components XML APIs (xml-apis:xml-apis:1.4.01 - http://xml.apache.org/commons/components/external/)
|
|
||||||
* XML Commons Resolver Component (xml-resolver:xml-resolver:1.2 - http://xml.apache.org/commons/components/resolver/)
|
|
||||||
|
|
||||||
BSD License:
|
|
||||||
|
|
||||||
* AntLR Parser Generator (antlr:antlr:2.7.7 - http://www.antlr.org/)
|
|
||||||
* ASM Core (asm:asm:3.3.1 - http://asm.objectweb.org/asm/)
|
|
||||||
* XMP Library for Java (com.adobe.xmp:xmpcore:5.1.2 - http://www.adobe.com/devnet/xmp.html)
|
|
||||||
* coverity-escapers (com.coverity.security:coverity-escapers:1.1.1 - http://coverity.com/security)
|
|
||||||
* JSONLD Java :: Core (com.github.jsonld-java:jsonld-java:0.5.1 - http://github.com/jsonld-java/jsonld-java/jsonld-java/)
|
|
||||||
* Protocol Buffer Java API (com.google.protobuf:protobuf-java:2.5.0 - http://code.google.com/p/protobuf)
|
|
||||||
* Jena IRI (com.hp.hpl.jena:iri:0.8 - http://jena.sf.net/iri)
|
|
||||||
* Jena (com.hp.hpl.jena:jena:2.6.4 - http://www.openjena.org/)
|
|
||||||
* yui compressor (com.yahoo.platform.yui:yuicompressor:2.3.6 - http://developer.yahoo.com/yui/compressor/)
|
|
||||||
* dnsjava (dnsjava:dnsjava:2.1.7 - http://www.dnsjava.org)
|
|
||||||
* dom4j (dom4j:dom4j:1.6.1 - http://dom4j.org)
|
|
||||||
* Biblio Transformation Engine :: Core (gr.ekt.bte:bte-core:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-core)
|
|
||||||
* Biblio Transformation Engine :: Input/Output (gr.ekt.bte:bte-io:0.9.3.5 - http://github.com/EKT/Biblio-Transformation-Engine/bte-io)
|
|
||||||
* jaxen (jaxen:jaxen:1.1.6 - http://jaxen.codehaus.org/)
|
|
||||||
* JLine (jline:jline:0.9.94 - http://jline.sourceforge.net)
|
|
||||||
* ANTLR 3 Runtime (org.antlr:antlr-runtime:3.5 - http://www.antlr.org)
|
|
||||||
* Morfologik FSA (org.carrot2:morfologik-fsa:1.7.1 - http://morfologik.blogspot.com/morfologik-fsa/)
|
|
||||||
* Morfologik Stemming Dictionary for Polish (org.carrot2:morfologik-polish:1.7.1 - http://morfologik.blogspot.com/morfologik-polish/)
|
|
||||||
* Morfologik Stemming APIs (org.carrot2:morfologik-stemming:1.7.1 - http://morfologik.blogspot.com/morfologik-stemming/)
|
|
||||||
* Stax2 API (org.codehaus.woodstox:stax2-api:3.1.1 - http://woodstox.codehaus.org/StAX2)
|
|
||||||
* DSpace Kernel :: API and Implementation (org.dspace:dspace-api:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-api)
|
|
||||||
* DSpace I18N :: Language Packs (org.dspace:dspace-api-lang:6.0.3 - https://github.com/dspace/dspace-api-lang)
|
|
||||||
* DSpace JSP-UI (org.dspace:dspace-jspui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-jspui)
|
|
||||||
* DSpace OAI-PMH (org.dspace:dspace-oai:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-oai)
|
|
||||||
* DSpace RDF (org.dspace:dspace-rdf:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-rdf)
|
|
||||||
* DSpace REST :: API and Implementation (org.dspace:dspace-rest:6.0-rc4-SNAPSHOT - http://demo.dspace.org)
|
|
||||||
* DSpace Services Framework :: API and Implementation (org.dspace:dspace-services:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-services)
|
|
||||||
* Apache Solr Webapp (org.dspace:dspace-solr:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-solr)
|
|
||||||
* DSpace SWORD (org.dspace:dspace-sword:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-sword)
|
|
||||||
* DSpace SWORD v2 (org.dspace:dspace-swordv2:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-swordv2)
|
|
||||||
* DSpace XML-UI (Manakin) (org.dspace:dspace-xmlui:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/dspace-xmlui)
|
|
||||||
* DSpace XML-UI (Manakin) I18N :: Language Packs (org.dspace:dspace-xmlui-lang:6.0.3 - https://github.com/dspace/dspace-xmlui-lang)
|
|
||||||
* handle (org.dspace:handle:6.2 - no url defined)
|
|
||||||
* jargon (org.dspace:jargon:1.4.25 - no url defined)
|
|
||||||
* mets (org.dspace:mets:1.5.2 - no url defined)
|
|
||||||
* oclc-harvester2 (org.dspace:oclc-harvester2:0.1.12 - no url defined)
|
|
||||||
* XOAI : OAI-PMH Java Toolkit (org.dspace:xoai:3.2.10 - http://nexus.sonatype.org/oss-repository-hosting.html/xoai)
|
|
||||||
* Repackaged Cocoon Servlet Service Implementation (org.dspace.dependencies.cocoon:dspace-cocoon-servlet-service-impl:1.0.3 - http://projects.dspace.org/dspace-pom/dspace-cocoon-servlet-service-impl)
|
|
||||||
* DSpace Kernel :: Additions and Local Customizations (org.dspace.modules:additions:6.0-rc4-SNAPSHOT - https://github.com/dspace/DSpace/modules/additions)
|
|
||||||
* Hamcrest All (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
|
|
||||||
* Hamcrest Core (org.hamcrest:hamcrest-all:1.3 - https://github.com/hamcrest/JavaHamcrest/hamcrest-all)
|
|
||||||
* JBibTeX (org.jbibtex:jbibtex:1.0.10 - http://www.jbibtex.org)
|
|
||||||
* ASM Core (org.ow2.asm:asm:4.1 - http://asm.objectweb.org/asm/)
|
|
||||||
* ASM Analysis (org.ow2.asm:asm-analysis:4.1 - http://asm.objectweb.org/asm-analysis/)
|
|
||||||
* ASM Commons (org.ow2.asm:asm-commons:4.1 - http://asm.objectweb.org/asm-commons/)
|
|
||||||
* ASM Tree (org.ow2.asm:asm-tree:4.1 - http://asm.objectweb.org/asm-tree/)
|
|
||||||
* ASM Util (org.ow2.asm:asm-util:4.1 - http://asm.objectweb.org/asm-util/)
|
|
||||||
* XMLUnit for Java (xmlunit:xmlunit:1.1 - http://xmlunit.sourceforge.net/)
|
|
||||||
* XMLUnit for Java (xmlunit:xmlunit:1.3 - http://xmlunit.sourceforge.net/)
|
|
||||||
|
|
||||||
Common Development and Distribution License (CDDL):
|
|
||||||
|
|
||||||
* JAXB Reference Implementation (com.sun.xml.bind:jaxb-impl:2.2.5 - http://jaxb.java.net/)
|
|
||||||
* JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
|
|
||||||
* JavaBeans(TM) Activation Framework (javax.activation:activation:1.1.1 - http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
|
|
||||||
* javax.annotation API (javax.annotation:javax.annotation-api:1.2 - http://jcp.org/en/jsr/detail?id=250)
|
|
||||||
* JavaMail API (compat) (javax.mail:mail:1.4.7 - http://kenai.com/projects/javamail/mail)
|
|
||||||
* Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
|
|
||||||
* jsp-api (javax.servlet:jsp-api:2.0 - no url defined)
|
|
||||||
* jstl (javax.servlet:jstl:1.2 - no url defined)
|
|
||||||
* servlet-api (javax.servlet:servlet-api:2.5 - no url defined)
|
|
||||||
* javax.ws.rs-api (javax.ws.rs:javax.ws.rs-api:2.0.1 - http://jax-rs-spec.java.net)
|
|
||||||
* Class Model for Hk2 (org.glassfish.hk2:class-model:2.4.0-b31 - https://hk2.java.net/class-model)
|
|
||||||
* HK2 config types (org.glassfish.hk2:config-types:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/config-types)
|
|
||||||
* HK2 module of HK2 itself (org.glassfish.hk2:hk2:2.4.0-b31 - https://hk2.java.net/hk2)
|
|
||||||
* HK2 API module (org.glassfish.hk2:hk2-api:2.4.0-b31 - https://hk2.java.net/hk2-api)
|
|
||||||
* HK2 configuration module (org.glassfish.hk2:hk2-config:2.4.0-b31 - https://hk2.java.net/hk2-configuration/hk2-configuration-persistence/hk2-xml-dom/hk2-config)
|
|
||||||
* HK2 core module (org.glassfish.hk2:hk2-core:2.4.0-b31 - https://hk2.java.net/hk2-core)
|
|
||||||
* ServiceLocator Default Implementation (org.glassfish.hk2:hk2-locator:2.4.0-b31 - https://hk2.java.net/hk2-locator)
|
|
||||||
* Run Level Service (org.glassfish.hk2:hk2-runlevel:2.4.0-b31 - https://hk2.java.net/hk2-runlevel)
|
|
||||||
* HK2 Implementation Utilities (org.glassfish.hk2:hk2-utils:2.4.0-b31 - https://hk2.java.net/hk2-utils)
|
|
||||||
* OSGi resource locator bundle - used by various API providers that rely on META-INF/services mechanism to locate providers. (org.glassfish.hk2:osgi-resource-locator:1.0.1 - http://glassfish.org/osgi-resource-locator/)
|
|
||||||
* HK2 Spring Bridge (org.glassfish.hk2:spring-bridge:2.4.0-b31 - https://hk2.java.net/spring-bridge)
|
|
||||||
* aopalliance version 1.0 repackaged as a module (org.glassfish.hk2.external:aopalliance-repackaged:2.4.0-b31 - https://hk2.java.net/external/aopalliance-repackaged)
|
|
||||||
* ASM library repackaged as OSGi bundle (org.glassfish.hk2.external:asm-all-repackaged:2.4.0-b31 - https://hk2.java.net/external/asm-all-repackaged)
|
|
||||||
* javax.validation:1.1.0.Final as OSGi bundle (org.glassfish.hk2.external:bean-validator:2.4.0-b31 - https://hk2.java.net/external/bean-validator)
|
|
||||||
* javax.inject:1 as OSGi bundle (org.glassfish.hk2.external:javax.inject:2.4.0-b31 - https://hk2.java.net/external/javax.inject)
|
|
||||||
* jersey-repackaged-guava (org.glassfish.jersey.bundles.repackaged:jersey-guava:2.22.1 - https://jersey.java.net/project/project/jersey-guava/)
|
|
||||||
* jersey-container-servlet (org.glassfish.jersey.containers:jersey-container-servlet:2.22.1 - https://jersey.java.net/project/jersey-container-servlet/)
|
|
||||||
* jersey-container-servlet-core (org.glassfish.jersey.containers:jersey-container-servlet-core:2.22.1 - https://jersey.java.net/project/jersey-container-servlet-core/)
|
|
||||||
* jersey-core-client (org.glassfish.jersey.core:jersey-client:2.22.1 - https://jersey.java.net/jersey-client/)
|
|
||||||
* jersey-core-common (org.glassfish.jersey.core:jersey-common:2.22.1 - https://jersey.java.net/jersey-common/)
|
|
||||||
* jersey-core-server (org.glassfish.jersey.core:jersey-server:2.22.1 - https://jersey.java.net/jersey-server/)
|
|
||||||
* jersey-ext-entity-filtering (org.glassfish.jersey.ext:jersey-entity-filtering:2.22.1 - https://jersey.java.net/project/jersey-entity-filtering/)
|
|
||||||
* jersey-spring3 (org.glassfish.jersey.ext:jersey-spring3:2.22.1 - https://jersey.java.net/project/jersey-spring3/)
|
|
||||||
* jersey-media-jaxb (org.glassfish.jersey.media:jersey-media-jaxb:2.22.1 - https://jersey.java.net/project/jersey-media-jaxb/)
|
|
||||||
* jersey-media-json-jackson (org.glassfish.jersey.media:jersey-media-json-jackson:2.22.1 - https://jersey.java.net/project/jersey-media-json-jackson/)
|
|
||||||
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
|
|
||||||
* Type arithmetic library for Java5 (org.jvnet:tiger-types:1.4 - http://java.net/tiger-types/)
|
|
||||||
|
|
||||||
Eclipse Public License:
|
|
||||||
|
|
||||||
* JUnit (junit:junit:4.11 - http://junit.org)
|
|
||||||
* AspectJ runtime (org.aspectj:aspectjrt:1.6.11 - http://www.aspectj.org)
|
|
||||||
* JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
|
|
||||||
* Jetty Server (org.mortbay.jetty:jetty:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/modules/jetty)
|
|
||||||
* Jetty Servlet Tester (org.mortbay.jetty:jetty-servlet-tester:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-servlet-tester)
|
|
||||||
* Jetty Utilities (org.mortbay.jetty:jetty-util:6.1.26 - http://www.eclipse.org/jetty/jetty-parent/project/jetty-util)
|
|
||||||
|
|
||||||
GNU General Public License, Version 2 with the Classpath Exception:
|
|
||||||
|
|
||||||
* Java Transaction API (org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.1.Final - http://www.jboss.org/jboss-transaction-api_1.1_spec)
|
|
||||||
|
|
||||||
GNU Lesser General Public License (LGPL):
|
|
||||||
|
|
||||||
* FindBugs-Annotations (com.google.code.findbugs:annotations:3.0.1u2 - http://findbugs.sourceforge.net/)
|
|
||||||
* MaxMind GeoIP Legacy API (com.maxmind.geoip:geoip-api:1.3.0 - https://github.com/maxmind/geoip-api-java)
|
|
||||||
* JHighlight (com.uwyn:jhighlight:1.0 - https://jhighlight.dev.java.net/)
|
|
||||||
* DSpace TM-Extractors Dependency (org.dspace.dependencies:dspace-tm-extractors:1.0.1 - http://projects.dspace.org/dspace-pom/dspace-tm-extractors)
|
|
||||||
* A Hibernate O/RM Module (org.hibernate:hibernate-core:4.2.21.Final - http://hibernate.org)
|
|
||||||
* A Hibernate O/RM Module (org.hibernate:hibernate-ehcache:4.2.21.Final - http://hibernate.org)
|
|
||||||
* Hibernate Commons Annotations (org.hibernate.common:hibernate-commons-annotations:4.0.2.Final - http://hibernate.org)
|
|
||||||
* im4java (org.im4java:im4java:1.4.0 - http://sourceforge.net/projects/im4java/)
|
|
||||||
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
|
|
||||||
* JBoss Logging 3 (org.jboss.logging:jboss-logging:3.1.0.GA - http://www.jboss.org)
|
|
||||||
* org.jdesktop - Swing Worker (org.jdesktop:swing-worker:1.1 - no url defined)
|
|
||||||
* xom (xom:xom:1.1 - http://www.xom.nu)
|
|
||||||
* XOM (xom:xom:1.2.5 - http://xom.nu)
|
|
||||||
|
|
||||||
ICU License:
|
|
||||||
|
|
||||||
* ICU4J (com.ibm.icu:icu4j:56.1 - http://icu-project.org/)
|
|
||||||
|
|
||||||
JDOM License (Apache-style license):
|
|
||||||
|
|
||||||
* jdom (jdom:jdom:1.0 - no url defined)
|
|
||||||
|
|
||||||
MIT License:
|
|
||||||
|
|
||||||
* Bouncy Castle CMS and S/MIME API (org.bouncycastle:bcmail-jdk15:1.46 - http://www.bouncycastle.org/java.html)
|
|
||||||
* Bouncy Castle Provider (org.bouncycastle:bcprov-jdk15:1.46 - http://www.bouncycastle.org/java.html)
|
|
||||||
* Main (org.jmockit:jmockit:1.21 - http://www.jmockit.org)
|
|
||||||
* OpenCloud (org.mcavallo:opencloud:0.3 - http://opencloud.mcavallo.org/)
|
|
||||||
* Mockito (org.mockito:mockito-core:1.10.19 - http://www.mockito.org)
|
|
||||||
* JCL 1.1.1 implemented over SLF4J (org.slf4j:jcl-over-slf4j:1.7.14 - http://www.slf4j.org)
|
|
||||||
* JUL to SLF4J bridge (org.slf4j:jul-to-slf4j:1.7.14 - http://www.slf4j.org)
|
|
||||||
* SLF4J API Module (org.slf4j:slf4j-api:1.7.14 - http://www.slf4j.org)
|
|
||||||
* SLF4J LOG4J-12 Binding (org.slf4j:slf4j-log4j12:1.7.14 - http://www.slf4j.org)
|
|
||||||
|
|
||||||
Mozilla Public License:
|
|
||||||
|
|
||||||
* juniversalchardet (com.googlecode.juniversalchardet:juniversalchardet:1.0.3 - http://juniversalchardet.googlecode.com/)
|
|
||||||
* h2 (com.h2database:h2:1.4.187 - no url defined)
|
|
||||||
* Javassist (org.javassist:javassist:3.18.1-GA - http://www.javassist.org/)
|
|
||||||
* Rhino (rhino:js:1.6R7 - http://www.mozilla.org/rhino/)
|
|
||||||
|
|
||||||
Public Domain:
|
|
||||||
|
|
||||||
* AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
|
|
||||||
* Dough Lea's util.concurrent package (concurrent:concurrent:1.3.4 - no url defined)
|
|
||||||
* Reflections (org.reflections:reflections:0.9.9-RC1 - http://code.google.com/p/reflections/reflections/)
|
|
||||||
* XZ for Java (org.tukaani:xz:1.4 - http://tukaani.org/xz/java.html)
|
|
||||||
|
|
||||||
Similar to Apache License but with the acknowledgment clause removed:
|
|
||||||
|
|
||||||
* JDOM (org.jdom:jdom:1.1.3 - http://www.jdom.org)
|
|
||||||
|
|
||||||
The PostgreSQL License:
|
|
||||||
|
|
||||||
* PostgreSQL JDBC Driver - JDBC 4.2 (org.postgresql:postgresql:9.4.1211 - https://github.com/pgjdbc/pgjdbc)
|
|
||||||
|
|
||||||
license.txt:
|
|
||||||
|
|
||||||
* JPA 2.0 API (org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final - http://hibernate.org)
|
|
||||||
@@ -1,5 +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/
|
|
||||||
15
NOTICE
15
NOTICE
@@ -1,15 +0,0 @@
|
|||||||
|
|
||||||
Licensing Notice
|
|
||||||
|
|
||||||
Fedora Commons joined with the DSpace Foundation and began operating under
|
|
||||||
the new name DuraSpace in July 2009. DuraSpace holds the copyrights of
|
|
||||||
the DSpace Foundation, Inc.
|
|
||||||
|
|
||||||
The DSpace Foundation, Inc. is a 501(c)3 corporation established in July 2007
|
|
||||||
with a mission to promote and advance the dspace platform enabling management,
|
|
||||||
access and preservation of digital works. The Foundation was able to transfer
|
|
||||||
the legal copyright from Hewlett-Packard Company (HP) and Massachusetts
|
|
||||||
Institute of Technology (MIT) to the DSpace Foundation in October 2007. Many
|
|
||||||
of the files in the source code may contain a copyright statement stating HP
|
|
||||||
and MIT possess the copyright, in these instances please note that the copy
|
|
||||||
right has transferred to the DSpace foundation, and subsequently to DuraSpace.
|
|
||||||
85
README.md
85
README.md
@@ -1,85 +0,0 @@
|
|||||||
|
|
||||||
# DSpace
|
|
||||||
|
|
||||||
## NOTE: The rest-tutorial branch has been created to support the [DSpace 7 REST documentation](https://dspace-labs.github.io/DSpace7RestTutorial/walkthrough/intro)
|
|
||||||
- This branch provides stable, referencable line numbers in code
|
|
||||||
|
|
||||||
[](https://travis-ci.org/DSpace/DSpace)
|
|
||||||
|
|
||||||
[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) |
|
|
||||||
[Support](https://wiki.duraspace.org/display/DSPACE/Support)
|
|
||||||
|
|
||||||
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.
|
|
||||||
* 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.
|
|
||||||
***
|
|
||||||
|
|
||||||
## Downloads
|
|
||||||
|
|
||||||
The latest release of DSpace can be downloaded from the [DSpace website](http://www.dspace.org/latest-release/) or from [GitHub](https://github.com/DSpace/DSpace/releases).
|
|
||||||
|
|
||||||
Past releases are all available via GitHub at https://github.com/DSpace/DSpace/releases
|
|
||||||
|
|
||||||
## Documentation / Installation
|
|
||||||
|
|
||||||
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)
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
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:
|
|
||||||
* [How to Contribute to DSpace](https://wiki.duraspace.org/display/DSPACE/How+to+Contribute+to+DSpace): How to contribute in general (via code, documentation, bug reports, expertise, etc)
|
|
||||||
* [Code Contribution Guidelines](https://wiki.duraspace.org/display/DSPACE/Code+Contribution+Guidelines): How to give back code or contribute features, bug fixes, etc.
|
|
||||||
* [DSpace Community Advisory Team (DCAT)](https://wiki.duraspace.org/display/cmtygp/DSpace+Community+Advisory+Team): If you are not a developer, we also have an interest group specifically for repository managers. The DCAT group meets virtually, once a month, and sends open invitations to join their meetings via the [DCAT mailing list](https://groups.google.com/d/forum/DSpaceCommunityAdvisoryTeam).
|
|
||||||
|
|
||||||
We also encourage GitHub Pull Requests (PRs) at any time. Please see our [Development with Git](https://wiki.duraspace.org/display/DSPACE/Development+with+Git) guide for more info.
|
|
||||||
|
|
||||||
In addition, a listing of all known contributors to DSpace software can be
|
|
||||||
found online at: https://wiki.duraspace.org/display/DSPACE/DSpaceContributors
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
DSpace provides public mailing lists where you can post questions or raise topics for discussion.
|
|
||||||
We welcome everyone to participate in these lists:
|
|
||||||
|
|
||||||
* [dspace-community@googlegroups.com](https://groups.google.com/d/forum/dspace-community) : General discussion about DSpace platform, announcements, sharing of best practices
|
|
||||||
* [dspace-tech@googlegroups.com](https://groups.google.com/d/forum/dspace-tech) : Technical support mailing list. See also our guide for [How to troubleshoot an error](https://wiki.duraspace.org/display/DSPACE/Troubleshoot+an+error).
|
|
||||||
* [dspace-devel@googlegroups.com](https://groups.google.com/d/forum/dspace-devel) : Developers / Development mailing list
|
|
||||||
|
|
||||||
Great Q&A is also available under the [DSpace tag on Stackoverflow](http://stackoverflow.com/questions/tagged/dspace)
|
|
||||||
|
|
||||||
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
|
|
||||||
[Registered Service Providers](http://www.dspace.org/service-providers).
|
|
||||||
|
|
||||||
## Issue Tracker
|
|
||||||
|
|
||||||
The DSpace Issue Tracker can be found at: https://jira.duraspace.org/projects/DS/summary
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
DSpace source code is freely available under a standard [BSD 3-Clause license](https://opensource.org/licenses/BSD-3-Clause).
|
|
||||||
The full license is available at http://www.dspace.org/license/
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE suppressions PUBLIC
|
|
||||||
"-//Puppy Crawl//DTD Suppressions 1.2//EN"
|
|
||||||
"http://checkstyle.sourceforge.net/dtds/suppressions_1_2.dtd">
|
|
||||||
<suppressions>
|
|
||||||
<!-- Temporarily suppress indentation checks for all Tests -->
|
|
||||||
<!-- TODO: We should have these turned on. But, currently there's a known bug with indentation checks
|
|
||||||
on JMockIt Expectations blocks and similar. See https://github.com/checkstyle/checkstyle/issues/3739 -->
|
|
||||||
<suppress checks="Indentation" files="src[/\\]test[/\\]java"/>
|
|
||||||
</suppressions>
|
|
||||||
144
checkstyle.xml
144
checkstyle.xml
@@ -1,144 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE module PUBLIC
|
|
||||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
|
||||||
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
|
|
||||||
<!--
|
|
||||||
DSpace CodeStyle Requirements
|
|
||||||
|
|
||||||
1. 4-space indents for Java, and 2-space indents for XML. NO TABS ALLOWED.
|
|
||||||
2. K&R style braces required. Braces required on all blocks.
|
|
||||||
3. Do not use wildcard imports (e.g. import java.util.*). Duplicated or unused imports also not allowed.
|
|
||||||
4. Javadocs should exist for all public classes and methods. (Methods rule is unenforced at this time.) Keep it short and to the point
|
|
||||||
5. Maximum line length is 120 characters (except for long URLs, packages or imports)
|
|
||||||
6. No trailing spaces allowed (except in comments)
|
|
||||||
7. Tokens should be surrounded by whitespace (see http://checkstyle.sourceforge.net/config_whitespace.html#WhitespaceAround)
|
|
||||||
8. Each source file must include our license header (validated separately by license-maven-plugin, see pom.xml)
|
|
||||||
|
|
||||||
For more information on CheckStyle configurations below, see: http://checkstyle.sourceforge.net/checks.html
|
|
||||||
-->
|
|
||||||
<module name="Checker">
|
|
||||||
<!-- Configure checker to use UTF-8 encoding -->
|
|
||||||
<property name="charset" value="UTF-8"/>
|
|
||||||
<!-- Configure checker to run on files with these extensions -->
|
|
||||||
<property name="fileExtensions" value="java, properties, cfg, xml"/>
|
|
||||||
|
|
||||||
<!-- Suppression configurations in checkstyle-suppressions.xml in same directory -->
|
|
||||||
<module name="SuppressionFilter">
|
|
||||||
<property name="file" value="${checkstyle.suppressions.file}" default="checkstyle-suppressions.xml"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- No tab characters ('\t') allowed in the source code -->
|
|
||||||
<module name="FileTabCharacter">
|
|
||||||
<property name="eachLine" value="true"/>
|
|
||||||
<property name="fileExtensions" value="java, properties, cfg, css, js, xml"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- No Trailing Whitespace, except on lines that only have an asterisk (e.g. Javadoc comments) -->
|
|
||||||
<module name="RegexpSingleline">
|
|
||||||
<property name="format" value="(?<!\*)\s+$|\*\s\s+$"/>
|
|
||||||
<property name="message" value="Line has trailing whitespace"/>
|
|
||||||
<property name="fileExtensions" value="java, properties, cfg, css, js, xml"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- Allow individual lines of code to be excluded from these rules, if they are annotated
|
|
||||||
with @SuppressWarnings. See also SuppressWarningsHolder below -->
|
|
||||||
<module name="SuppressWarningsFilter" />
|
|
||||||
|
|
||||||
<!-- Check individual Java source files for specific rules -->
|
|
||||||
<module name="TreeWalker">
|
|
||||||
<!-- Maximum line length is 120 characters -->
|
|
||||||
<module name="LineLength">
|
|
||||||
<property name="max" value="120"/>
|
|
||||||
<!-- Only exceptions for packages, imports, URLs, and JavaDoc {@link} tags -->
|
|
||||||
<property name="ignorePattern" value="^package.*|^import.*|http://|https://|@link"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- Highlight any TODO or FIXME comments in info messages -->
|
|
||||||
<module name="TodoComment">
|
|
||||||
<property name="severity" value="info"/>
|
|
||||||
<property name="format" value="(TODO)|(FIXME)"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- Do not report errors on any lines annotated with @SuppressWarnings -->
|
|
||||||
<module name="SuppressWarningsHolder"/>
|
|
||||||
|
|
||||||
<!-- ##### Import statement requirements ##### -->
|
|
||||||
<!-- Star imports (e.g. import java.util.*) are NOT ALLOWED -->
|
|
||||||
<module name="AvoidStarImport"/>
|
|
||||||
<!-- Redundant import statements are NOT ALLOWED -->
|
|
||||||
<module name="RedundantImport"/>
|
|
||||||
<!-- Unused import statements are NOT ALLOWED -->
|
|
||||||
<module name="UnusedImports"/>
|
|
||||||
<!-- Ensure imports appear alphabetically and grouped -->
|
|
||||||
<module name="CustomImportOrder">
|
|
||||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
|
||||||
<property name="separateLineBetweenGroups" value="true"/>
|
|
||||||
<property name="customImportOrderRules" value="STATIC###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- ##### Javadocs requirements ##### -->
|
|
||||||
<!-- Requirements for Javadocs for classes/interfaces -->
|
|
||||||
<module name="JavadocType">
|
|
||||||
<!-- All public classes/interfaces MUST HAVE Javadocs -->
|
|
||||||
<property name="scope" value="public"/>
|
|
||||||
<!-- Add an exception for anonymous inner classes -->
|
|
||||||
<property name="excludeScope" value="anoninner"/>
|
|
||||||
<!-- Ignore errors related to unknown tags -->
|
|
||||||
<property name="allowUnknownTags" value="true"/>
|
|
||||||
<!-- Allow params tags to be optional -->
|
|
||||||
<property name="allowMissingParamTags" value="false"/>
|
|
||||||
</module>
|
|
||||||
<!-- Requirements for Javadocs for methods -->
|
|
||||||
<module name="JavadocMethod">
|
|
||||||
<!-- All public methods MUST HAVE Javadocs -->
|
|
||||||
<!-- <property name="scope" value="public"/> -->
|
|
||||||
<!-- TODO: Above rule has been disabled because of large amount of missing public method Javadocs -->
|
|
||||||
<property name="scope" value="nothing"/>
|
|
||||||
<!-- Allow RuntimeExceptions to be undeclared -->
|
|
||||||
<property name="allowUndeclaredRTE" value="true"/>
|
|
||||||
<!-- Allow params, throws and return tags to be optional -->
|
|
||||||
<property name="allowMissingParamTags" value="true"/>
|
|
||||||
<property name="allowMissingThrowsTags" value="true"/>
|
|
||||||
<property name="allowMissingReturnTag" value="true"/>
|
|
||||||
</module>
|
|
||||||
|
|
||||||
<!-- ##### Requirements for K&R Style braces ##### -->
|
|
||||||
<!-- Code blocks MUST HAVE braces, even single line statements (if, while, etc) -->
|
|
||||||
<module name="NeedBraces"/>
|
|
||||||
<!-- Left braces should be at the end of current line (default value)-->
|
|
||||||
<module name="LeftCurly"/>
|
|
||||||
<!-- Right braces should be on start of a new line (default value) -->
|
|
||||||
<module name="RightCurly"/>
|
|
||||||
|
|
||||||
<!-- ##### Indentation / Whitespace requirements ##### -->
|
|
||||||
<!-- Require 4-space indentation (default value) -->
|
|
||||||
<module name="Indentation"/>
|
|
||||||
<!-- Whitespace should exist around all major tokens -->
|
|
||||||
<module name="WhitespaceAround">
|
|
||||||
<!-- However, make an exception for empty constructors, methods, types, etc. -->
|
|
||||||
<property name="allowEmptyConstructors" value="true"/>
|
|
||||||
<property name="allowEmptyMethods" value="true"/>
|
|
||||||
<property name="allowEmptyTypes" value="true"/>
|
|
||||||
<property name="allowEmptyLoops" value="true"/>
|
|
||||||
</module>
|
|
||||||
<!-- Validate whitespace around Generics (angle brackets) per typical conventions
|
|
||||||
http://checkstyle.sourceforge.net/config_whitespace.html#GenericWhitespace -->
|
|
||||||
<module name="GenericWhitespace"/>
|
|
||||||
|
|
||||||
<!-- ##### Requirements for "switch" statements ##### -->
|
|
||||||
<!-- "switch" statements MUST have a "default" clause -->
|
|
||||||
<module name="MissingSwitchDefault"/>
|
|
||||||
<!-- "case" clauses in switch statements MUST include break, return, throw or continue -->
|
|
||||||
<module name="FallThrough"/>
|
|
||||||
|
|
||||||
<!-- ##### Other / Miscellaneous requirements ##### -->
|
|
||||||
<!-- Require utility classes do not have a public constructor -->
|
|
||||||
<module name="HideUtilityClassConstructor"/>
|
|
||||||
<!-- Require each variable declaration is its own statement on its own line -->
|
|
||||||
<module name="MultipleVariableDeclarations"/>
|
|
||||||
<!-- Each line of code can only include one statement -->
|
|
||||||
<module name="OneStatementPerLine"/>
|
|
||||||
<!-- Require that "catch" statements are not empty (must at least contain a comment) -->
|
|
||||||
<module name="EmptyCatchBlock"/>
|
|
||||||
</module>
|
|
||||||
</module>
|
|
||||||
@@ -1,739 +0,0 @@
|
|||||||
<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>
|
|
||||||
<name>DSpace Kernel :: API and Implementation</name>
|
|
||||||
<description>DSpace core data model and service APIs.</description>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
A Parent POM that Maven inherits DSpace Defaults
|
|
||||||
POM attributes from.
|
|
||||||
-->
|
|
||||||
<parent>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>dspace-parent</artifactId>
|
|
||||||
<version>7.0-SNAPSHOT</version>
|
|
||||||
<relativePath>..</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<!-- This is the path to the root [dspace-src] directory. -->
|
|
||||||
<root.basedir>${basedir}/..</root.basedir>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Runtime and Compile Time dependencies for DSpace.
|
|
||||||
-->
|
|
||||||
<build>
|
|
||||||
<resources>
|
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
<includes>
|
|
||||||
<include>maven.properties</include>
|
|
||||||
<include>scm.properties</include>
|
|
||||||
</includes>
|
|
||||||
<filtering>true</filtering>
|
|
||||||
</resource>
|
|
||||||
<resource>
|
|
||||||
<directory>src/main/resources</directory>
|
|
||||||
<excludes>
|
|
||||||
<exclude>maven.properties</exclude>
|
|
||||||
<exclude>scm.properties</exclude>
|
|
||||||
</excludes>
|
|
||||||
<filtering>false</filtering>
|
|
||||||
</resource>
|
|
||||||
</resources>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<debug>true</debug>
|
|
||||||
<showDeprecation>true</showDeprecation>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-jar-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<archive>
|
|
||||||
<manifest>
|
|
||||||
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
|
||||||
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
|
||||||
</manifest>
|
|
||||||
</archive>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<goals>
|
|
||||||
<goal>test-jar</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
<!-- Verify OS license headers for all source code files -->
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.mycila</groupId>
|
|
||||||
<artifactId>license-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<excludes>
|
|
||||||
<exclude>**/src/test/resources/**</exclude>
|
|
||||||
<exclude>**/src/test/data/**</exclude>
|
|
||||||
<exclude>**/.gitignore</exclude>
|
|
||||||
<exclude>src/test/data/dspaceFolder/config/spiders/**</exclude>
|
|
||||||
<exclude>src/main/java/org/apache/solr/handler/extraction/ExtractingParams.java</exclude>
|
|
||||||
</excludes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>build-helper-maven-plugin</artifactId>
|
|
||||||
<version>1.9.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>maven-version</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
|
||||||
<version>1.4</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<phase>validate</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>create</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
|
|
||||||
<profiles>
|
|
||||||
<profile>
|
|
||||||
<id>findbugs</id>
|
|
||||||
<activation>
|
|
||||||
<activeByDefault>false</activeByDefault>
|
|
||||||
<!-- property>
|
|
||||||
<name>maven.test.skip</name>
|
|
||||||
<value>false</value>
|
|
||||||
</property -->
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>findbugs-maven-plugin</artifactId>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</profile>
|
|
||||||
|
|
||||||
<!-- If Unit Testing is enabled, then setup the Unit Test Environment.
|
|
||||||
See also the 'skiptests' profile in Parent POM. -->
|
|
||||||
<profile>
|
|
||||||
<id>test-environment</id>
|
|
||||||
<activation>
|
|
||||||
<activeByDefault>false</activeByDefault>
|
|
||||||
<property>
|
|
||||||
<name>maven.test.skip</name>
|
|
||||||
<value>false</value>
|
|
||||||
</property>
|
|
||||||
</activation>
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<!-- Unit/Integration Testing setup: This plugin unzips the
|
|
||||||
'testEnvironment.zip' file (created by dspace-parent POM), into
|
|
||||||
the 'target/testing/' folder, to essentially create a test
|
|
||||||
install of DSpace, against which Tests can be run. -->
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
|
||||||
<version>2.8</version>
|
|
||||||
<configuration>
|
|
||||||
<outputDirectory>${project.build.directory}/testing</outputDirectory>
|
|
||||||
<artifactItems>
|
|
||||||
<artifactItem>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>dspace-parent</artifactId>
|
|
||||||
<version>${project.version}</version>
|
|
||||||
<type>zip</type>
|
|
||||||
<classifier>testEnvironment</classifier>
|
|
||||||
</artifactItem>
|
|
||||||
</artifactItems>
|
|
||||||
</configuration>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>setupTestEnvironment</id>
|
|
||||||
<phase>generate-test-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
<execution>
|
|
||||||
<id>setupIntegrationTestEnvironment</id>
|
|
||||||
<phase>pre-integration-test</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>unpack</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- This plugin allows us to run a Groovy script in our Maven POM
|
|
||||||
(see: http://gmaven.codehaus.org/Executing+Groovy+Code )
|
|
||||||
We are generating a OS-agnostic version (agnostic.build.dir) of
|
|
||||||
the ${project.build.directory} property (full path of target dir).
|
|
||||||
This is needed by the FileWeaver & Surefire plugins (see below)
|
|
||||||
to initialize the Unit Test environment's dspace.cfg file.
|
|
||||||
Otherwise, the Unit Test Framework will not work on Windows OS.
|
|
||||||
This Groovy code was mostly borrowed from:
|
|
||||||
http://stackoverflow.com/questions/3872355/how-to-convert-file-separator-in-maven
|
|
||||||
-->
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.gmaven</groupId>
|
|
||||||
<artifactId>groovy-maven-plugin</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>setproperty</id>
|
|
||||||
<phase>generate-test-resources
|
|
||||||
</phase> <!-- XXX I think this should be 'initialize' - MHW -->
|
|
||||||
<goals>
|
|
||||||
<goal>execute</goal>
|
|
||||||
</goals>
|
|
||||||
<configuration>
|
|
||||||
<source>
|
|
||||||
project.properties['agnostic.build.dir'] = project.build.directory.replace(File.separator, '/');
|
|
||||||
println("Initializing Maven property 'agnostic.build.dir' to: " + project.properties['agnostic.build.dir']);
|
|
||||||
</source>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- Run Unit Testing! This plugin just kicks off the tests (when enabled). -->
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<systemPropertyVariables>
|
|
||||||
<!-- Specify the dspace.dir to use for test environment -->
|
|
||||||
<!-- This system property is loaded by AbstractDSpaceTest to initialize the test environment -->
|
|
||||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
|
||||||
<!-- Turn off any DSpace logging -->
|
|
||||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
|
||||||
</systemPropertyVariables>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
|
||||||
<artifactId>xml-maven-plugin</artifactId>
|
|
||||||
<version>1.0.1</version>
|
|
||||||
<executions>
|
|
||||||
<execution>
|
|
||||||
<id>validate-ALL-xml-and-xsl</id>
|
|
||||||
<phase>process-test-resources</phase>
|
|
||||||
<goals>
|
|
||||||
<goal>validate</goal>
|
|
||||||
</goals>
|
|
||||||
</execution>
|
|
||||||
</executions>
|
|
||||||
<configuration>
|
|
||||||
<validationSets>
|
|
||||||
<!-- validate ALL XML and XSL config files in the testing folder -->
|
|
||||||
<validationSet>
|
|
||||||
<dir>${agnostic.build.dir}/testing</dir>
|
|
||||||
<includes>
|
|
||||||
<include>**/*.xml</include>
|
|
||||||
<include>**/*.xsl</include>
|
|
||||||
<include>**/*.xconf</include>
|
|
||||||
</includes>
|
|
||||||
</validationSet>
|
|
||||||
<!-- validate ALL XML and XSL files throughout the project -->
|
|
||||||
<validationSet>
|
|
||||||
<dir>${root.basedir}</dir>
|
|
||||||
<includes>
|
|
||||||
<include>**/*.xml</include>
|
|
||||||
<include>**/*.xsl</include>
|
|
||||||
<include>**/*.xmap</include>
|
|
||||||
</includes>
|
|
||||||
</validationSet>
|
|
||||||
</validationSets>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Run Integration Testing! This plugin just kicks off the tests (when enabled). -->
|
|
||||||
<plugin>
|
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<systemPropertyVariables>
|
|
||||||
<!-- Specify the dspace.dir to use for test environment -->
|
|
||||||
<dspace.dir>${agnostic.build.dir}/testing/dspace/</dspace.dir>
|
|
||||||
<!-- Turn off any DSpace logging -->
|
|
||||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
|
||||||
</systemPropertyVariables>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
</profile>
|
|
||||||
</profiles>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-core</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.jboss.logging</groupId>
|
|
||||||
<artifactId>jboss-logging</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-ehcache</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-validator-cdi</artifactId>
|
|
||||||
<version>${hibernate-validator.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-orm</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.glassfish</groupId>
|
|
||||||
<artifactId>javax.el</artifactId>
|
|
||||||
<version>3.0.1-b10</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>handle</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>jargon</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>mets</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace.dependencies</groupId>
|
|
||||||
<artifactId>dspace-tm-extractors</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.jena</groupId>
|
|
||||||
<artifactId>apache-jena-libs</artifactId>
|
|
||||||
<type>pom</type>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-cli</groupId>
|
|
||||||
<artifactId>commons-cli</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-codec</groupId>
|
|
||||||
<artifactId>commons-codec</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-collections</groupId>
|
|
||||||
<artifactId>commons-collections</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-collections4</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-dbcp2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-fileupload</groupId>
|
|
||||||
<artifactId>commons-fileupload</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-io</groupId>
|
|
||||||
<artifactId>commons-io</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-lang</groupId>
|
|
||||||
<artifactId>commons-lang</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-pool2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-validator</groupId>
|
|
||||||
<artifactId>commons-validator</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.mail</groupId>
|
|
||||||
<artifactId>mail</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
<artifactId>servlet-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>jaxen</groupId>
|
|
||||||
<artifactId>jaxen</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>xom</artifactId>
|
|
||||||
<groupId>xom</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jdom</groupId>
|
|
||||||
<artifactId>jdom</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>log4j</groupId>
|
|
||||||
<artifactId>log4j</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>oro</groupId>
|
|
||||||
<artifactId>oro</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.pdfbox</groupId>
|
|
||||||
<artifactId>pdfbox</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<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>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-scratchpad</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>rome</groupId>
|
|
||||||
<artifactId>rome</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>rome</groupId>
|
|
||||||
<artifactId>opensearch</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>xalan</groupId>
|
|
||||||
<artifactId>xalan</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>xerces</groupId>
|
|
||||||
<artifactId>xercesImpl</artifactId>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>xml-apis</groupId>
|
|
||||||
<artifactId>xml-apis</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>xml-apis</groupId>
|
|
||||||
<artifactId>xml-apis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.activation</groupId>
|
|
||||||
<artifactId>activation</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.ibm.icu</groupId>
|
|
||||||
<artifactId>icu4j</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>oclc-harvester2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.dspace</groupId>
|
|
||||||
<artifactId>dspace-services</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency> <!-- Keep jmockit before junit -->
|
|
||||||
<groupId>org.jmockit</groupId>
|
|
||||||
<artifactId>jmockit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hamcrest</groupId>
|
|
||||||
<artifactId>hamcrest-core</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.rometools</groupId>
|
|
||||||
<artifactId>rome-modules</artifactId>
|
|
||||||
<version>1.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.ekt.bte</groupId>
|
|
||||||
<artifactId>bte-core</artifactId>
|
|
||||||
<version>0.9.3.5</version>
|
|
||||||
<exclusions>
|
|
||||||
<!-- A more recent version is retrieved from another dependency -->
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>gr.ekt.bte</groupId>
|
|
||||||
<artifactId>bte-io</artifactId>
|
|
||||||
<version>0.9.3.5</version>
|
|
||||||
<exclusions>
|
|
||||||
<!-- A more recent version is retrieved from another dependency -->
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<!-- A more recent version is retrieved from another dependency -->
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.mockito</groupId>
|
|
||||||
<artifactId>mockito-core</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
|
||||||
<artifactId>httpcore</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.httpcomponents</groupId>
|
|
||||||
<artifactId>httpclient</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.solr</groupId>
|
|
||||||
<artifactId>solr-solrj</artifactId>
|
|
||||||
<version>${solr.version}</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>jcl-over-slf4j</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-configuration</groupId>
|
|
||||||
<artifactId>commons-configuration</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.maxmind.geoip2</groupId>
|
|
||||||
<artifactId>geoip2</artifactId>
|
|
||||||
<version>2.11.0</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.ant</groupId>
|
|
||||||
<artifactId>ant</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>dnsjava</groupId>
|
|
||||||
<artifactId>dnsjava</artifactId>
|
|
||||||
<version>2.1.7</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.lucene</groupId>
|
|
||||||
<artifactId>lucene-core</artifactId>
|
|
||||||
<version>4.10.4</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.coverity.security</groupId>
|
|
||||||
<artifactId>coverity-escapers</artifactId>
|
|
||||||
<version>1.1.1</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Gson: Java to Json conversion -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.gson</groupId>
|
|
||||||
<artifactId>gson</artifactId>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.guava</groupId>
|
|
||||||
<artifactId>guava</artifactId>
|
|
||||||
<version>19.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.postgresql</groupId>
|
|
||||||
<artifactId>postgresql</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.slf4j</groupId>
|
|
||||||
<artifactId>slf4j-api</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jdbm</groupId>
|
|
||||||
<artifactId>jdbm</artifactId>
|
|
||||||
<version>1.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- For ImageMagick MediaFilters -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.im4java</groupId>
|
|
||||||
<artifactId>im4java</artifactId>
|
|
||||||
<version>1.4.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Flyway DB API (flywaydb.org) is used to manage DB upgrades automatically. -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.flywaydb</groupId>
|
|
||||||
<artifactId>flyway-core</artifactId>
|
|
||||||
<version>4.0.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Google Analytics -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.apis</groupId>
|
|
||||||
<artifactId>google-api-services-analytics</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.api-client</groupId>
|
|
||||||
<artifactId>google-api-client</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.http-client</groupId>
|
|
||||||
<artifactId>google-http-client</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.http-client</groupId>
|
|
||||||
<artifactId>google-http-client-jackson2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.oauth-client</groupId>
|
|
||||||
<artifactId>google-oauth-client</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<!-- FindBugs -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
|
||||||
<artifactId>jsr305</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
|
||||||
<artifactId>annotations</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>joda-time</groupId>
|
|
||||||
<artifactId>joda-time</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>javax.inject</groupId>
|
|
||||||
<artifactId>javax.inject</artifactId>
|
|
||||||
<version>1</version>
|
|
||||||
<type>jar</type>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.ws.commons.axiom</groupId>
|
|
||||||
<artifactId>axiom-impl</artifactId>
|
|
||||||
<!-- NOTE: SWORDv2 needs 1.2.14, required by Abdera: https://abdera.apache.org/ -->
|
|
||||||
<version>1.2.14</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.ws.commons.axiom</groupId>
|
|
||||||
<artifactId>axiom-api</artifactId>
|
|
||||||
<!-- NOTE: SWORDv2 needs 1.2.14, required by Abdera: https://abdera.apache.org/ -->
|
|
||||||
<version>1.2.14</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.glassfish.jersey.core</groupId>
|
|
||||||
<artifactId>jersey-client</artifactId>
|
|
||||||
<version>${jersey.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!-- S3 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.amazonaws</groupId>
|
|
||||||
<artifactId>aws-java-sdk-s3</artifactId>
|
|
||||||
<version>1.10.50</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>joda-time</groupId>
|
|
||||||
<artifactId>joda-time</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
<!-- S3 also wanted jackson... -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-core</artifactId>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
|
||||||
<artifactId>jackson-databind</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
||||||
@@ -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>
|
|
||||||
* <html>
|
|
||||||
* ...
|
|
||||||
* <body>
|
|
||||||
* <p>some text here. <div>more text</div></p>
|
|
||||||
* Some more text
|
|
||||||
* </body>
|
|
||||||
* </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 .*=<defaultmypassword> at the end
|
|
||||||
*/
|
|
||||||
public static final String PASSWORD_MAP_FILE = "passwordsFile";
|
|
||||||
}
|
|
||||||
@@ -1,271 +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.administer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
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.PosixParser;
|
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.CommunityService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.handle.service.HandleService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A command-line tool for setting/removing community/sub-community
|
|
||||||
* relationships. Takes community DB Id or handle arguments as inputs.
|
|
||||||
*
|
|
||||||
* @author rrodgers
|
|
||||||
* @version $Revision$
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CommunityFiliator {
|
|
||||||
|
|
||||||
protected CommunityService communityService;
|
|
||||||
protected HandleService handleService;
|
|
||||||
|
|
||||||
public CommunityFiliator() {
|
|
||||||
communityService = ContentServiceFactory.getInstance().getCommunityService();
|
|
||||||
handleService = HandleServiceFactory.getInstance().getHandleService();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("s", "set", false, "set a parent/child relationship");
|
|
||||||
options.addOption("r", "remove", false,
|
|
||||||
"remove a parent/child relationship");
|
|
||||||
options.addOption("p", "parent", true,
|
|
||||||
"parent community (handle or database ID)");
|
|
||||||
options.addOption("c", "child", true,
|
|
||||||
"child community (handle or databaseID)");
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
String command = null; // set or remove
|
|
||||||
String parentID = null;
|
|
||||||
String childID = null;
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("CommunityFiliator\n", options);
|
|
||||||
System.out
|
|
||||||
.println("\nestablish a relationship: CommunityFiliator -s -p parentID -c childID");
|
|
||||||
System.out
|
|
||||||
.println("remove a relationship: CommunityFiliator -r -p parentID -c childID");
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('s')) {
|
|
||||||
command = "set";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('r')) {
|
|
||||||
command = "remove";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('p')) { // parent
|
|
||||||
parentID = line.getOptionValue('p');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('c')) { // child
|
|
||||||
childID = line.getOptionValue('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
// now validate
|
|
||||||
// must have a command set
|
|
||||||
if (command == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - must run with either set or remove (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("set".equals(command) || "remove".equals(command)) {
|
|
||||||
if (parentID == null) {
|
|
||||||
System.out.println("Error - a parentID must be specified (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (childID == null) {
|
|
||||||
System.out.println("Error - a childID must be specified (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CommunityFiliator filiator = new CommunityFiliator();
|
|
||||||
Context c = new Context();
|
|
||||||
|
|
||||||
// we are superuser!
|
|
||||||
c.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// validate and resolve the parent and child IDs into commmunities
|
|
||||||
Community parent = filiator.resolveCommunity(c, parentID);
|
|
||||||
Community child = filiator.resolveCommunity(c, childID);
|
|
||||||
|
|
||||||
if (parent == null) {
|
|
||||||
System.out.println("Error, parent community cannot be found: "
|
|
||||||
+ parentID);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child == null) {
|
|
||||||
System.out.println("Error, child community cannot be found: "
|
|
||||||
+ childID);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("set".equals(command)) {
|
|
||||||
filiator.filiate(c, parent, child);
|
|
||||||
} else {
|
|
||||||
filiator.defiliate(c, parent, child);
|
|
||||||
}
|
|
||||||
} catch (SQLException sqlE) {
|
|
||||||
System.out.println("Error - SQL exception: " + sqlE.toString());
|
|
||||||
} catch (AuthorizeException authE) {
|
|
||||||
System.out.println("Error - Authorize exception: "
|
|
||||||
+ authE.toString());
|
|
||||||
} catch (IOException ioE) {
|
|
||||||
System.out.println("Error - IO exception: " + ioE.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param c context
|
|
||||||
* @param parent parent Community
|
|
||||||
* @param child child community
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorize error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
public void filiate(Context c, Community parent, Community child)
|
|
||||||
throws SQLException, AuthorizeException, IOException {
|
|
||||||
// check that a valid filiation would be established
|
|
||||||
// first test - proposed child must currently be an orphan (i.e.
|
|
||||||
// top-level)
|
|
||||||
Community childDad = CollectionUtils.isNotEmpty(child.getParentCommunities()) ? child.getParentCommunities()
|
|
||||||
.iterator().next() : null;
|
|
||||||
|
|
||||||
if (childDad != null) {
|
|
||||||
System.out.println("Error, child community: " + child.getID()
|
|
||||||
+ " already a child of: " + childDad.getID());
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// second test - circularity: parent's parents can't include proposed
|
|
||||||
// child
|
|
||||||
List<Community> parentDads = parent.getParentCommunities();
|
|
||||||
|
|
||||||
for (int i = 0; i < parentDads.size(); i++) {
|
|
||||||
if (parentDads.get(i).getID().equals(child.getID())) {
|
|
||||||
System.out
|
|
||||||
.println("Error, circular parentage - child is parent of parent");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// everthing's OK
|
|
||||||
communityService.addSubcommunity(c, parent, child);
|
|
||||||
|
|
||||||
// complete the pending transaction
|
|
||||||
c.complete();
|
|
||||||
System.out.println("Filiation complete. Community: '" + parent.getID()
|
|
||||||
+ "' is parent of community: '" + child.getID() + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param c context
|
|
||||||
* @param parent parent Community
|
|
||||||
* @param child child community
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorize error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
public void defiliate(Context c, Community parent, Community child)
|
|
||||||
throws SQLException, AuthorizeException, IOException {
|
|
||||||
// verify that child is indeed a child of parent
|
|
||||||
List<Community> parentKids = parent.getSubcommunities();
|
|
||||||
boolean isChild = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < parentKids.size(); i++) {
|
|
||||||
if (parentKids.get(i).getID().equals(child.getID())) {
|
|
||||||
isChild = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isChild) {
|
|
||||||
System.out
|
|
||||||
.println("Error, child community not a child of parent community");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// OK remove the mappings - but leave the community, which will become
|
|
||||||
// top-level
|
|
||||||
child.getParentCommunities().remove(parent);
|
|
||||||
parent.getSubcommunities().remove(child);
|
|
||||||
communityService.update(c, child);
|
|
||||||
communityService.update(c, parent);
|
|
||||||
|
|
||||||
// complete the pending transaction
|
|
||||||
c.complete();
|
|
||||||
System.out.println("Defiliation complete. Community: '" + child.getID()
|
|
||||||
+ "' is no longer a child of community: '" + parent.getID()
|
|
||||||
+ "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a community by ID
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param communityID community ID
|
|
||||||
* @return Community object
|
|
||||||
* @throws SQLException if database error
|
|
||||||
*/
|
|
||||||
protected Community resolveCommunity(Context c, String communityID)
|
|
||||||
throws SQLException {
|
|
||||||
Community community = null;
|
|
||||||
|
|
||||||
if (communityID.indexOf('/') != -1) {
|
|
||||||
// has a / must be a handle
|
|
||||||
community = (Community) handleService.resolveToObject(c,
|
|
||||||
communityID);
|
|
||||||
|
|
||||||
// ensure it's a community
|
|
||||||
if ((community == null)
|
|
||||||
|| (community.getType() != Constants.COMMUNITY)) {
|
|
||||||
community = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
community = communityService.find(c, UUID.fromString(communityID));
|
|
||||||
}
|
|
||||||
|
|
||||||
return community;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,253 +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.administer;
|
|
||||||
|
|
||||||
import java.io.Console;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.I18nUtil;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.dspace.eperson.Group;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.EPersonService;
|
|
||||||
import org.dspace.eperson.service.GroupService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A command-line tool for creating an initial administrator for setting up a
|
|
||||||
* DSpace site. Prompts for an e-mail address, last name, first name and
|
|
||||||
* password from standard input. An administrator group is then created and the
|
|
||||||
* data passed in used to create an e-person in that group.
|
|
||||||
* <P>
|
|
||||||
* Alternatively, it can be used to take the email, first name, last name and
|
|
||||||
* desired password as arguments thus:
|
|
||||||
*
|
|
||||||
* CreateAdministrator -e [email] -f [first name] -l [last name] -p [password]
|
|
||||||
*
|
|
||||||
* This is particularly convenient for automated deploy scripts that require an
|
|
||||||
* initial administrator, for example, before deployment can be completed
|
|
||||||
*
|
|
||||||
* @author Robert Tansley
|
|
||||||
* @author Richard Jones
|
|
||||||
* @version $Revision$
|
|
||||||
*/
|
|
||||||
public final class CreateAdministrator {
|
|
||||||
/**
|
|
||||||
* DSpace Context object
|
|
||||||
*/
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
protected EPersonService ePersonService;
|
|
||||||
protected GroupService groupService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For invoking via the command line. If called with no command line arguments,
|
|
||||||
* it will negotiate with the user for the administrator details
|
|
||||||
*
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv)
|
|
||||||
throws Exception {
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
CreateAdministrator ca = new CreateAdministrator();
|
|
||||||
|
|
||||||
options.addOption("e", "email", true, "administrator email address");
|
|
||||||
options.addOption("f", "first", true, "administrator first name");
|
|
||||||
options.addOption("l", "last", true, "administrator last name");
|
|
||||||
options.addOption("c", "language", true, "administrator language");
|
|
||||||
options.addOption("p", "password", true, "administrator password");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
if (line.hasOption("e") && line.hasOption("f") && line.hasOption("l") &&
|
|
||||||
line.hasOption("c") && line.hasOption("p")) {
|
|
||||||
ca.createAdministrator(line.getOptionValue("e"),
|
|
||||||
line.getOptionValue("f"), line.getOptionValue("l"),
|
|
||||||
line.getOptionValue("c"), line.getOptionValue("p"));
|
|
||||||
} else {
|
|
||||||
ca.negotiateAdministratorDetails();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constructor, which just creates and object with a ready context
|
|
||||||
*
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
protected CreateAdministrator()
|
|
||||||
throws Exception {
|
|
||||||
context = new Context();
|
|
||||||
groupService = EPersonServiceFactory.getInstance().getGroupService();
|
|
||||||
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method which will negotiate with the user via the command line to
|
|
||||||
* obtain the administrator's details
|
|
||||||
*
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
protected void negotiateAdministratorDetails()
|
|
||||||
throws Exception {
|
|
||||||
Console console = System.console();
|
|
||||||
|
|
||||||
System.out.println("Creating an initial administrator account");
|
|
||||||
|
|
||||||
boolean dataOK = false;
|
|
||||||
|
|
||||||
String email = null;
|
|
||||||
String firstName = null;
|
|
||||||
String lastName = null;
|
|
||||||
char[] password1 = null;
|
|
||||||
char[] password2 = null;
|
|
||||||
String language = I18nUtil.DEFAULTLOCALE.getLanguage();
|
|
||||||
|
|
||||||
while (!dataOK) {
|
|
||||||
System.out.print("E-mail address: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
email = console.readLine();
|
|
||||||
if (!StringUtils.isBlank(email)) {
|
|
||||||
email = email.trim();
|
|
||||||
} else {
|
|
||||||
System.out.println("Please provide an email address.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.print("First name: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
firstName = console.readLine();
|
|
||||||
|
|
||||||
if (firstName != null) {
|
|
||||||
firstName = firstName.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.print("Last name: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
lastName = console.readLine();
|
|
||||||
|
|
||||||
if (lastName != null) {
|
|
||||||
lastName = lastName.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ConfigurationManager.getProperty("webui.supported.locales") != null) {
|
|
||||||
System.out.println("Select one of the following languages: " + ConfigurationManager
|
|
||||||
.getProperty("webui.supported.locales"));
|
|
||||||
System.out.print("Language: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
language = console.readLine();
|
|
||||||
|
|
||||||
if (language != null) {
|
|
||||||
language = language.trim();
|
|
||||||
language = I18nUtil.getSupportedLocale(new Locale(language)).getLanguage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Password will not display on screen.");
|
|
||||||
System.out.print("Password: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
password1 = console.readPassword();
|
|
||||||
|
|
||||||
System.out.print("Again to confirm: ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
password2 = console.readPassword();
|
|
||||||
|
|
||||||
//TODO real password validation
|
|
||||||
if (password1.length > 1 && Arrays.equals(password1, password2)) {
|
|
||||||
// password OK
|
|
||||||
System.out.print("Is the above data correct? (y or n): ");
|
|
||||||
System.out.flush();
|
|
||||||
|
|
||||||
String s = console.readLine();
|
|
||||||
|
|
||||||
if (s != null) {
|
|
||||||
s = s.trim();
|
|
||||||
if (s.toLowerCase().startsWith("y")) {
|
|
||||||
dataOK = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
System.out.println("Passwords don't match");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we make it to here, we are ready to create an administrator
|
|
||||||
createAdministrator(email, firstName, lastName, language, String.valueOf(password1));
|
|
||||||
|
|
||||||
//Cleaning arrays that held password
|
|
||||||
Arrays.fill(password1, ' ');
|
|
||||||
Arrays.fill(password2, ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the administrator with the given details. If the user
|
|
||||||
* already exists then they are simply upped to administrator status
|
|
||||||
*
|
|
||||||
* @param email the email for the user
|
|
||||||
* @param first user's first name
|
|
||||||
* @param last user's last name
|
|
||||||
* @param language preferred language
|
|
||||||
* @param pw desired password
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
protected void createAdministrator(String email, String first, String last,
|
|
||||||
String language, String pw)
|
|
||||||
throws Exception {
|
|
||||||
// Of course we aren't an administrator yet so we need to
|
|
||||||
// circumvent authorisation
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
// Find administrator group
|
|
||||||
Group admins = groupService.findByName(context, Group.ADMIN);
|
|
||||||
|
|
||||||
if (admins == null) {
|
|
||||||
throw new IllegalStateException("Error, no admin group (group 1) found");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the administrator e-person
|
|
||||||
EPerson eperson = ePersonService.findByEmail(context, email);
|
|
||||||
|
|
||||||
// check if the email belongs to a registered user,
|
|
||||||
// if not create a new user with this email
|
|
||||||
if (eperson == null) {
|
|
||||||
eperson = ePersonService.create(context);
|
|
||||||
eperson.setEmail(email);
|
|
||||||
eperson.setCanLogIn(true);
|
|
||||||
eperson.setRequireCertificate(false);
|
|
||||||
eperson.setSelfRegistered(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
eperson.setLastName(context, last);
|
|
||||||
eperson.setFirstName(context, first);
|
|
||||||
eperson.setLanguage(context, language);
|
|
||||||
ePersonService.setPassword(eperson, pw);
|
|
||||||
ePersonService.update(context, eperson);
|
|
||||||
|
|
||||||
groupService.addMember(context, admins, eperson);
|
|
||||||
groupService.update(context, admins);
|
|
||||||
|
|
||||||
context.complete();
|
|
||||||
|
|
||||||
System.out.println("Administrator account created");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,328 +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.administer;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.xml.serialize.Method;
|
|
||||||
import org.apache.xml.serialize.OutputFormat;
|
|
||||||
import org.apache.xml.serialize.XMLSerializer;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.MetadataFieldService;
|
|
||||||
import org.dspace.content.service.MetadataSchemaService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Graham Triggs
|
|
||||||
*
|
|
||||||
* This class creates an xml document as passed in the arguments and
|
|
||||||
* from the metadata schemas for the repository.
|
|
||||||
*
|
|
||||||
* The form of the XML is as follows
|
|
||||||
* {@code
|
|
||||||
* <metadata-schemas>
|
|
||||||
* <schema>
|
|
||||||
* <name>dc</name>
|
|
||||||
* <namespace>http://dublincore.org/documents/dcmi-terms/</namespace>
|
|
||||||
* </schema>
|
|
||||||
* </metadata-schemas>
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
public class MetadataExporter {
|
|
||||||
|
|
||||||
protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
|
|
||||||
.getMetadataSchemaService();
|
|
||||||
protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance()
|
|
||||||
.getMetadataFieldService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private MetadataExporter() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args commandline arguments
|
|
||||||
* @throws ParseException if parser error
|
|
||||||
* @throws SAXException if XML parse error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
*/
|
|
||||||
public static void main(String[] args)
|
|
||||||
throws ParseException, SQLException, IOException, SAXException, RegistryExportException {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
Options options = new Options();
|
|
||||||
options.addOption("f", "file", true, "output xml file for registry");
|
|
||||||
options.addOption("s", "schema", true, "the name of the schema to export");
|
|
||||||
CommandLine line = parser.parse(options, args);
|
|
||||||
|
|
||||||
String file = null;
|
|
||||||
String schema = null;
|
|
||||||
|
|
||||||
if (line.hasOption('f')) {
|
|
||||||
file = line.getOptionValue('f');
|
|
||||||
} else {
|
|
||||||
usage();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('s')) {
|
|
||||||
schema = line.getOptionValue('s');
|
|
||||||
}
|
|
||||||
|
|
||||||
saveRegistry(file, schema);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save a registry to a filepath
|
|
||||||
*
|
|
||||||
* @param file filepath
|
|
||||||
* @param schema schema definition to save
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SAXException if XML error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
*/
|
|
||||||
public static void saveRegistry(String file, String schema)
|
|
||||||
throws SQLException, IOException, SAXException, RegistryExportException {
|
|
||||||
// create a context
|
|
||||||
Context context = new Context();
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
OutputFormat xmlFormat = new OutputFormat(Method.XML, "UTF-8", true);
|
|
||||||
xmlFormat.setLineWidth(120);
|
|
||||||
xmlFormat.setIndent(4);
|
|
||||||
|
|
||||||
XMLSerializer xmlSerializer = new XMLSerializer(new BufferedWriter(new FileWriter(file)), xmlFormat);
|
|
||||||
// XMLSerializer xmlSerializer = new XMLSerializer(System.out, xmlFormat);
|
|
||||||
xmlSerializer.startDocument();
|
|
||||||
xmlSerializer.startElement("dspace-dc-types", null);
|
|
||||||
|
|
||||||
// Save the schema definition(s)
|
|
||||||
saveSchema(context, xmlSerializer, schema);
|
|
||||||
|
|
||||||
List<MetadataField> mdFields = null;
|
|
||||||
|
|
||||||
// If a single schema has been specified
|
|
||||||
if (schema != null && !"".equals(schema)) {
|
|
||||||
// Get the id of that schema
|
|
||||||
MetadataSchema mdSchema = metadataSchemaService.find(context, schema);
|
|
||||||
if (mdSchema == null) {
|
|
||||||
throw new RegistryExportException("no schema to export");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the metadata fields only for the specified schema
|
|
||||||
mdFields = metadataFieldService.findAllInSchema(context, mdSchema);
|
|
||||||
} else {
|
|
||||||
// Get the metadata fields for all the schemas
|
|
||||||
mdFields = metadataFieldService.findAll(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the metadata fields
|
|
||||||
for (MetadataField mdField : mdFields) {
|
|
||||||
saveType(context, xmlSerializer, mdField);
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlSerializer.endElement("dspace-dc-types");
|
|
||||||
xmlSerializer.endDocument();
|
|
||||||
|
|
||||||
// abort the context, as we shouldn't have changed it!!
|
|
||||||
context.abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize the schema registry. If the parameter 'schema' is null or empty, save all schemas
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param xmlSerializer XML serializer
|
|
||||||
* @param schema schema (may be null to save all)
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws SAXException if XML error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
*/
|
|
||||||
public static void saveSchema(Context context, XMLSerializer xmlSerializer, String schema)
|
|
||||||
throws SQLException, SAXException, RegistryExportException {
|
|
||||||
if (schema != null && !"".equals(schema)) {
|
|
||||||
// Find a single named schema
|
|
||||||
MetadataSchema mdSchema = metadataSchemaService.find(context, schema);
|
|
||||||
|
|
||||||
saveSchema(xmlSerializer, mdSchema);
|
|
||||||
} else {
|
|
||||||
// Find all schemas
|
|
||||||
List<MetadataSchema> mdSchemas = metadataSchemaService.findAll(context);
|
|
||||||
|
|
||||||
for (MetadataSchema mdSchema : mdSchemas) {
|
|
||||||
saveSchema(xmlSerializer, mdSchema);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize a single schema (namespace) registry entry
|
|
||||||
*
|
|
||||||
* @param xmlSerializer XML serializer
|
|
||||||
* @param mdSchema DSpace metadata schema
|
|
||||||
* @throws SAXException if XML error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
*/
|
|
||||||
private static void saveSchema(XMLSerializer xmlSerializer, MetadataSchema mdSchema)
|
|
||||||
throws SAXException, RegistryExportException {
|
|
||||||
// If we haven't got a schema, it's an error
|
|
||||||
if (mdSchema == null) {
|
|
||||||
throw new RegistryExportException("no schema to export");
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = mdSchema.getName();
|
|
||||||
String namespace = mdSchema.getNamespace();
|
|
||||||
|
|
||||||
if (name == null || "".equals(name)) {
|
|
||||||
System.out.println("name is null, skipping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namespace == null || "".equals(namespace)) {
|
|
||||||
System.out.println("namespace is null, skipping");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the parent tag
|
|
||||||
xmlSerializer.startElement("dc-schema", null);
|
|
||||||
|
|
||||||
// Output the schema name
|
|
||||||
xmlSerializer.startElement("name", null);
|
|
||||||
xmlSerializer.characters(name.toCharArray(), 0, name.length());
|
|
||||||
xmlSerializer.endElement("name");
|
|
||||||
|
|
||||||
// Output the schema namespace
|
|
||||||
xmlSerializer.startElement("namespace", null);
|
|
||||||
xmlSerializer.characters(namespace.toCharArray(), 0, namespace.length());
|
|
||||||
xmlSerializer.endElement("namespace");
|
|
||||||
|
|
||||||
xmlSerializer.endElement("dc-schema");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Serialize a single metadata field registry entry to xml
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param xmlSerializer xml serializer
|
|
||||||
* @param mdField DSpace metadata field
|
|
||||||
* @throws SAXException if XML error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
private static void saveType(Context context, XMLSerializer xmlSerializer, MetadataField mdField)
|
|
||||||
throws SAXException, RegistryExportException, SQLException, IOException {
|
|
||||||
// If we haven't been given a field, it's an error
|
|
||||||
if (mdField == null) {
|
|
||||||
throw new RegistryExportException("no field to export");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the data from the metadata field
|
|
||||||
String schemaName = getSchemaName(context, mdField);
|
|
||||||
String element = mdField.getElement();
|
|
||||||
String qualifier = mdField.getQualifier();
|
|
||||||
String scopeNote = mdField.getScopeNote();
|
|
||||||
|
|
||||||
// We must have a schema and element
|
|
||||||
if (schemaName == null || element == null) {
|
|
||||||
throw new RegistryExportException("incomplete field information");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the parent tag
|
|
||||||
xmlSerializer.startElement("dc-type", null);
|
|
||||||
|
|
||||||
// Output the schema name
|
|
||||||
xmlSerializer.startElement("schema", null);
|
|
||||||
xmlSerializer.characters(schemaName.toCharArray(), 0, schemaName.length());
|
|
||||||
xmlSerializer.endElement("schema");
|
|
||||||
|
|
||||||
// Output the element
|
|
||||||
xmlSerializer.startElement("element", null);
|
|
||||||
xmlSerializer.characters(element.toCharArray(), 0, element.length());
|
|
||||||
xmlSerializer.endElement("element");
|
|
||||||
|
|
||||||
// Output the qualifier, if present
|
|
||||||
if (qualifier != null) {
|
|
||||||
xmlSerializer.startElement("qualifier", null);
|
|
||||||
xmlSerializer.characters(qualifier.toCharArray(), 0, qualifier.length());
|
|
||||||
xmlSerializer.endElement("qualifier");
|
|
||||||
} else {
|
|
||||||
xmlSerializer.comment("unqualified");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output the scope note, if present
|
|
||||||
if (scopeNote != null) {
|
|
||||||
xmlSerializer.startElement("scope_note", null);
|
|
||||||
xmlSerializer.characters(scopeNote.toCharArray(), 0, scopeNote.length());
|
|
||||||
xmlSerializer.endElement("scope_note");
|
|
||||||
} else {
|
|
||||||
xmlSerializer.comment("no scope note");
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlSerializer.endElement("dc-type");
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<Integer, String> schemaMap = new HashMap<Integer, String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper method to retrieve a schema name for the field.
|
|
||||||
* Caches the name after looking up the id.
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param mdField DSpace metadata field
|
|
||||||
* @return name of schema
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws RegistryExportException if export error
|
|
||||||
*/
|
|
||||||
private static String getSchemaName(Context context, MetadataField mdField)
|
|
||||||
throws SQLException, RegistryExportException {
|
|
||||||
// Get name from cache
|
|
||||||
String name = schemaMap.get(mdField.getMetadataSchema().getID());
|
|
||||||
|
|
||||||
if (name == null) {
|
|
||||||
// Name not retrieved before, so get the schema now
|
|
||||||
MetadataSchema mdSchema = metadataSchemaService.find(context, mdField.getMetadataSchema().getID());
|
|
||||||
if (mdSchema != null) {
|
|
||||||
name = mdSchema.getName();
|
|
||||||
schemaMap.put(mdSchema.getID(), name);
|
|
||||||
} else {
|
|
||||||
// Can't find the schema
|
|
||||||
throw new RegistryExportException("Can't get schema name for field");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print the usage message to stdout
|
|
||||||
*/
|
|
||||||
public static void usage() {
|
|
||||||
String usage = "Use this class with the following options:\n" +
|
|
||||||
" -f <xml output file> : specify the output file for the schemas\n" +
|
|
||||||
" -s <schema> : name of the schema to export\n";
|
|
||||||
System.out.println(usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,287 +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.administer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.xpath.XPathAPI;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.NonUniqueMetadataException;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.MetadataFieldService;
|
|
||||||
import org.dspace.content.service.MetadataSchemaService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Richard Jones
|
|
||||||
*
|
|
||||||
* This class takes an xml document as passed in the arguments and
|
|
||||||
* uses it to create metadata elements in the Metadata Registry if
|
|
||||||
* they do not already exist
|
|
||||||
*
|
|
||||||
* The format of the XML file is as follows:
|
|
||||||
*
|
|
||||||
* {@code
|
|
||||||
* <dspace-dc-types>
|
|
||||||
* <dc-type>
|
|
||||||
* <schema>icadmin</schema>
|
|
||||||
* <element>status</element>
|
|
||||||
* <qualifier>dateset</qualifier>
|
|
||||||
* <scope_note>the workflow status of an item</scope_note>
|
|
||||||
* </dc-type>
|
|
||||||
*
|
|
||||||
* [....]
|
|
||||||
*
|
|
||||||
* </dspace-dc-types>
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
public class MetadataImporter {
|
|
||||||
protected static MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
|
|
||||||
.getMetadataSchemaService();
|
|
||||||
protected static MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance()
|
|
||||||
.getMetadataFieldService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* logging category
|
|
||||||
*/
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MetadataImporter.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private MetadataImporter() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* main method for reading user input from the command line
|
|
||||||
*
|
|
||||||
* @param args the command line arguments given
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws ParserConfigurationException if config error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws SAXException if parser error
|
|
||||||
* @throws NonUniqueMetadataException if duplicate metadata
|
|
||||||
* @throws RegistryImportException if import fails
|
|
||||||
**/
|
|
||||||
public static void main(String[] args)
|
|
||||||
throws ParseException, SQLException, IOException, TransformerException,
|
|
||||||
ParserConfigurationException, AuthorizeException, SAXException,
|
|
||||||
NonUniqueMetadataException, RegistryImportException {
|
|
||||||
boolean forceUpdate = false;
|
|
||||||
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
Options options = new Options();
|
|
||||||
options.addOption("f", "file", true, "source xml file for DC fields");
|
|
||||||
options.addOption("u", "update", false, "update an existing schema");
|
|
||||||
CommandLine line = parser.parse(options, args);
|
|
||||||
|
|
||||||
String file = null;
|
|
||||||
if (line.hasOption('f')) {
|
|
||||||
file = line.getOptionValue('f');
|
|
||||||
} else {
|
|
||||||
usage();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
forceUpdate = line.hasOption('u');
|
|
||||||
loadRegistry(file, forceUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the data from the specified file path into the database
|
|
||||||
*
|
|
||||||
* @param file the file path containing the source data
|
|
||||||
* @param forceUpdate whether to force update
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws ParserConfigurationException if config error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws SAXException if parser error
|
|
||||||
* @throws NonUniqueMetadataException if duplicate metadata
|
|
||||||
* @throws RegistryImportException if import fails
|
|
||||||
*/
|
|
||||||
public static void loadRegistry(String file, boolean forceUpdate)
|
|
||||||
throws SQLException, IOException, TransformerException, ParserConfigurationException,
|
|
||||||
AuthorizeException, SAXException, NonUniqueMetadataException, RegistryImportException {
|
|
||||||
Context context = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// create a context
|
|
||||||
context = new Context();
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
// read the XML
|
|
||||||
Document document = RegistryImporter.loadXML(file);
|
|
||||||
|
|
||||||
// Get the nodes corresponding to types
|
|
||||||
NodeList schemaNodes = XPathAPI.selectNodeList(document, "/dspace-dc-types/dc-schema");
|
|
||||||
|
|
||||||
// Add each one as a new format to the registry
|
|
||||||
for (int i = 0; i < schemaNodes.getLength(); i++) {
|
|
||||||
Node n = schemaNodes.item(i);
|
|
||||||
loadSchema(context, n, forceUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the nodes corresponding to types
|
|
||||||
NodeList typeNodes = XPathAPI.selectNodeList(document, "/dspace-dc-types/dc-type");
|
|
||||||
|
|
||||||
// Add each one as a new format to the registry
|
|
||||||
for (int i = 0; i < typeNodes.getLength(); i++) {
|
|
||||||
Node n = typeNodes.item(i);
|
|
||||||
loadType(context, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
context.complete();
|
|
||||||
} finally {
|
|
||||||
// Clean up our context, if it still exists & it was never completed
|
|
||||||
if (context != null && context.isValid()) {
|
|
||||||
context.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a node in the metadata registry XML file. If the
|
|
||||||
* schema already exists, it will not be recreated
|
|
||||||
*
|
|
||||||
* @param context DSpace context object
|
|
||||||
* @param node the node in the DOM tree
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws NonUniqueMetadataException if duplicate metadata
|
|
||||||
* @throws RegistryImportException if import fails
|
|
||||||
*/
|
|
||||||
private static void loadSchema(Context context, Node node, boolean updateExisting)
|
|
||||||
throws SQLException, IOException, TransformerException,
|
|
||||||
AuthorizeException, NonUniqueMetadataException, RegistryImportException {
|
|
||||||
// Get the values
|
|
||||||
String name = RegistryImporter.getElementData(node, "name");
|
|
||||||
String namespace = RegistryImporter.getElementData(node, "namespace");
|
|
||||||
|
|
||||||
if (name == null || "".equals(name)) {
|
|
||||||
throw new RegistryImportException("Name of schema must be supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (namespace == null || "".equals(namespace)) {
|
|
||||||
throw new RegistryImportException("Namespace of schema must be supplied");
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if the schema already exists
|
|
||||||
MetadataSchema s = metadataSchemaService.find(context, name);
|
|
||||||
|
|
||||||
if (s == null) {
|
|
||||||
// Schema does not exist - create
|
|
||||||
log.info("Registering Schema " + name + " (" + namespace + ")");
|
|
||||||
metadataSchemaService.create(context, name, namespace);
|
|
||||||
} else {
|
|
||||||
// Schema exists - if it's the same namespace, allow the type imports to continue
|
|
||||||
if (s.getNamespace().equals(namespace)) {
|
|
||||||
// This schema already exists with this namespace, skipping it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// It's a different namespace - have we been told to update?
|
|
||||||
if (updateExisting) {
|
|
||||||
// Update the existing schema namespace and continue to type import
|
|
||||||
log.info("Updating Schema " + name + ": New namespace " + namespace);
|
|
||||||
s.setNamespace(namespace);
|
|
||||||
metadataSchemaService.update(context, s);
|
|
||||||
} else {
|
|
||||||
throw new RegistryImportException(
|
|
||||||
"Schema " + name + " already registered with different namespace " + namespace + ". Rerun with " +
|
|
||||||
"'update' option enabled if you wish to update this schema.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a node in the metadata registry XML file. The node must
|
|
||||||
* be a "dc-type" node. If the type already exists, then it
|
|
||||||
* will not be reimported
|
|
||||||
*
|
|
||||||
* @param context DSpace context object
|
|
||||||
* @param node the node in the DOM tree
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws NonUniqueMetadataException if duplicate metadata
|
|
||||||
* @throws RegistryImportException if import fails
|
|
||||||
*/
|
|
||||||
private static void loadType(Context context, Node node)
|
|
||||||
throws SQLException, IOException, TransformerException,
|
|
||||||
AuthorizeException, NonUniqueMetadataException, RegistryImportException {
|
|
||||||
// Get the values
|
|
||||||
String schema = RegistryImporter.getElementData(node, "schema");
|
|
||||||
String element = RegistryImporter.getElementData(node, "element");
|
|
||||||
String qualifier = RegistryImporter.getElementData(node, "qualifier");
|
|
||||||
String scopeNote = RegistryImporter.getElementData(node, "scope_note");
|
|
||||||
|
|
||||||
// If the schema is not provided default to DC
|
|
||||||
if (schema == null) {
|
|
||||||
schema = MetadataSchema.DC_SCHEMA;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Find the matching schema object
|
|
||||||
MetadataSchema schemaObj = metadataSchemaService.find(context, schema);
|
|
||||||
|
|
||||||
if (schemaObj == null) {
|
|
||||||
throw new RegistryImportException("Schema '" + schema + "' is not registered and does not exist.");
|
|
||||||
}
|
|
||||||
|
|
||||||
MetadataField mf = metadataFieldService.findByElement(context, schemaObj, element, qualifier);
|
|
||||||
if (mf != null) {
|
|
||||||
// Metadata field already exists, skipping it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actually create this metadata field as it doesn't yet exist
|
|
||||||
String fieldName = schema + "." + element + "." + qualifier;
|
|
||||||
if (qualifier == null) {
|
|
||||||
fieldName = schema + "." + element;
|
|
||||||
}
|
|
||||||
log.info("Registering metadata field " + fieldName);
|
|
||||||
MetadataField field = metadataFieldService.create(context, schemaObj, element, qualifier, scopeNote);
|
|
||||||
metadataFieldService.update(context, field);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print the usage message to stdout
|
|
||||||
*/
|
|
||||||
public static void usage() {
|
|
||||||
String usage = "Use this class with the following option:\n" +
|
|
||||||
" -f <xml source file> : specify which xml source file " +
|
|
||||||
"contains the DC fields to import.\n";
|
|
||||||
System.out.println(usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +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.administer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Graham Triggs
|
|
||||||
*
|
|
||||||
* An exception to report any problems with registry exports
|
|
||||||
*/
|
|
||||||
public class RegistryExportException extends Exception {
|
|
||||||
/**
|
|
||||||
* Create an empty authorize exception
|
|
||||||
*/
|
|
||||||
public RegistryExportException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with only a message
|
|
||||||
*
|
|
||||||
* @param message exception message
|
|
||||||
*/
|
|
||||||
public RegistryExportException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with an inner exception and a message
|
|
||||||
*
|
|
||||||
* @param message exception message
|
|
||||||
* @param e reference to Throwable
|
|
||||||
*/
|
|
||||||
public RegistryExportException(String message, Throwable e) {
|
|
||||||
super(message, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with an inner exception
|
|
||||||
*
|
|
||||||
* @param e reference to Throwable
|
|
||||||
*/
|
|
||||||
public RegistryExportException(Throwable e) {
|
|
||||||
super(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,51 +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.administer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Richard Jones
|
|
||||||
*
|
|
||||||
* An exception to report any problems with registry imports
|
|
||||||
*/
|
|
||||||
public class RegistryImportException extends Exception {
|
|
||||||
/**
|
|
||||||
* Create an empty authorize exception
|
|
||||||
*/
|
|
||||||
public RegistryImportException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with only a message
|
|
||||||
*
|
|
||||||
* @param message error message
|
|
||||||
*/
|
|
||||||
public RegistryImportException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with an inner exception and a message
|
|
||||||
*
|
|
||||||
* @param message error message
|
|
||||||
* @param e throwable
|
|
||||||
*/
|
|
||||||
public RegistryImportException(String message, Throwable e) {
|
|
||||||
super(message, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* create an exception with an inner exception
|
|
||||||
*
|
|
||||||
* @param e throwable
|
|
||||||
*/
|
|
||||||
public RegistryImportException(Throwable e) {
|
|
||||||
super(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,134 +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.administer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
|
|
||||||
import org.apache.xpath.XPathAPI;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Richard Jones
|
|
||||||
*
|
|
||||||
* This class provides the tools that registry importers might need to
|
|
||||||
* use. Basically some utility methods. And actually, although it says
|
|
||||||
* I am the author, really I ripped these methods off from other
|
|
||||||
* classes
|
|
||||||
*/
|
|
||||||
public class RegistryImporter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private RegistryImporter() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load in the XML from file.
|
|
||||||
*
|
|
||||||
* @param filename the filename to load from
|
|
||||||
* @return the DOM representation of the XML file
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws ParserConfigurationException if configuration parse error
|
|
||||||
* @throws SAXException if XML parse error
|
|
||||||
*/
|
|
||||||
public static Document loadXML(String filename)
|
|
||||||
throws IOException, ParserConfigurationException, SAXException {
|
|
||||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
|
||||||
.newDocumentBuilder();
|
|
||||||
|
|
||||||
Document document = builder.parse(new File(filename));
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the CDATA of a particular element. For example, if the XML document
|
|
||||||
* contains:
|
|
||||||
* <P>
|
|
||||||
* <code>
|
|
||||||
* <foo><mimetype>application/pdf</mimetype></foo>
|
|
||||||
* </code>
|
|
||||||
* passing this the <code>foo</code> node and <code>mimetype</code> will
|
|
||||||
* return <code>application/pdf</code>.
|
|
||||||
* </P>
|
|
||||||
* Why this isn't a core part of the XML API I do not know...
|
|
||||||
*
|
|
||||||
* @param parentElement the element, whose child element you want the CDATA from
|
|
||||||
* @param childName the name of the element you want the CDATA from
|
|
||||||
* @return the CDATA as a <code>String</code>
|
|
||||||
* @throws TransformerException if error
|
|
||||||
*/
|
|
||||||
public static String getElementData(Node parentElement, String childName)
|
|
||||||
throws TransformerException {
|
|
||||||
// Grab the child node
|
|
||||||
Node childNode = XPathAPI.selectSingleNode(parentElement, childName);
|
|
||||||
|
|
||||||
if (childNode == null) {
|
|
||||||
// No child node, so no values
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the #text
|
|
||||||
Node dataNode = childNode.getFirstChild();
|
|
||||||
|
|
||||||
if (dataNode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the data
|
|
||||||
String value = dataNode.getNodeValue().trim();
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get repeated CDATA for a particular element. For example, if the XML
|
|
||||||
* document contains:
|
|
||||||
* <P>
|
|
||||||
* <code>
|
|
||||||
* <foo>
|
|
||||||
* <bar>val1</bar>
|
|
||||||
* <bar>val2</bar>
|
|
||||||
* </foo>
|
|
||||||
* </code>
|
|
||||||
* passing this the <code>foo</code> node and <code>bar</code> will
|
|
||||||
* return <code>val1</code> and <code>val2</code>.
|
|
||||||
* </P>
|
|
||||||
* Why this also isn't a core part of the XML API I do not know...
|
|
||||||
*
|
|
||||||
* @param parentElement the element, whose child element you want the CDATA from
|
|
||||||
* @param childName the name of the element you want the CDATA from
|
|
||||||
* @return the CDATA as a <code>String</code>
|
|
||||||
* @throws TransformerException if error
|
|
||||||
*/
|
|
||||||
public static String[] getRepeatedElementData(Node parentElement,
|
|
||||||
String childName) throws TransformerException {
|
|
||||||
// Grab the child node
|
|
||||||
NodeList childNodes = XPathAPI.selectNodeList(parentElement, childName);
|
|
||||||
|
|
||||||
String[] data = new String[childNodes.getLength()];
|
|
||||||
|
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
|
||||||
// Get the #text node
|
|
||||||
Node dataNode = childNodes.item(i).getFirstChild();
|
|
||||||
|
|
||||||
// Get the data
|
|
||||||
data[i] = dataNode.getNodeValue().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,293 +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.administer;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.xpath.XPathAPI;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.BitstreamFormat;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.BitstreamFormatService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.LogManager;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the bitstream format and Dublin Core type registries into the database.
|
|
||||||
* Intended for use as a command-line tool.
|
|
||||||
* <P>
|
|
||||||
* Example usage:
|
|
||||||
* <P>
|
|
||||||
* <code>RegistryLoader -bitstream bitstream-formats.xml</code>
|
|
||||||
* <P>
|
|
||||||
* <code>RegistryLoader -dc dc-types.xml</code>
|
|
||||||
*
|
|
||||||
* @author Robert Tansley
|
|
||||||
* @version $Revision$
|
|
||||||
*/
|
|
||||||
public class RegistryLoader {
|
|
||||||
/**
|
|
||||||
* log4j category
|
|
||||||
*/
|
|
||||||
private static Logger log = Logger.getLogger(RegistryLoader.class);
|
|
||||||
|
|
||||||
protected static BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
|
|
||||||
.getBitstreamFormatService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private RegistryLoader() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For invoking via the command line
|
|
||||||
*
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
String usage = "Usage: " + RegistryLoader.class.getName()
|
|
||||||
+ " (-bitstream | -metadata) registry-file.xml";
|
|
||||||
|
|
||||||
Context context = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
context = new Context();
|
|
||||||
|
|
||||||
// Can't update registries anonymously, so we need to turn off
|
|
||||||
// authorisation
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
// Work out what we're loading
|
|
||||||
if (argv[0].equalsIgnoreCase("-bitstream")) {
|
|
||||||
RegistryLoader.loadBitstreamFormats(context, argv[1]);
|
|
||||||
} else if (argv[0].equalsIgnoreCase("-metadata")) {
|
|
||||||
// Call MetadataImporter, as it handles Metadata schema updates
|
|
||||||
MetadataImporter.loadRegistry(argv[1], true);
|
|
||||||
} else {
|
|
||||||
System.err.println(usage);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Commit changes and close Context
|
|
||||||
context.complete();
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
} catch (ArrayIndexOutOfBoundsException ae) {
|
|
||||||
System.err.println(usage);
|
|
||||||
|
|
||||||
System.exit(1);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.fatal(LogManager.getHeader(context, "error_loading_registries",
|
|
||||||
""), e);
|
|
||||||
|
|
||||||
System.err.println("Error: \n - " + e.getMessage());
|
|
||||||
System.exit(1);
|
|
||||||
} finally {
|
|
||||||
// Clean up our context, if it still exists & it was never completed
|
|
||||||
if (context != null && context.isValid()) {
|
|
||||||
context.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load Bitstream Format metadata
|
|
||||||
*
|
|
||||||
* @param context DSpace context object
|
|
||||||
* @param filename the filename of the XML file to load
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws ParserConfigurationException if config error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws SAXException if parser error
|
|
||||||
*/
|
|
||||||
public static void loadBitstreamFormats(Context context, String filename)
|
|
||||||
throws SQLException, IOException, ParserConfigurationException,
|
|
||||||
SAXException, TransformerException, AuthorizeException {
|
|
||||||
Document document = loadXML(filename);
|
|
||||||
|
|
||||||
// Get the nodes corresponding to formats
|
|
||||||
NodeList typeNodes = XPathAPI.selectNodeList(document,
|
|
||||||
"dspace-bitstream-types/bitstream-type");
|
|
||||||
|
|
||||||
// Add each one as a new format to the registry
|
|
||||||
for (int i = 0; i < typeNodes.getLength(); i++) {
|
|
||||||
Node n = typeNodes.item(i);
|
|
||||||
loadFormat(context, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(LogManager.getHeader(context, "load_bitstream_formats",
|
|
||||||
"number_loaded=" + typeNodes.getLength()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process a node in the bitstream format registry XML file. The node must
|
|
||||||
* be a "bitstream-type" node
|
|
||||||
*
|
|
||||||
* @param context DSpace context object
|
|
||||||
* @param node the node in the DOM tree
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
*/
|
|
||||||
private static void loadFormat(Context context, Node node)
|
|
||||||
throws SQLException, IOException, TransformerException,
|
|
||||||
AuthorizeException {
|
|
||||||
// Get the values
|
|
||||||
String mimeType = getElementData(node, "mimetype");
|
|
||||||
String shortDesc = getElementData(node, "short_description");
|
|
||||||
String desc = getElementData(node, "description");
|
|
||||||
|
|
||||||
String supportLevelString = getElementData(node, "support_level");
|
|
||||||
int supportLevel = Integer.parseInt(supportLevelString);
|
|
||||||
|
|
||||||
String internalString = getElementData(node, "internal");
|
|
||||||
boolean internal = Boolean.valueOf(internalString).booleanValue();
|
|
||||||
|
|
||||||
String[] extensions = getRepeatedElementData(node, "extension");
|
|
||||||
|
|
||||||
// Check if this format already exists in our registry (by mime type)
|
|
||||||
BitstreamFormat exists = bitstreamFormatService.findByMIMEType(context, mimeType);
|
|
||||||
|
|
||||||
// If not found by mimeType, check by short description (since this must also be unique)
|
|
||||||
if (exists == null) {
|
|
||||||
exists = bitstreamFormatService.findByShortDescription(context, shortDesc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If it doesn't exist, create it..otherwise skip it.
|
|
||||||
if (exists == null) {
|
|
||||||
// Create the format object
|
|
||||||
BitstreamFormat format = bitstreamFormatService.create(context);
|
|
||||||
|
|
||||||
// Fill it out with the values
|
|
||||||
format.setMIMEType(mimeType);
|
|
||||||
bitstreamFormatService.setShortDescription(context, format, shortDesc);
|
|
||||||
format.setDescription(desc);
|
|
||||||
format.setSupportLevel(supportLevel);
|
|
||||||
format.setInternal(internal);
|
|
||||||
ArrayList<String> extensionList = new ArrayList<>();
|
|
||||||
extensionList.addAll(Arrays.asList(extensions));
|
|
||||||
format.setExtensions(extensionList);
|
|
||||||
|
|
||||||
// Write to database
|
|
||||||
bitstreamFormatService.update(context, format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================== XML Utility Methods =========================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load in the XML from file.
|
|
||||||
*
|
|
||||||
* @param filename the filename to load from
|
|
||||||
* @return the DOM representation of the XML file
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws ParserConfigurationException if config error
|
|
||||||
* @throws SAXException if parser error
|
|
||||||
*/
|
|
||||||
private static Document loadXML(String filename) throws IOException,
|
|
||||||
ParserConfigurationException, SAXException {
|
|
||||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
|
||||||
.newDocumentBuilder();
|
|
||||||
|
|
||||||
return builder.parse(new File(filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the CDATA of a particular element. For example, if the XML document
|
|
||||||
* contains:
|
|
||||||
* <P>
|
|
||||||
* <code>
|
|
||||||
* <foo><mimetype>application/pdf</mimetype></foo>
|
|
||||||
* </code>
|
|
||||||
* passing this the <code>foo</code> node and <code>mimetype</code> will
|
|
||||||
* return <code>application/pdf</code>.
|
|
||||||
* </P>
|
|
||||||
* Why this isn't a core part of the XML API I do not know...
|
|
||||||
*
|
|
||||||
* @param parentElement the element, whose child element you want the CDATA from
|
|
||||||
* @param childName the name of the element you want the CDATA from
|
|
||||||
* @return the CDATA as a <code>String</code>
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
*/
|
|
||||||
private static String getElementData(Node parentElement, String childName)
|
|
||||||
throws TransformerException {
|
|
||||||
// Grab the child node
|
|
||||||
Node childNode = XPathAPI.selectSingleNode(parentElement, childName);
|
|
||||||
|
|
||||||
if (childNode == null) {
|
|
||||||
// No child node, so no values
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the #text
|
|
||||||
Node dataNode = childNode.getFirstChild();
|
|
||||||
|
|
||||||
if (dataNode == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the data
|
|
||||||
String value = dataNode.getNodeValue().trim();
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get repeated CDATA for a particular element. For example, if the XML
|
|
||||||
* document contains:
|
|
||||||
* <P>
|
|
||||||
* <code>
|
|
||||||
* <foo>
|
|
||||||
* <bar>val1</bar>
|
|
||||||
* <bar>val2</bar>
|
|
||||||
* </foo>
|
|
||||||
* </code>
|
|
||||||
* passing this the <code>foo</code> node and <code>bar</code> will
|
|
||||||
* return <code>val1</code> and <code>val2</code>.
|
|
||||||
* </P>
|
|
||||||
* Why this also isn't a core part of the XML API I do not know...
|
|
||||||
*
|
|
||||||
* @param parentElement the element, whose child element you want the CDATA from
|
|
||||||
* @param childName the name of the element you want the CDATA from
|
|
||||||
* @return the CDATA as a <code>String</code>
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
*/
|
|
||||||
private static String[] getRepeatedElementData(Node parentElement,
|
|
||||||
String childName) throws TransformerException {
|
|
||||||
// Grab the child node
|
|
||||||
NodeList childNodes = XPathAPI.selectNodeList(parentElement, childName);
|
|
||||||
|
|
||||||
String[] data = new String[childNodes.getLength()];
|
|
||||||
|
|
||||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
|
||||||
// Get the #text node
|
|
||||||
Node dataNode = childNodes.item(i).getFirstChild();
|
|
||||||
|
|
||||||
// Get the data
|
|
||||||
data[i] = dataNode.getNodeValue().trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,542 +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.administer;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.xpath.XPathAPI;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.CollectionService;
|
|
||||||
import org.dspace.content.service.CommunityService;
|
|
||||||
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.XMLOutputter;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class deals with importing community and collection structures from
|
|
||||||
* an XML file.
|
|
||||||
*
|
|
||||||
* The XML file structure needs to be:
|
|
||||||
* {@code
|
|
||||||
* <import_structure>
|
|
||||||
* <community>
|
|
||||||
* <name>....</name>
|
|
||||||
* <community>...</community>
|
|
||||||
* <collection>
|
|
||||||
* <name>....</name>
|
|
||||||
* </collection>
|
|
||||||
* </community>
|
|
||||||
* </import_structure>
|
|
||||||
* }
|
|
||||||
* it can be arbitrarily deep, and supports all the metadata elements
|
|
||||||
* that make up the community and collection metadata. See the system
|
|
||||||
* documentation for more details
|
|
||||||
*
|
|
||||||
* @author Richard Jones
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class StructBuilder {
|
|
||||||
/**
|
|
||||||
* the output xml document which will contain updated information about the
|
|
||||||
* imported structure
|
|
||||||
*/
|
|
||||||
private static org.jdom.Document xmlOutput = new org.jdom.Document(new Element("imported_structure"));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a hashtable to hold metadata for the collection being worked on
|
|
||||||
*/
|
|
||||||
private static Map<String, String> collectionMap = new HashMap<String, String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* a hashtable to hold metadata for the community being worked on
|
|
||||||
*/
|
|
||||||
private static Map<String, String> communityMap = new HashMap<String, String>();
|
|
||||||
|
|
||||||
protected static CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
|
|
||||||
protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
|
||||||
protected static EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private StructBuilder() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main method to be run from the command line to import a structure into
|
|
||||||
* DSpace
|
|
||||||
*
|
|
||||||
* This is of the form:
|
|
||||||
*
|
|
||||||
* {@code StructBuilder -f [xml source] -e [administrator email] -o [output file]}
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
* @throws Exception if an error occurs
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv)
|
|
||||||
throws Exception {
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("f", "file", true, "file");
|
|
||||||
options.addOption("e", "eperson", true, "eperson");
|
|
||||||
options.addOption("o", "output", true, "output");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
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();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a context
|
|
||||||
Context context = new Context();
|
|
||||||
|
|
||||||
// set the context
|
|
||||||
context.setCurrentUser(ePersonService.findByEmail(context, eperson));
|
|
||||||
|
|
||||||
// load the XML
|
|
||||||
Document document = loadXML(file);
|
|
||||||
|
|
||||||
// run the preliminary validation, to be sure that the the XML document
|
|
||||||
// is properly structured
|
|
||||||
validate(document);
|
|
||||||
|
|
||||||
// load the mappings into the member variable hashmaps
|
|
||||||
communityMap.put("name", "name");
|
|
||||||
communityMap.put("description", "short_description");
|
|
||||||
communityMap.put("intro", "introductory_text");
|
|
||||||
communityMap.put("copyright", "copyright_text");
|
|
||||||
communityMap.put("sidebar", "side_bar_text");
|
|
||||||
|
|
||||||
collectionMap.put("name", "name");
|
|
||||||
collectionMap.put("description", "short_description");
|
|
||||||
collectionMap.put("intro", "introductory_text");
|
|
||||||
collectionMap.put("copyright", "copyright_text");
|
|
||||||
collectionMap.put("sidebar", "side_bar_text");
|
|
||||||
collectionMap.put("license", "license");
|
|
||||||
collectionMap.put("provenance", "provenance_description");
|
|
||||||
|
|
||||||
// get the top level community list
|
|
||||||
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
|
|
||||||
|
|
||||||
// run the import starting with the top level communities
|
|
||||||
Element[] elements = handleCommunities(context, first, null);
|
|
||||||
|
|
||||||
// generate the output
|
|
||||||
Element root = xmlOutput.getRootElement();
|
|
||||||
for (int i = 0; i < elements.length; i++) {
|
|
||||||
root.addContent(elements[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally write the string into the output file
|
|
||||||
try {
|
|
||||||
BufferedWriter out = new BufferedWriter(new FileWriter(output));
|
|
||||||
out.write(new XMLOutputter().outputString(xmlOutput));
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("Unable to write to output file " + output);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.complete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output the usage information
|
|
||||||
*/
|
|
||||||
private static void usage() {
|
|
||||||
System.out.println("Usage: java StructBuilder -f <source XML file> -o <output file> -e <eperson email>");
|
|
||||||
System.out.println(
|
|
||||||
"Communities will be created from the top level, and a map of communities to handles will be returned in " +
|
|
||||||
"the output file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the XML document. This method does not return, but if validation
|
|
||||||
* fails it generates an error and ceases execution
|
|
||||||
*
|
|
||||||
* @param document the XML document object
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
*/
|
|
||||||
private static void validate(org.w3c.dom.Document document)
|
|
||||||
throws TransformerException {
|
|
||||||
StringBuffer err = new StringBuffer();
|
|
||||||
boolean trip = false;
|
|
||||||
|
|
||||||
err.append("The following errors were encountered parsing the source XML\n");
|
|
||||||
err.append("No changes have been made to the DSpace instance\n\n");
|
|
||||||
|
|
||||||
NodeList first = XPathAPI.selectNodeList(document, "/import_structure/community");
|
|
||||||
if (first.getLength() == 0) {
|
|
||||||
err.append("-There are no top level communities in the source document");
|
|
||||||
System.out.println(err.toString());
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
String errs = validateCommunities(first, 1);
|
|
||||||
if (errs != null) {
|
|
||||||
err.append(errs);
|
|
||||||
trip = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trip) {
|
|
||||||
System.out.println(err.toString());
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the communities section of the XML document. This returns a string
|
|
||||||
* containing any errors encountered, or null if there were no errors
|
|
||||||
*
|
|
||||||
* @param communities the NodeList of communities to validate
|
|
||||||
* @param level the level in the XML document that we are at, for the purposes
|
|
||||||
* of error reporting
|
|
||||||
* @return the errors that need to be generated by the calling method, or null if
|
|
||||||
* no errors.
|
|
||||||
*/
|
|
||||||
private static String validateCommunities(NodeList communities, int level)
|
|
||||||
throws TransformerException {
|
|
||||||
StringBuffer err = new StringBuffer();
|
|
||||||
boolean trip = false;
|
|
||||||
String errs = null;
|
|
||||||
|
|
||||||
for (int i = 0; i < communities.getLength(); i++) {
|
|
||||||
Node n = communities.item(i);
|
|
||||||
NodeList name = XPathAPI.selectNodeList(n, "name");
|
|
||||||
if (name.getLength() != 1) {
|
|
||||||
String pos = Integer.toString(i + 1);
|
|
||||||
err.append("-The level " + level + " community in position " + pos);
|
|
||||||
err.append(" does not contain exactly one name field\n");
|
|
||||||
trip = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate sub communities
|
|
||||||
NodeList subCommunities = XPathAPI.selectNodeList(n, "community");
|
|
||||||
String comErrs = validateCommunities(subCommunities, level + 1);
|
|
||||||
if (comErrs != null) {
|
|
||||||
err.append(comErrs);
|
|
||||||
trip = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate collections
|
|
||||||
NodeList collections = XPathAPI.selectNodeList(n, "collection");
|
|
||||||
String colErrs = validateCollections(collections, level + 1);
|
|
||||||
if (colErrs != null) {
|
|
||||||
err.append(colErrs);
|
|
||||||
trip = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trip) {
|
|
||||||
errs = err.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return errs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* validate the collection section of the XML document. This generates a
|
|
||||||
* string containing any errors encountered, or returns null if no errors
|
|
||||||
*
|
|
||||||
* @param collections a NodeList of collections to validate
|
|
||||||
* @param level the level in the XML document for the purposes of error reporting
|
|
||||||
* @return the errors to be generated by the calling method, or null if none
|
|
||||||
*/
|
|
||||||
private static String validateCollections(NodeList collections, int level)
|
|
||||||
throws TransformerException {
|
|
||||||
StringBuffer err = new StringBuffer();
|
|
||||||
boolean trip = false;
|
|
||||||
String errs = null;
|
|
||||||
|
|
||||||
for (int i = 0; i < collections.getLength(); i++) {
|
|
||||||
Node n = collections.item(i);
|
|
||||||
NodeList name = XPathAPI.selectNodeList(n, "name");
|
|
||||||
if (name.getLength() != 1) {
|
|
||||||
String pos = Integer.toString(i + 1);
|
|
||||||
err.append("-The level " + level + " collection in position " + pos);
|
|
||||||
err.append(" does not contain exactly one name field\n");
|
|
||||||
trip = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trip) {
|
|
||||||
errs = err.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return errs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load in the XML from file.
|
|
||||||
*
|
|
||||||
* @param filename the filename to load from
|
|
||||||
* @return the DOM representation of the XML file
|
|
||||||
*/
|
|
||||||
private static org.w3c.dom.Document loadXML(String filename)
|
|
||||||
throws IOException, ParserConfigurationException, SAXException {
|
|
||||||
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
|
|
||||||
.newDocumentBuilder();
|
|
||||||
|
|
||||||
org.w3c.dom.Document document = builder.parse(new File(filename));
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the String value of a Node
|
|
||||||
*
|
|
||||||
* @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) {
|
|
||||||
String value = node.getNodeValue();
|
|
||||||
|
|
||||||
if (node.hasChildNodes()) {
|
|
||||||
Node first = node.getFirstChild();
|
|
||||||
|
|
||||||
if (first.getNodeType() == Node.TEXT_NODE) {
|
|
||||||
return first.getNodeValue().trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a node list of communities and build the structure from them, delegating
|
|
||||||
* to the relevant methods in this class for sub-communities and collections
|
|
||||||
*
|
|
||||||
* @param context the context of the request
|
|
||||||
* @param communities a nodelist of communities to create along with their sub-structures
|
|
||||||
* @param parent the parent community of the nodelist of communities to create
|
|
||||||
* @return an element array containing additional information regarding the
|
|
||||||
* created communities (e.g. the handles they have been assigned)
|
|
||||||
*/
|
|
||||||
private static Element[] handleCommunities(Context context, NodeList communities, Community parent)
|
|
||||||
throws TransformerException, SQLException, Exception {
|
|
||||||
Element[] elements = new Element[communities.getLength()];
|
|
||||||
|
|
||||||
for (int i = 0; i < communities.getLength(); i++) {
|
|
||||||
Community community;
|
|
||||||
Element element = new Element("community");
|
|
||||||
|
|
||||||
// create the community or sub community
|
|
||||||
if (parent != null) {
|
|
||||||
community = communityService.create(parent, context);
|
|
||||||
} else {
|
|
||||||
community = communityService.create(null, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
// default the short description to be an empty string
|
|
||||||
communityService.setMetadata(context, community, "short_description", " ");
|
|
||||||
|
|
||||||
// now update the metadata
|
|
||||||
Node tn = communities.item(i);
|
|
||||||
for (Map.Entry<String, String> entry : communityMap.entrySet()) {
|
|
||||||
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
|
|
||||||
if (nl.getLength() == 1) {
|
|
||||||
communityService.setMetadata(context, community, entry.getValue(), getStringValue(nl.item(0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: at the moment, if the community already exists by name
|
|
||||||
// then this will throw a PSQLException on a duplicate key
|
|
||||||
// violation
|
|
||||||
// Ideally we'd skip this row and continue to create sub
|
|
||||||
// communities
|
|
||||||
// and so forth where they don't exist, but it's proving
|
|
||||||
// difficult
|
|
||||||
// to isolate the community that already exists without hitting
|
|
||||||
// the database directly.
|
|
||||||
communityService.update(context, community);
|
|
||||||
|
|
||||||
// build the element with the handle that identifies the new
|
|
||||||
// community
|
|
||||||
// along with all the information that we imported here
|
|
||||||
// This looks like a lot of repetition of getting information
|
|
||||||
// from above
|
|
||||||
// but it's here to keep it separate from the create process in
|
|
||||||
// case
|
|
||||||
// we want to move it or make it switchable later
|
|
||||||
element.setAttribute("identifier", community.getHandle());
|
|
||||||
|
|
||||||
Element nameElement = new Element("name");
|
|
||||||
nameElement.setText(communityService.getMetadata(community, "name"));
|
|
||||||
element.addContent(nameElement);
|
|
||||||
|
|
||||||
if (communityService.getMetadata(community, "short_description") != null) {
|
|
||||||
Element descriptionElement = new Element("description");
|
|
||||||
descriptionElement.setText(communityService.getMetadata(community, "short_description"));
|
|
||||||
element.addContent(descriptionElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (communityService.getMetadata(community, "introductory_text") != null) {
|
|
||||||
Element introElement = new Element("intro");
|
|
||||||
introElement.setText(communityService.getMetadata(community, "introductory_text"));
|
|
||||||
element.addContent(introElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (communityService.getMetadata(community, "copyright_text") != null) {
|
|
||||||
Element copyrightElement = new Element("copyright");
|
|
||||||
copyrightElement.setText(communityService.getMetadata(community, "copyright_text"));
|
|
||||||
element.addContent(copyrightElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (communityService.getMetadata(community, "side_bar_text") != null) {
|
|
||||||
Element sidebarElement = new Element("sidebar");
|
|
||||||
sidebarElement.setText(communityService.getMetadata(community, "side_bar_text"));
|
|
||||||
element.addContent(sidebarElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle sub communities
|
|
||||||
NodeList subCommunities = XPathAPI.selectNodeList(tn, "community");
|
|
||||||
Element[] subCommunityElements = handleCommunities(context, subCommunities, community);
|
|
||||||
|
|
||||||
// handle collections
|
|
||||||
NodeList collections = XPathAPI.selectNodeList(tn, "collection");
|
|
||||||
Element[] collectionElements = handleCollections(context, collections, community);
|
|
||||||
|
|
||||||
int j;
|
|
||||||
for (j = 0; j < subCommunityElements.length; j++) {
|
|
||||||
element.addContent(subCommunityElements[j]);
|
|
||||||
}
|
|
||||||
for (j = 0; j < collectionElements.length; j++) {
|
|
||||||
element.addContent(collectionElements[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[i] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a node list of collections and create the structure from them
|
|
||||||
*
|
|
||||||
* @param context the context of the request
|
|
||||||
* @param collections the node list of collections to be created
|
|
||||||
* @param parent the parent community to whom the collections belong
|
|
||||||
* @return an Element array containing additional information about the
|
|
||||||
* created collections (e.g. the handle)
|
|
||||||
*/
|
|
||||||
private static Element[] handleCollections(Context context, NodeList collections, Community parent)
|
|
||||||
throws TransformerException, SQLException, AuthorizeException, IOException, Exception {
|
|
||||||
Element[] elements = new Element[collections.getLength()];
|
|
||||||
|
|
||||||
for (int i = 0; i < collections.getLength(); i++) {
|
|
||||||
Element element = new Element("collection");
|
|
||||||
Collection collection = collectionService.create(context, parent);
|
|
||||||
|
|
||||||
// default the short description to the empty string
|
|
||||||
collectionService.setMetadata(context, collection, "short_description", " ");
|
|
||||||
|
|
||||||
// import the rest of the metadata
|
|
||||||
Node tn = collections.item(i);
|
|
||||||
for (Map.Entry<String, String> entry : collectionMap.entrySet()) {
|
|
||||||
NodeList nl = XPathAPI.selectNodeList(tn, entry.getKey());
|
|
||||||
if (nl.getLength() == 1) {
|
|
||||||
collectionService.setMetadata(context, collection, entry.getValue(), getStringValue(nl.item(0)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
collectionService.update(context, collection);
|
|
||||||
|
|
||||||
element.setAttribute("identifier", collection.getHandle());
|
|
||||||
|
|
||||||
Element nameElement = new Element("name");
|
|
||||||
nameElement.setText(collectionService.getMetadata(collection, "name"));
|
|
||||||
element.addContent(nameElement);
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "short_description") != null) {
|
|
||||||
Element descriptionElement = new Element("description");
|
|
||||||
descriptionElement.setText(collectionService.getMetadata(collection, "short_description"));
|
|
||||||
element.addContent(descriptionElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "introductory_text") != null) {
|
|
||||||
Element introElement = new Element("intro");
|
|
||||||
introElement.setText(collectionService.getMetadata(collection, "introductory_text"));
|
|
||||||
element.addContent(introElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "copyright_text") != null) {
|
|
||||||
Element copyrightElement = new Element("copyright");
|
|
||||||
copyrightElement.setText(collectionService.getMetadata(collection, "copyright_text"));
|
|
||||||
element.addContent(copyrightElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "side_bar_text") != null) {
|
|
||||||
Element sidebarElement = new Element("sidebar");
|
|
||||||
sidebarElement.setText(collectionService.getMetadata(collection, "side_bar_text"));
|
|
||||||
element.addContent(sidebarElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "license") != null) {
|
|
||||||
Element sidebarElement = new Element("license");
|
|
||||||
sidebarElement.setText(collectionService.getMetadata(collection, "license"));
|
|
||||||
element.addContent(sidebarElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionService.getMetadata(collection, "provenance_description") != null) {
|
|
||||||
Element sidebarElement = new Element("provenance");
|
|
||||||
sidebarElement.setText(collectionService.getMetadata(collection, "provenance_description"));
|
|
||||||
element.addContent(sidebarElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[i] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
return elements;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,23 +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/
|
|
||||||
|
|
||||||
-->
|
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<!--
|
|
||||||
Author: Robert Tansley
|
|
||||||
Version: $Revision$
|
|
||||||
Date: $Date$
|
|
||||||
-->
|
|
||||||
</head>
|
|
||||||
<body bgcolor="white">
|
|
||||||
Provides classes and methods for administrative functions that fall outside
|
|
||||||
the regular use of other subsystems.
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to store changes to item that may occur during a batch edit.
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class BulkEditChange {
|
|
||||||
/**
|
|
||||||
* The item these changes relate to
|
|
||||||
*/
|
|
||||||
private Item item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The List of hashtables with the new elements
|
|
||||||
*/
|
|
||||||
private List<BulkEditMetadataValue> adds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The List of hashtables with the removed elements
|
|
||||||
*/
|
|
||||||
private List<BulkEditMetadataValue> removes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The List of hashtables with the unchanged elements
|
|
||||||
*/
|
|
||||||
private List<BulkEditMetadataValue> constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The List of the complete set of new values (constant + adds)
|
|
||||||
*/
|
|
||||||
private List<BulkEditMetadataValue> complete;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of old collections the item used to be mapped to
|
|
||||||
*/
|
|
||||||
private List<Collection> oldMappedCollections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of new collections the item has been mapped into
|
|
||||||
*/
|
|
||||||
private List<Collection> newMappedCollections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The old owning collection
|
|
||||||
*/
|
|
||||||
private Collection oldOwningCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The new owning collection
|
|
||||||
*/
|
|
||||||
private Collection newOwningCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is this a new item
|
|
||||||
*/
|
|
||||||
private boolean newItem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this item been deleted?
|
|
||||||
*/
|
|
||||||
private boolean deleted;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this item been withdrawn?
|
|
||||||
*/
|
|
||||||
private boolean withdrawn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this item been reinstated?
|
|
||||||
*/
|
|
||||||
private boolean reinstated;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Have any changes actually been made?
|
|
||||||
*/
|
|
||||||
private boolean empty;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise a change holder for a new item
|
|
||||||
*/
|
|
||||||
public BulkEditChange() {
|
|
||||||
// Set the item to be null
|
|
||||||
item = null;
|
|
||||||
newItem = true;
|
|
||||||
empty = true;
|
|
||||||
oldOwningCollection = null;
|
|
||||||
newOwningCollection = null;
|
|
||||||
|
|
||||||
// Initialise the arrays
|
|
||||||
adds = new ArrayList<>();
|
|
||||||
removes = new ArrayList<>();
|
|
||||||
constant = new ArrayList<>();
|
|
||||||
complete = new ArrayList<>();
|
|
||||||
oldMappedCollections = new ArrayList<>();
|
|
||||||
newMappedCollections = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise a new change holder for an existing item
|
|
||||||
*
|
|
||||||
* @param i The Item to store
|
|
||||||
*/
|
|
||||||
public BulkEditChange(Item i) {
|
|
||||||
// Store the item
|
|
||||||
item = i;
|
|
||||||
newItem = false;
|
|
||||||
empty = true;
|
|
||||||
|
|
||||||
// Initialise the arrays
|
|
||||||
adds = new ArrayList<>();
|
|
||||||
removes = new ArrayList<>();
|
|
||||||
constant = new ArrayList<>();
|
|
||||||
complete = new ArrayList<>();
|
|
||||||
oldMappedCollections = new ArrayList<>();
|
|
||||||
newMappedCollections = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the item - used when a new item is created
|
|
||||||
*
|
|
||||||
* @param i The item
|
|
||||||
*/
|
|
||||||
public void setItem(Item i) {
|
|
||||||
// Store the item
|
|
||||||
item = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an added metadata value
|
|
||||||
*
|
|
||||||
* @param dcv The value to add
|
|
||||||
*/
|
|
||||||
public void registerAdd(BulkEditMetadataValue dcv) {
|
|
||||||
// Add the added value
|
|
||||||
adds.add(dcv);
|
|
||||||
complete.add(dcv);
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a removed metadata value
|
|
||||||
*
|
|
||||||
* @param dcv The value to remove
|
|
||||||
*/
|
|
||||||
public void registerRemove(BulkEditMetadataValue dcv) {
|
|
||||||
// Add the removed value
|
|
||||||
removes.add(dcv);
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an unchanged metadata value
|
|
||||||
*
|
|
||||||
* @param dcv The value to keep unchanged
|
|
||||||
*/
|
|
||||||
public void registerConstant(BulkEditMetadataValue dcv) {
|
|
||||||
// Add the removed value
|
|
||||||
constant.add(dcv);
|
|
||||||
complete.add(dcv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new mapped Collection
|
|
||||||
*
|
|
||||||
* @param c The new mapped Collection
|
|
||||||
*/
|
|
||||||
public void registerNewMappedCollection(Collection c) {
|
|
||||||
// Add the new owning Collection
|
|
||||||
newMappedCollections.add(c);
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an old mapped Collection
|
|
||||||
*
|
|
||||||
* @param c The old mapped Collection
|
|
||||||
*/
|
|
||||||
public void registerOldMappedCollection(Collection c) {
|
|
||||||
// Add the old owning Collection (if it isn't there already, or is an old collection)
|
|
||||||
boolean found = false;
|
|
||||||
|
|
||||||
if ((this.getOldOwningCollection() != null) &&
|
|
||||||
(this.getOldOwningCollection().getHandle().equals(c.getHandle()))) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Collection collection : oldMappedCollections) {
|
|
||||||
if (collection.getHandle().equals(c.getHandle())) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
oldMappedCollections.add(c);
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a change to the owning collection
|
|
||||||
*
|
|
||||||
* @param oldC The old owning collection
|
|
||||||
* @param newC The new owning collection
|
|
||||||
*/
|
|
||||||
public void changeOwningCollection(Collection oldC, Collection newC) {
|
|
||||||
// Store the old owning collection
|
|
||||||
oldOwningCollection = oldC;
|
|
||||||
|
|
||||||
// Store the new owning collection
|
|
||||||
newOwningCollection = newC;
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the owning collection of an item
|
|
||||||
*
|
|
||||||
* @param newC The new owning collection
|
|
||||||
*/
|
|
||||||
public void setOwningCollection(Collection newC) {
|
|
||||||
// Store the new owning collection
|
|
||||||
newOwningCollection = newC;
|
|
||||||
//empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the DSpace Item that these changes are applicable to.
|
|
||||||
*
|
|
||||||
* @return The item
|
|
||||||
*/
|
|
||||||
public Item getItem() {
|
|
||||||
// Return the item
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of elements and their values that have been added.
|
|
||||||
*
|
|
||||||
* @return the list of elements and their values that have been added.
|
|
||||||
*/
|
|
||||||
public List<BulkEditMetadataValue> getAdds() {
|
|
||||||
// Return the array
|
|
||||||
return adds;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of elements and their values that have been removed.
|
|
||||||
*
|
|
||||||
* @return the list of elements and their values that have been removed.
|
|
||||||
*/
|
|
||||||
public List<BulkEditMetadataValue> getRemoves() {
|
|
||||||
// Return the array
|
|
||||||
return removes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of unchanged values
|
|
||||||
*
|
|
||||||
* @return the list of unchanged values
|
|
||||||
*/
|
|
||||||
public List<BulkEditMetadataValue> getConstant() {
|
|
||||||
// Return the array
|
|
||||||
return constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of all values
|
|
||||||
*
|
|
||||||
* @return the list of all values
|
|
||||||
*/
|
|
||||||
public List<BulkEditMetadataValue> getComplete() {
|
|
||||||
// Return the array
|
|
||||||
return complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of new mapped Collections
|
|
||||||
*
|
|
||||||
* @return the list of new mapped collections
|
|
||||||
*/
|
|
||||||
public List<Collection> getNewMappedCollections() {
|
|
||||||
// Return the array
|
|
||||||
return newMappedCollections;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of old mapped Collections
|
|
||||||
*
|
|
||||||
* @return the list of old mapped collections
|
|
||||||
*/
|
|
||||||
public List<Collection> getOldMappedCollections() {
|
|
||||||
// Return the array
|
|
||||||
return oldMappedCollections;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the old owning collection
|
|
||||||
*
|
|
||||||
* @return the old owning collection
|
|
||||||
*/
|
|
||||||
public Collection getOldOwningCollection() {
|
|
||||||
// Return the old owning collection
|
|
||||||
return oldOwningCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the new owning collection
|
|
||||||
*
|
|
||||||
* @return the new owning collection
|
|
||||||
*/
|
|
||||||
public Collection getNewOwningCollection() {
|
|
||||||
// Return the new owning collection
|
|
||||||
return newOwningCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this change object represent a new item?
|
|
||||||
*
|
|
||||||
* @return Whether or not this is for a new item
|
|
||||||
*/
|
|
||||||
public boolean isNewItem() {
|
|
||||||
// Return the new item status
|
|
||||||
return newItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this change object represent a deleted item?
|
|
||||||
*
|
|
||||||
* @return Whether or not this is for a deleted item
|
|
||||||
*/
|
|
||||||
public boolean isDeleted() {
|
|
||||||
// Return the new item status
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set that this item has been deleted
|
|
||||||
*/
|
|
||||||
public void setDeleted() {
|
|
||||||
// Store the setting
|
|
||||||
deleted = true;
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this change object represent a withdrawn item?
|
|
||||||
*
|
|
||||||
* @return Whether or not this is for a withdrawn item
|
|
||||||
*/
|
|
||||||
public boolean isWithdrawn() {
|
|
||||||
// Return the new item status
|
|
||||||
return withdrawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set that this item has been withdrawn
|
|
||||||
*/
|
|
||||||
public void setWithdrawn() {
|
|
||||||
// Store the setting
|
|
||||||
withdrawn = true;
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does this change object represent a reinstated item?
|
|
||||||
*
|
|
||||||
* @return Whether or not this is for a reinstated item
|
|
||||||
*/
|
|
||||||
public boolean isReinstated() {
|
|
||||||
// Return the new item status
|
|
||||||
return reinstated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set that this item has been deleted
|
|
||||||
*/
|
|
||||||
public void setReinstated() {
|
|
||||||
// Store the setting
|
|
||||||
reinstated = true;
|
|
||||||
empty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Have any changes actually been recorded, or is this empty?
|
|
||||||
*
|
|
||||||
* @return Whether or not changes have been made
|
|
||||||
*/
|
|
||||||
public boolean hasChanges() {
|
|
||||||
return !empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value class used for metadata value edits used by the bulk edit.
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public class BulkEditMetadataValue {
|
|
||||||
|
|
||||||
private String schema;
|
|
||||||
private String element;
|
|
||||||
private String qualifier;
|
|
||||||
private String language;
|
|
||||||
private String value;
|
|
||||||
private String authority;
|
|
||||||
private int confidence;
|
|
||||||
|
|
||||||
public BulkEditMetadataValue() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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 setLanguage(String language) {
|
|
||||||
this.language = language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(String value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthority(String authority) {
|
|
||||||
this.authority = authority;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConfidence(int confidence) {
|
|
||||||
this.confidence = confidence;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSchema() {
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getElement() {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getQualifier() {
|
|
||||||
return qualifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLanguage() {
|
|
||||||
return language;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthority() {
|
|
||||||
return authority;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getConfidence() {
|
|
||||||
return confidence;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,689 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.dspace.authority.AuthorityValue;
|
|
||||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
|
||||||
import org.dspace.authority.service.AuthorityValueService;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.MetadataValue;
|
|
||||||
import org.dspace.content.authority.Choices;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.content.service.MetadataFieldService;
|
|
||||||
import org.dspace.content.service.MetadataSchemaService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to read and write CSV files
|
|
||||||
*
|
|
||||||
* **************
|
|
||||||
* Important Note
|
|
||||||
* **************
|
|
||||||
*
|
|
||||||
* This class has been made serializable, as it is stored in a Session.
|
|
||||||
* Is it wise to:
|
|
||||||
* a) be putting this into a user's session?
|
|
||||||
* b) holding an entire CSV upload in memory?
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class DSpaceCSV implements Serializable {
|
|
||||||
/**
|
|
||||||
* The headings of the CSV file
|
|
||||||
*/
|
|
||||||
protected List<String> headings;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An array list of CSV lines
|
|
||||||
*/
|
|
||||||
protected List<DSpaceCSVLine> lines;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A counter of how many CSV lines this object holds
|
|
||||||
*/
|
|
||||||
protected int counter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The value separator (defaults to double pipe '||')
|
|
||||||
*/
|
|
||||||
protected String valueSeparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The value separator in an escaped form for using in regexes
|
|
||||||
*/
|
|
||||||
protected String escapedValueSeparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The field separator (defaults to comma)
|
|
||||||
*/
|
|
||||||
protected String fieldSeparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The field separator in an escaped form for using in regexes
|
|
||||||
*/
|
|
||||||
protected String escapedFieldSeparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The authority separator (defaults to double colon '::')
|
|
||||||
*/
|
|
||||||
protected String authoritySeparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The authority separator in an escaped form for using in regexes
|
|
||||||
*/
|
|
||||||
protected String escapedAuthoritySeparator;
|
|
||||||
|
|
||||||
protected transient final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
protected transient final MetadataSchemaService metadataSchemaService =
|
|
||||||
ContentServiceFactory.getInstance().getMetadataSchemaService();
|
|
||||||
protected transient final MetadataFieldService metadataFieldService =
|
|
||||||
ContentServiceFactory.getInstance().getMetadataFieldService();
|
|
||||||
protected transient final AuthorityValueService authorityValueService =
|
|
||||||
AuthorityServiceFactory.getInstance().getAuthorityValueService();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to export all metadata such as handles and provenance information
|
|
||||||
*/
|
|
||||||
protected boolean exportAll;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list of metadata elements to ignore
|
|
||||||
*/
|
|
||||||
protected Map<String, String> ignore;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of a CSV line holder
|
|
||||||
*
|
|
||||||
* @param exportAll Whether to export all metadata such as handles and provenance information
|
|
||||||
*/
|
|
||||||
public DSpaceCSV(boolean exportAll) {
|
|
||||||
// Initialise the class
|
|
||||||
init();
|
|
||||||
|
|
||||||
// Store the exportAll setting
|
|
||||||
this.exportAll = exportAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance, reading the lines in from file
|
|
||||||
*
|
|
||||||
* @param f The file to read from
|
|
||||||
* @param c The DSpace Context
|
|
||||||
* @throws Exception thrown if there is an error reading or processing the file
|
|
||||||
*/
|
|
||||||
public DSpaceCSV(File f, Context c) throws Exception {
|
|
||||||
// Initialise the class
|
|
||||||
init();
|
|
||||||
|
|
||||||
// Open the CSV file
|
|
||||||
BufferedReader input = null;
|
|
||||||
try {
|
|
||||||
input = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
|
|
||||||
|
|
||||||
// Read the heading line
|
|
||||||
String head = input.readLine();
|
|
||||||
String[] headingElements = head.split(escapedFieldSeparator);
|
|
||||||
int columnCounter = 0;
|
|
||||||
for (String element : headingElements) {
|
|
||||||
columnCounter++;
|
|
||||||
|
|
||||||
// Remove surrounding quotes if there are any
|
|
||||||
if ((element.startsWith("\"")) && (element.endsWith("\""))) {
|
|
||||||
element = element.substring(1, element.length() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the heading
|
|
||||||
if ("collection".equals(element)) {
|
|
||||||
// Store the heading
|
|
||||||
headings.add(element);
|
|
||||||
} else if ("action".equals(element)) { // Store the action
|
|
||||||
// Store the heading
|
|
||||||
headings.add(element);
|
|
||||||
} else if (!"id".equals(element)) {
|
|
||||||
String authorityPrefix = "";
|
|
||||||
AuthorityValue authorityValueType = authorityValueService.getAuthorityValueType(element);
|
|
||||||
if (authorityValueType != null) {
|
|
||||||
String authorityType = authorityValueType.getAuthorityType();
|
|
||||||
authorityPrefix = element.substring(0, authorityType.length() + 1);
|
|
||||||
element = element.substring(authorityPrefix.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the heading is valid in the metadata registry
|
|
||||||
String[] clean = element.split("\\[");
|
|
||||||
String[] parts = clean[0].split("\\.");
|
|
||||||
|
|
||||||
if (parts.length < 2) {
|
|
||||||
throw new MetadataImportInvalidHeadingException(element,
|
|
||||||
MetadataImportInvalidHeadingException.ENTRY,
|
|
||||||
columnCounter);
|
|
||||||
}
|
|
||||||
|
|
||||||
String metadataSchema = parts[0];
|
|
||||||
String metadataElement = parts[1];
|
|
||||||
String metadataQualifier = null;
|
|
||||||
if (parts.length > 2) {
|
|
||||||
metadataQualifier = parts[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the scheme exists
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the heading
|
|
||||||
headings.add(authorityPrefix + element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read each subsequent line
|
|
||||||
StringBuilder lineBuilder = new StringBuilder();
|
|
||||||
String lineRead;
|
|
||||||
|
|
||||||
while ((lineRead = input.readLine()) != null) {
|
|
||||||
if (lineBuilder.length() > 0) {
|
|
||||||
// Already have a previously read value - add this line
|
|
||||||
lineBuilder.append("\n").append(lineRead);
|
|
||||||
|
|
||||||
// Count the number of quotes in the buffer
|
|
||||||
int quoteCount = 0;
|
|
||||||
for (int pos = 0; pos < lineBuilder.length(); pos++) {
|
|
||||||
if (lineBuilder.charAt(pos) == '"') {
|
|
||||||
quoteCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quoteCount % 2 == 0) {
|
|
||||||
// Number of quotes is a multiple of 2, add the item
|
|
||||||
addItem(lineBuilder.toString());
|
|
||||||
lineBuilder = new StringBuilder();
|
|
||||||
}
|
|
||||||
} else if (lineRead.indexOf('"') > -1) {
|
|
||||||
// Get the number of quotes in the line
|
|
||||||
int quoteCount = 0;
|
|
||||||
for (int pos = 0; pos < lineRead.length(); pos++) {
|
|
||||||
if (lineRead.charAt(pos) == '"') {
|
|
||||||
quoteCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (quoteCount % 2 == 0) {
|
|
||||||
// Number of quotes is a multiple of 2, add the item
|
|
||||||
addItem(lineRead);
|
|
||||||
} else {
|
|
||||||
// Uneven quotes - add to the buffer and leave for later
|
|
||||||
lineBuilder.append(lineRead);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No previously read line, and no quotes in the line - add item
|
|
||||||
addItem(lineRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (input != null) {
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise this class with values from dspace.cfg
|
|
||||||
*/
|
|
||||||
protected void init() {
|
|
||||||
// Set the value separator
|
|
||||||
setValueSeparator();
|
|
||||||
|
|
||||||
// Set the field separator
|
|
||||||
setFieldSeparator();
|
|
||||||
|
|
||||||
// Set the authority separator
|
|
||||||
setAuthoritySeparator();
|
|
||||||
|
|
||||||
// Create the headings
|
|
||||||
headings = new ArrayList<>();
|
|
||||||
|
|
||||||
// Create the blank list of items
|
|
||||||
lines = new ArrayList<>();
|
|
||||||
|
|
||||||
// Initialise the counter
|
|
||||||
counter = 0;
|
|
||||||
|
|
||||||
// Set the metadata fields to ignore
|
|
||||||
ignore = new HashMap<>();
|
|
||||||
|
|
||||||
// Specify default values
|
|
||||||
String[] defaultValues =
|
|
||||||
new String[] {
|
|
||||||
"dc.date.accessioned, dc.date.available, dc.date.updated, dc.description.provenance"
|
|
||||||
};
|
|
||||||
String[] toIgnoreArray =
|
|
||||||
DSpaceServicesFactory.getInstance()
|
|
||||||
.getConfigurationService()
|
|
||||||
.getArrayProperty("bulkedit.ignore-on-export", defaultValues);
|
|
||||||
for (String toIgnoreString : toIgnoreArray) {
|
|
||||||
if (!"".equals(toIgnoreString.trim())) {
|
|
||||||
ignore.put(toIgnoreString.trim(), toIgnoreString.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decide if this CSV file has an 'action' (case-dependent!) header.
|
|
||||||
*
|
|
||||||
* @return Whether or not there is an 'action' header
|
|
||||||
*/
|
|
||||||
public boolean hasActions() {
|
|
||||||
// Look for a heading called 'action'
|
|
||||||
for (String header : headings) {
|
|
||||||
if (header.equals("action")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the value separator for multiple values stored in one csv value.
|
|
||||||
*
|
|
||||||
* Is set in bulkedit.cfg as valueseparator
|
|
||||||
*
|
|
||||||
* If not set, defaults to double pipe '||'
|
|
||||||
*/
|
|
||||||
private void setValueSeparator() {
|
|
||||||
// Get the value separator
|
|
||||||
valueSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
|
|
||||||
.getProperty("bulkedit.valueseparator");
|
|
||||||
if ((valueSeparator != null) && (!"".equals(valueSeparator.trim()))) {
|
|
||||||
valueSeparator = valueSeparator.trim();
|
|
||||||
} else {
|
|
||||||
valueSeparator = "||";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now store the escaped version
|
|
||||||
Pattern spchars = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
|
|
||||||
Matcher match = spchars.matcher(valueSeparator);
|
|
||||||
escapedValueSeparator = match.replaceAll("\\\\$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the field separator use to separate fields in the csv.
|
|
||||||
*
|
|
||||||
* Is set in bulkedit.cfg as fieldseparator
|
|
||||||
*
|
|
||||||
* If not set, defaults to comma ','.
|
|
||||||
*
|
|
||||||
* Special values are 'tab', 'hash' and 'semicolon' which will
|
|
||||||
* get substituted from the text to the value.
|
|
||||||
*/
|
|
||||||
private void setFieldSeparator() {
|
|
||||||
// Get the value separator
|
|
||||||
fieldSeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
|
|
||||||
.getProperty("bulkedit.fieldseparator");
|
|
||||||
if ((fieldSeparator != null) && (!"".equals(fieldSeparator.trim()))) {
|
|
||||||
fieldSeparator = fieldSeparator.trim();
|
|
||||||
if ("tab".equals(fieldSeparator)) {
|
|
||||||
fieldSeparator = "\t";
|
|
||||||
} else if ("semicolon".equals(fieldSeparator)) {
|
|
||||||
fieldSeparator = ";";
|
|
||||||
} else if ("hash".equals(fieldSeparator)) {
|
|
||||||
fieldSeparator = "#";
|
|
||||||
} else {
|
|
||||||
fieldSeparator = fieldSeparator.trim();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fieldSeparator = ",";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now store the escaped version
|
|
||||||
Pattern spchars = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
|
|
||||||
Matcher match = spchars.matcher(fieldSeparator);
|
|
||||||
escapedFieldSeparator = match.replaceAll("\\\\$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the authority separator for value with authority data.
|
|
||||||
*
|
|
||||||
* Is set in dspace.cfg as bulkedit.authorityseparator
|
|
||||||
*
|
|
||||||
* If not set, defaults to double colon '::'
|
|
||||||
*/
|
|
||||||
private void setAuthoritySeparator() {
|
|
||||||
// Get the value separator
|
|
||||||
authoritySeparator = DSpaceServicesFactory.getInstance().getConfigurationService()
|
|
||||||
.getProperty("bulkedit.authorityseparator");
|
|
||||||
if ((authoritySeparator != null) && (!"".equals(authoritySeparator.trim()))) {
|
|
||||||
authoritySeparator = authoritySeparator.trim();
|
|
||||||
} else {
|
|
||||||
authoritySeparator = "::";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now store the escaped version
|
|
||||||
Pattern spchars = Pattern.compile("([\\\\*+\\[\\](){}\\$.?\\^|])");
|
|
||||||
Matcher match = spchars.matcher(authoritySeparator);
|
|
||||||
escapedAuthoritySeparator = match.replaceAll("\\\\$1");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a DSpace item to the CSV file
|
|
||||||
*
|
|
||||||
* @param i The DSpace item
|
|
||||||
* @throws Exception if something goes wrong with adding the Item
|
|
||||||
*/
|
|
||||||
public final void addItem(Item i) throws Exception {
|
|
||||||
// If the item does not have an "owningCollection" the the below "getHandle()" call will fail
|
|
||||||
// This should not happen but is here for safety.
|
|
||||||
if (i.getOwningCollection() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the CSV line
|
|
||||||
DSpaceCSVLine line = new DSpaceCSVLine(i.getID());
|
|
||||||
|
|
||||||
// Add in owning collection
|
|
||||||
String owningCollectionHandle = i.getOwningCollection().getHandle();
|
|
||||||
line.add("collection", owningCollectionHandle);
|
|
||||||
|
|
||||||
// Add in any mapped collections
|
|
||||||
List<Collection> collections = i.getCollections();
|
|
||||||
for (Collection c : collections) {
|
|
||||||
// Only add if it is not the owning collection
|
|
||||||
if (!c.getHandle().equals(owningCollectionHandle)) {
|
|
||||||
line.add("collection", c.getHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate it
|
|
||||||
List<MetadataValue> md = itemService.getMetadata(i, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
|
|
||||||
for (MetadataValue value : md) {
|
|
||||||
MetadataField metadataField = value.getMetadataField();
|
|
||||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
|
||||||
// Get the key (schema.element)
|
|
||||||
String key = metadataSchema.getName() + "." + metadataField.getElement();
|
|
||||||
|
|
||||||
// Add the qualifier if there is one (schema.element.qualifier)
|
|
||||||
if (metadataField.getQualifier() != null) {
|
|
||||||
key = key + "." + metadataField.getQualifier();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the language if there is one (schema.element.qualifier[langauge])
|
|
||||||
//if ((value.language != null) && (!"".equals(value.language)))
|
|
||||||
if (value.getLanguage() != null) {
|
|
||||||
key = key + "[" + value.getLanguage() + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the item
|
|
||||||
if (exportAll || okToExport(metadataField)) {
|
|
||||||
// Add authority and confidence if authority is not null
|
|
||||||
String mdValue = value.getValue();
|
|
||||||
if (value.getAuthority() != null && !"".equals(value.getAuthority())) {
|
|
||||||
mdValue += authoritySeparator + value.getAuthority() + authoritySeparator + (value
|
|
||||||
.getConfidence() != -1 ? value.getConfidence() : Choices.CF_ACCEPTED);
|
|
||||||
}
|
|
||||||
line.add(key, mdValue);
|
|
||||||
if (!headings.contains(key)) {
|
|
||||||
headings.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lines.add(line);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an item to the CSV file, from a CSV line of elements
|
|
||||||
*
|
|
||||||
* @param line The line of elements
|
|
||||||
* @throws Exception Thrown if an error occurs when adding the item
|
|
||||||
*/
|
|
||||||
public final void addItem(String line) throws Exception {
|
|
||||||
// Check to see if the last character is a field separator, which hides the last empty column
|
|
||||||
boolean last = false;
|
|
||||||
if (line.endsWith(fieldSeparator)) {
|
|
||||||
// Add a space to the end, then remove it later
|
|
||||||
last = true;
|
|
||||||
line += " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Split up on field separator
|
|
||||||
String[] parts = line.split(escapedFieldSeparator);
|
|
||||||
ArrayList<String> bits = new ArrayList<>();
|
|
||||||
bits.addAll(Arrays.asList(parts));
|
|
||||||
|
|
||||||
// Merge parts with embedded separators
|
|
||||||
boolean alldone = false;
|
|
||||||
while (!alldone) {
|
|
||||||
boolean found = false;
|
|
||||||
int i = 0;
|
|
||||||
for (String part : bits) {
|
|
||||||
int bitcounter = part.length() - part.replaceAll("\"", "").length();
|
|
||||||
if ((part.startsWith("\"")) && ((!part.endsWith("\"")) || ((bitcounter & 1) == 1))) {
|
|
||||||
found = true;
|
|
||||||
String add = bits.get(i) + fieldSeparator + bits.get(i + 1);
|
|
||||||
bits.remove(i);
|
|
||||||
bits.add(i, add);
|
|
||||||
bits.remove(i + 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
alldone = !found;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deal with quotes around the elements
|
|
||||||
int i = 0;
|
|
||||||
for (String part : bits) {
|
|
||||||
if ((part.startsWith("\"")) && (part.endsWith("\""))) {
|
|
||||||
part = part.substring(1, part.length() - 1);
|
|
||||||
bits.set(i, part);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove embedded quotes
|
|
||||||
i = 0;
|
|
||||||
for (String part : bits) {
|
|
||||||
if (part.contains("\"\"")) {
|
|
||||||
part = part.replaceAll("\"\"", "\"");
|
|
||||||
bits.set(i, part);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add elements to a DSpaceCSVLine
|
|
||||||
String id = parts[0].replaceAll("\"", "");
|
|
||||||
DSpaceCSVLine csvLine;
|
|
||||||
|
|
||||||
// Is this an existing item, or a new item (where id = '+')
|
|
||||||
if ("+".equals(id)) {
|
|
||||||
csvLine = new DSpaceCSVLine();
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
csvLine = new DSpaceCSVLine(UUID.fromString(id));
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
System.err.println("Invalid item identifier: " + id);
|
|
||||||
System.err.println("Please check your CSV file for information. " +
|
|
||||||
"Item id must be numeric, or a '+' to add a new item");
|
|
||||||
throw (nfe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the rest of the parts
|
|
||||||
i = 0;
|
|
||||||
for (String part : bits) {
|
|
||||||
if (i > 0) {
|
|
||||||
// Is this a last empty item?
|
|
||||||
if ((last) && (i == headings.size())) {
|
|
||||||
part = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we register that this column was there
|
|
||||||
if (headings.size() < i) {
|
|
||||||
throw new MetadataImportInvalidHeadingException("",
|
|
||||||
MetadataImportInvalidHeadingException.MISSING,
|
|
||||||
i + 1);
|
|
||||||
}
|
|
||||||
csvLine.add(headings.get(i - 1), null);
|
|
||||||
String[] elements = part.split(escapedValueSeparator);
|
|
||||||
for (String element : elements) {
|
|
||||||
if ((element != null) && (!"".equals(element))) {
|
|
||||||
csvLine.add(headings.get(i - 1), element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
lines.add(csvLine);
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the lines in CSV holders
|
|
||||||
*
|
|
||||||
* @return The lines
|
|
||||||
*/
|
|
||||||
public final List<DSpaceCSVLine> getCSVLines() {
|
|
||||||
// Return the lines
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the CSV lines as an array of CSV formatted strings
|
|
||||||
*
|
|
||||||
* @return the array of CSV formatted Strings
|
|
||||||
*/
|
|
||||||
public final String[] getCSVLinesAsStringArray() {
|
|
||||||
// Create the headings line
|
|
||||||
String[] csvLines = new String[counter + 1];
|
|
||||||
csvLines[0] = "id" + fieldSeparator + "collection";
|
|
||||||
List<String> headingsCopy = new ArrayList<>(headings);
|
|
||||||
Collections.sort(headingsCopy);
|
|
||||||
for (String value : headingsCopy) {
|
|
||||||
csvLines[0] = csvLines[0] + fieldSeparator + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<DSpaceCSVLine> i = lines.iterator();
|
|
||||||
int c = 1;
|
|
||||||
while (i.hasNext()) {
|
|
||||||
csvLines[c++] = i.next().toCSV(headingsCopy, fieldSeparator, valueSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
return csvLines;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save the CSV file to the given filename
|
|
||||||
*
|
|
||||||
* @param filename The filename to save the CSV file to
|
|
||||||
* @throws IOException Thrown if an error occurs when writing the file
|
|
||||||
*/
|
|
||||||
public final void save(String filename) throws IOException {
|
|
||||||
// Save the file
|
|
||||||
BufferedWriter out = new BufferedWriter(
|
|
||||||
new OutputStreamWriter(
|
|
||||||
new FileOutputStream(filename), "UTF-8"));
|
|
||||||
for (String csvLine : getCSVLinesAsStringArray()) {
|
|
||||||
out.write(csvLine + "\n");
|
|
||||||
}
|
|
||||||
out.flush();
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is it Ok to export this value? When exportAll is set to false, we don't export
|
|
||||||
* some of the metadata elements.
|
|
||||||
*
|
|
||||||
* The list can be configured via the key ignore-on-export in bulkedit.cfg
|
|
||||||
*
|
|
||||||
* @param md The Metadatum to examine
|
|
||||||
* @return Whether or not it is OK to export this element
|
|
||||||
*/
|
|
||||||
protected boolean okToExport(MetadataField md) {
|
|
||||||
// Now compare with the list to ignore
|
|
||||||
String key = md.getMetadataSchema().getName() + "." + md.getElement();
|
|
||||||
if (md.getQualifier() != null) {
|
|
||||||
key += "." + md.getQualifier();
|
|
||||||
}
|
|
||||||
if (ignore.get(key) != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be OK, so don't ignore
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the headings used in this CSV file
|
|
||||||
*
|
|
||||||
* @return The headings
|
|
||||||
*/
|
|
||||||
public List<String> getHeadings() {
|
|
||||||
return headings;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the csv file as one long formatted string
|
|
||||||
*
|
|
||||||
* @return The formatted String as a csv
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public final String toString() {
|
|
||||||
// Return the csv as one long string
|
|
||||||
StringBuilder csvLines = new StringBuilder();
|
|
||||||
String[] lines = this.getCSVLinesAsStringArray();
|
|
||||||
for (String line : lines) {
|
|
||||||
csvLines.append(line).append("\n");
|
|
||||||
}
|
|
||||||
return csvLines.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthoritySeparator() {
|
|
||||||
return authoritySeparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEscapedAuthoritySeparator() {
|
|
||||||
return escapedAuthoritySeparator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.dspace.authority.AuthorityValue;
|
|
||||||
import org.dspace.authority.factory.AuthorityServiceFactory;
|
|
||||||
import org.dspace.authority.service.AuthorityValueService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility class to store a line from a CSV file
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class DSpaceCSVLine implements Serializable {
|
|
||||||
/**
|
|
||||||
* The item id of the item represented by this line. -1 is for a new item
|
|
||||||
*/
|
|
||||||
private final UUID id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The elements in this line in a hashtable, keyed by the metadata type
|
|
||||||
*/
|
|
||||||
private final Map<String, ArrayList> items;
|
|
||||||
|
|
||||||
protected transient final AuthorityValueService authorityValueService
|
|
||||||
= AuthorityServiceFactory.getInstance().getAuthorityValueService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ensuring that the order-sensible columns of the csv are processed in the correct order
|
|
||||||
*/
|
|
||||||
private transient final Comparator<? super String> headerComparator = new Comparator<String>() {
|
|
||||||
@Override
|
|
||||||
public int compare(String md1, String md2) {
|
|
||||||
// The metadata coming from an external source should be processed after the others
|
|
||||||
AuthorityValue source1 = authorityValueService.getAuthorityValueType(md1);
|
|
||||||
AuthorityValue source2 = authorityValueService.getAuthorityValueType(md2);
|
|
||||||
|
|
||||||
int compare;
|
|
||||||
if (source1 == null && source2 != null) {
|
|
||||||
compare = -1;
|
|
||||||
} else if (source1 != null && source2 == null) {
|
|
||||||
compare = 1;
|
|
||||||
} else {
|
|
||||||
// the order of the rest does not matter
|
|
||||||
compare = md1.compareTo(md2);
|
|
||||||
}
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new CSV line
|
|
||||||
*
|
|
||||||
* @param itemId The item ID of the line
|
|
||||||
*/
|
|
||||||
public DSpaceCSVLine(UUID itemId) {
|
|
||||||
// Store the ID + separator, and initialise the hashtable
|
|
||||||
this.id = itemId;
|
|
||||||
items = new TreeMap<>(headerComparator);
|
|
||||||
// this.items = new HashMap<String, ArrayList>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new CSV line for a new item
|
|
||||||
*/
|
|
||||||
public DSpaceCSVLine() {
|
|
||||||
// Set the ID to be null, and initialise the hashtable
|
|
||||||
this.id = null;
|
|
||||||
this.items = new TreeMap<>(headerComparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the item ID that this line represents
|
|
||||||
*
|
|
||||||
* @return The item ID
|
|
||||||
*/
|
|
||||||
public UUID getID() {
|
|
||||||
// Return the ID
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new metadata value to this line
|
|
||||||
*
|
|
||||||
* @param key The metadata key (e.g. dc.contributor.author)
|
|
||||||
* @param value The metadata value
|
|
||||||
*/
|
|
||||||
public void add(String key, String value) {
|
|
||||||
// Create the array list if we need to
|
|
||||||
if (items.get(key) == null) {
|
|
||||||
items.put(key, new ArrayList<String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the item if it is not null
|
|
||||||
if (value != null) {
|
|
||||||
items.get(key).add(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all the values that match the given metadata key. Will be null if none exist.
|
|
||||||
*
|
|
||||||
* @param key The metadata key
|
|
||||||
* @return All the elements that match
|
|
||||||
*/
|
|
||||||
public List<String> get(String key) {
|
|
||||||
// Return any relevant values
|
|
||||||
return items.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get any action associated with this line
|
|
||||||
*
|
|
||||||
* @return The action (may be blank, 'withdraw', 'reinstate' or 'delete')
|
|
||||||
*/
|
|
||||||
public String getAction() {
|
|
||||||
if (items.containsKey("action")) {
|
|
||||||
ArrayList actions = items.get("action");
|
|
||||||
if (actions.size() > 0) {
|
|
||||||
return ((String) actions.get(0)).trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all the metadata keys that are represented in this line
|
|
||||||
*
|
|
||||||
* @return An enumeration of all the keys
|
|
||||||
*/
|
|
||||||
public Set<String> keys() {
|
|
||||||
// Return the keys
|
|
||||||
return items.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write this line out as a CSV formatted string, in the order given by the headings provided
|
|
||||||
*
|
|
||||||
* @param headings The headings which define the order the elements must be presented in
|
|
||||||
* @param fieldSeparator separator between metadata fields
|
|
||||||
* @param valueSeparator separator between metadata values (within a field)
|
|
||||||
* @return The CSV formatted String
|
|
||||||
*/
|
|
||||||
protected String toCSV(List<String> headings, String fieldSeparator, String valueSeparator) {
|
|
||||||
StringBuilder bits = new StringBuilder();
|
|
||||||
|
|
||||||
// Add the id
|
|
||||||
bits.append("\"").append(id).append("\"").append(fieldSeparator);
|
|
||||||
bits.append(valueToCSV(items.get("collection"), valueSeparator));
|
|
||||||
|
|
||||||
// Add the rest of the elements
|
|
||||||
for (String heading : headings) {
|
|
||||||
bits.append(fieldSeparator);
|
|
||||||
List<String> values = items.get(heading);
|
|
||||||
if (values != null && !"collection".equals(heading)) {
|
|
||||||
bits.append(valueToCSV(values, valueSeparator));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bits.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal method to create a CSV formatted String joining a given set of elements
|
|
||||||
*
|
|
||||||
* @param values The values to create the string from
|
|
||||||
* @param valueSeparator value separator
|
|
||||||
* @return The line as a CSV formatted String
|
|
||||||
*/
|
|
||||||
protected String valueToCSV(List<String> values, String valueSeparator) {
|
|
||||||
// Check there is some content
|
|
||||||
if (values == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get on with the work
|
|
||||||
String s;
|
|
||||||
if (values.size() == 1) {
|
|
||||||
s = values.get(0);
|
|
||||||
} else {
|
|
||||||
// Concatenate any fields together
|
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
|
|
||||||
for (String value : values) {
|
|
||||||
if (str.length() > 0) {
|
|
||||||
str.append(valueSeparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
str.append(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
s = str.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace internal quotes with two sets of quotes
|
|
||||||
return "\"" + s.replaceAll("\"", "\"\"") + "\"";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,278 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata exporter to allow the batch export of metadata into a file
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class MetadataExport {
|
|
||||||
/**
|
|
||||||
* The items to export
|
|
||||||
*/
|
|
||||||
protected Iterator<Item> toExport;
|
|
||||||
|
|
||||||
protected ItemService itemService;
|
|
||||||
|
|
||||||
protected Context context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to export all metadata, or just normally edited metadata
|
|
||||||
*/
|
|
||||||
protected boolean exportAll;
|
|
||||||
|
|
||||||
protected MetadataExport() {
|
|
||||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up a new metadata export
|
|
||||||
*
|
|
||||||
* @param c The Context
|
|
||||||
* @param toExport The ItemIterator of items to export
|
|
||||||
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
|
|
||||||
*/
|
|
||||||
public MetadataExport(Context c, Iterator<Item> toExport, boolean exportAll) {
|
|
||||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
// Store the export settings
|
|
||||||
this.toExport = toExport;
|
|
||||||
this.exportAll = exportAll;
|
|
||||||
this.context = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to export a community (and sub-communities and collections)
|
|
||||||
*
|
|
||||||
* @param c The Context
|
|
||||||
* @param toExport The Community to export
|
|
||||||
* @param exportAll whether to export all metadata or not (include handle, provenance etc)
|
|
||||||
*/
|
|
||||||
public MetadataExport(Context c, Community toExport, boolean exportAll) {
|
|
||||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Try to export the community
|
|
||||||
this.toExport = buildFromCommunity(c, toExport, 0);
|
|
||||||
this.exportAll = exportAll;
|
|
||||||
this.context = c;
|
|
||||||
} catch (SQLException sqle) {
|
|
||||||
// Something went wrong...
|
|
||||||
System.err.println("Error running exporter:");
|
|
||||||
sqle.printStackTrace(System.err);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build an array list of item ids that are in a community (include sub-communities and collections)
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param community The community to build from
|
|
||||||
* @param indent How many spaces to use when writing out the names of items added
|
|
||||||
* @return The list of item ids
|
|
||||||
* @throws SQLException if database error
|
|
||||||
*/
|
|
||||||
protected Iterator<Item> buildFromCommunity(Context context, Community community, int indent)
|
|
||||||
throws SQLException {
|
|
||||||
// Add all the collections
|
|
||||||
List<Collection> collections = community.getCollections();
|
|
||||||
Iterator<Item> result = null;
|
|
||||||
for (Collection collection : collections) {
|
|
||||||
for (int i = 0; i < indent; i++) {
|
|
||||||
System.out.print(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator<Item> items = itemService.findByCollection(context, collection);
|
|
||||||
result = addItemsToResult(result, items);
|
|
||||||
|
|
||||||
}
|
|
||||||
// Add all the sub-communities
|
|
||||||
List<Community> communities = community.getSubcommunities();
|
|
||||||
for (Community subCommunity : communities) {
|
|
||||||
for (int i = 0; i < indent; i++) {
|
|
||||||
System.out.print(" ");
|
|
||||||
}
|
|
||||||
Iterator<Item> items = buildFromCommunity(context, subCommunity, indent + 1);
|
|
||||||
result = addItemsToResult(result, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Iterator<Item> addItemsToResult(Iterator<Item> result, Iterator<Item> items) {
|
|
||||||
if (result == null) {
|
|
||||||
result = items;
|
|
||||||
} else {
|
|
||||||
result = Iterators.concat(result, items);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the export
|
|
||||||
*
|
|
||||||
* @return the exported CSV lines
|
|
||||||
*/
|
|
||||||
public DSpaceCSV export() {
|
|
||||||
try {
|
|
||||||
Context.Mode originalMode = context.getCurrentMode();
|
|
||||||
context.setMode(Context.Mode.READ_ONLY);
|
|
||||||
|
|
||||||
// Process each item
|
|
||||||
DSpaceCSV csv = new DSpaceCSV(exportAll);
|
|
||||||
while (toExport.hasNext()) {
|
|
||||||
Item item = toExport.next();
|
|
||||||
csv.addItem(item);
|
|
||||||
context.uncacheEntity(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.setMode(originalMode);
|
|
||||||
// Return the results
|
|
||||||
return csv;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Something went wrong...
|
|
||||||
System.err.println("Error exporting to CSV:");
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print the help message
|
|
||||||
*
|
|
||||||
* @param options The command line options the user gave
|
|
||||||
* @param exitCode the system exit code to use
|
|
||||||
*/
|
|
||||||
private static void printHelp(Options options, int exitCode) {
|
|
||||||
// print the help message
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("MetadataExport\n", options);
|
|
||||||
System.out.println("\nfull export: metadataexport -f filename");
|
|
||||||
System.out.println("partial export: metadataexport -i handle -f filename");
|
|
||||||
System.exit(exitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* main method to run the metadata exporter
|
|
||||||
*
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
* @throws Exception if error occurs
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
// Create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
|
|
||||||
options.addOption("f", "file", true, "destination where you want file written");
|
|
||||||
options.addOption("a", "all", false,
|
|
||||||
"include all metadata fields that are not normally changed (e.g. provenance)");
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
CommandLine line = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
line = parser.parse(options, argv);
|
|
||||||
} catch (ParseException pe) {
|
|
||||||
System.err.println("Error with commands.");
|
|
||||||
printHelp(options, 1);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
printHelp(options, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check a filename is given
|
|
||||||
if (!line.hasOption('f')) {
|
|
||||||
System.err.println("Required parameter -f missing!");
|
|
||||||
printHelp(options, 1);
|
|
||||||
}
|
|
||||||
String filename = line.getOptionValue('f');
|
|
||||||
|
|
||||||
// Create a context
|
|
||||||
Context c = new Context(Context.Mode.READ_ONLY);
|
|
||||||
c.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
// The things we'll export
|
|
||||||
Iterator<Item> toExport = null;
|
|
||||||
MetadataExport exporter = null;
|
|
||||||
|
|
||||||
// Export everything?
|
|
||||||
boolean exportAll = line.hasOption('a');
|
|
||||||
|
|
||||||
ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
|
|
||||||
// Check we have an item OK
|
|
||||||
ItemService itemService = contentServiceFactory.getItemService();
|
|
||||||
if (!line.hasOption('i')) {
|
|
||||||
System.out.println("Exporting whole repository WARNING: May take some time!");
|
|
||||||
exporter = new MetadataExport(c, itemService.findAll(c), exportAll);
|
|
||||||
} else {
|
|
||||||
String handle = line.getOptionValue('i');
|
|
||||||
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle);
|
|
||||||
if (dso == null) {
|
|
||||||
System.err.println("Item '" + handle + "' does not resolve to an item in your repository!");
|
|
||||||
printHelp(options, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dso.getType() == Constants.ITEM) {
|
|
||||||
System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")");
|
|
||||||
List<Item> item = new ArrayList<>();
|
|
||||||
item.add((Item) dso);
|
|
||||||
exporter = new MetadataExport(c, item.iterator(), exportAll);
|
|
||||||
} else if (dso.getType() == Constants.COLLECTION) {
|
|
||||||
System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")");
|
|
||||||
Collection collection = (Collection) dso;
|
|
||||||
toExport = itemService.findByCollection(c, collection);
|
|
||||||
exporter = new MetadataExport(c, toExport, exportAll);
|
|
||||||
} else if (dso.getType() == Constants.COMMUNITY) {
|
|
||||||
System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")");
|
|
||||||
exporter = new MetadataExport(c, (Community) dso, exportAll);
|
|
||||||
} else {
|
|
||||||
System.err.println("Error identifying '" + handle + "'");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform the export
|
|
||||||
DSpaceCSV csv = exporter.export();
|
|
||||||
|
|
||||||
// Save the files to the file
|
|
||||||
csv.save(filename);
|
|
||||||
|
|
||||||
// Finish off and tidy up
|
|
||||||
c.restoreAuthSystemState();
|
|
||||||
c.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata importer exception
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class MetadataImportException extends Exception {
|
|
||||||
/**
|
|
||||||
* Instantiate a new MetadataImportException
|
|
||||||
*
|
|
||||||
* @param message the error message
|
|
||||||
*/
|
|
||||||
public MetadataImportException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a new MetadataImportException
|
|
||||||
*
|
|
||||||
* @param message the error message
|
|
||||||
* @param exception the root cause
|
|
||||||
*/
|
|
||||||
public MetadataImportException(String message, Exception exception) {
|
|
||||||
super(message, exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Metadata importer exception
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
*/
|
|
||||||
public class MetadataImportInvalidHeadingException extends Exception {
|
|
||||||
/**
|
|
||||||
* The type of error (schema or element)
|
|
||||||
*/
|
|
||||||
private int type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The bad heading
|
|
||||||
*/
|
|
||||||
private String badHeading;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The column number
|
|
||||||
*/
|
|
||||||
private int column;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error with the schema
|
|
||||||
*/
|
|
||||||
public static final int SCHEMA = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error with the element
|
|
||||||
*/
|
|
||||||
public static final int ELEMENT = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error with a missing header
|
|
||||||
*/
|
|
||||||
public static final int MISSING = 98;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Error with the whole entry
|
|
||||||
*/
|
|
||||||
public static final int ENTRY = 99;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a new MetadataImportInvalidHeadingException
|
|
||||||
*
|
|
||||||
* @param message the error message
|
|
||||||
* @param theType the type of the error
|
|
||||||
* @param theColumn column number
|
|
||||||
*/
|
|
||||||
public MetadataImportInvalidHeadingException(String message, int theType, int theColumn) {
|
|
||||||
super(message);
|
|
||||||
badHeading = message;
|
|
||||||
type = theType;
|
|
||||||
column = theColumn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the type of the exception
|
|
||||||
*
|
|
||||||
* @return the type of the exception
|
|
||||||
*/
|
|
||||||
public String getType() {
|
|
||||||
return "" + type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the heading that was invalid
|
|
||||||
*
|
|
||||||
* @return the invalid heading
|
|
||||||
*/
|
|
||||||
public String getBadHeader() {
|
|
||||||
return badHeading;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the column number that was invalid
|
|
||||||
*
|
|
||||||
* @return the invalid column number
|
|
||||||
*/
|
|
||||||
public int getColumn() {
|
|
||||||
return column;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the exception message
|
|
||||||
*
|
|
||||||
* @return The exception message
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
if (type == SCHEMA) {
|
|
||||||
return "Unknown metadata schema in column " + column + ": " + badHeading;
|
|
||||||
} else if (type == ELEMENT) {
|
|
||||||
return "Unknown metadata element in column " + column + ": " + badHeading;
|
|
||||||
} else if (type == MISSING) {
|
|
||||||
return "Row with missing header: column " + column;
|
|
||||||
} else {
|
|
||||||
return "Bad metadata declaration in column" + column + ": " + badHeading;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>The DSpace Batch Metadata Editor, which uses a CSV file to export/import
|
|
||||||
* item metadata.</p>
|
|
||||||
* <ul>
|
|
||||||
* <li>works on items, communities, collections or the whole site</li>
|
|
||||||
* <li>can also create new items, delete items and withdraw/restore them</li>
|
|
||||||
* <li>cannot export/import bitstreams</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.dspace.app.bulkedit;
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.checker;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.OptionBuilder;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.ParseException;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.dspace.checker.BitstreamDispatcher;
|
|
||||||
import org.dspace.checker.CheckerCommand;
|
|
||||||
import org.dspace.checker.HandleDispatcher;
|
|
||||||
import org.dspace.checker.IteratorDispatcher;
|
|
||||||
import org.dspace.checker.LimitedCountDispatcher;
|
|
||||||
import org.dspace.checker.LimitedDurationDispatcher;
|
|
||||||
import org.dspace.checker.ResultsLogger;
|
|
||||||
import org.dspace.checker.ResultsPruner;
|
|
||||||
import org.dspace.checker.SimpleDispatcher;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.BitstreamService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.Utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command line access to the checksum checker. Options are listed in the
|
|
||||||
* documentation for the main method.
|
|
||||||
*
|
|
||||||
* @author Jim Downing
|
|
||||||
* @author Grace Carpenter
|
|
||||||
* @author Nathan Sarr
|
|
||||||
*/
|
|
||||||
public final class ChecksumChecker {
|
|
||||||
private static final Logger LOG = Logger.getLogger(ChecksumChecker.class);
|
|
||||||
|
|
||||||
private static final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blanked off constructor, this class should be used as a command line
|
|
||||||
* tool.
|
|
||||||
*/
|
|
||||||
private ChecksumChecker() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command line access to the checksum package.
|
|
||||||
*
|
|
||||||
* <dl>
|
|
||||||
* <dt>-h</dt>
|
|
||||||
* <dd>Print help on command line options</dd>
|
|
||||||
* <dt>-l</dt>
|
|
||||||
* <dd>loop through bitstreams once</dd>
|
|
||||||
* <dt>-L</dt>
|
|
||||||
* <dd>loop continuously through bitstreams</dd>
|
|
||||||
* <dt>-d</dt>
|
|
||||||
* <dd>specify duration of process run</dd>
|
|
||||||
* <dt>-b</dt>
|
|
||||||
* <dd>specify bitstream IDs</dd>
|
|
||||||
* <dt>-a [handle_id]</dt>
|
|
||||||
* <dd>check anything by handle</dd>
|
|
||||||
* <dt>-e</dt>
|
|
||||||
* <dd>Report only errors in the logs</dd>
|
|
||||||
* <dt>-p</dt>
|
|
||||||
* <dd>Don't prune results before running checker</dd>
|
|
||||||
* </dl>
|
|
||||||
*
|
|
||||||
* @param args the command line arguments given
|
|
||||||
* @throws SQLException if error
|
|
||||||
*/
|
|
||||||
public static void main(String[] args) throws SQLException {
|
|
||||||
// set up command line parser
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
CommandLine line = null;
|
|
||||||
|
|
||||||
// create an options object and populate it
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("l", "looping", false, "Loop once through bitstreams");
|
|
||||||
options.addOption("L", "continuous", false,
|
|
||||||
"Loop continuously through bitstreams");
|
|
||||||
options.addOption("h", "help", false, "Help");
|
|
||||||
options.addOption("d", "duration", true, "Checking duration");
|
|
||||||
options.addOption("c", "count", true, "Check count");
|
|
||||||
options.addOption("a", "handle", true, "Specify a handle to check");
|
|
||||||
options.addOption("v", "verbose", false, "Report all processing");
|
|
||||||
|
|
||||||
OptionBuilder.withArgName("bitstream-ids").hasArgs().withDescription(
|
|
||||||
"Space separated list of bitstream ids");
|
|
||||||
Option useBitstreamIds = OptionBuilder.create('b');
|
|
||||||
|
|
||||||
options.addOption(useBitstreamIds);
|
|
||||||
|
|
||||||
options.addOption("p", "prune", false, "Prune configuration file");
|
|
||||||
options.addOption(OptionBuilder
|
|
||||||
.withArgName("prune")
|
|
||||||
.hasOptionalArgs(1)
|
|
||||||
.withDescription(
|
|
||||||
"Prune old results (optionally using specified properties file for configuration)")
|
|
||||||
.create('p'));
|
|
||||||
|
|
||||||
try {
|
|
||||||
line = parser.parse(options, args);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
LOG.fatal(e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// user asks for help
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
printHelp(options);
|
|
||||||
}
|
|
||||||
Context context = null;
|
|
||||||
try {
|
|
||||||
context = new Context();
|
|
||||||
|
|
||||||
|
|
||||||
// Prune stage
|
|
||||||
if (line.hasOption('p')) {
|
|
||||||
ResultsPruner rp = null;
|
|
||||||
try {
|
|
||||||
rp = (line.getOptionValue('p') != null) ? ResultsPruner
|
|
||||||
.getPruner(context, line.getOptionValue('p')) : ResultsPruner
|
|
||||||
.getDefaultPruner(context);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
LOG.error("File not found", e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
int count = rp.prune();
|
|
||||||
System.out.println("Pruned " + count
|
|
||||||
+ " old results from the database.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Date processStart = Calendar.getInstance().getTime();
|
|
||||||
|
|
||||||
BitstreamDispatcher dispatcher = null;
|
|
||||||
|
|
||||||
// process should loop infinitely through
|
|
||||||
// most_recent_checksum table
|
|
||||||
if (line.hasOption('l')) {
|
|
||||||
dispatcher = new SimpleDispatcher(context, processStart, false);
|
|
||||||
} else if (line.hasOption('L')) {
|
|
||||||
dispatcher = new SimpleDispatcher(context, processStart, true);
|
|
||||||
} else if (line.hasOption('b')) {
|
|
||||||
// check only specified bitstream(s)
|
|
||||||
String[] ids = line.getOptionValues('b');
|
|
||||||
List<Bitstream> bitstreams = new ArrayList<>(ids.length);
|
|
||||||
|
|
||||||
for (int i = 0; i < ids.length; i++) {
|
|
||||||
try {
|
|
||||||
bitstreams.add(bitstreamService.find(context, UUID.fromString(ids[i])));
|
|
||||||
} catch (NumberFormatException nfe) {
|
|
||||||
System.err.println("The following argument: " + ids[i]
|
|
||||||
+ " is not an integer");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dispatcher = new IteratorDispatcher(bitstreams.iterator());
|
|
||||||
} else if (line.hasOption('a')) {
|
|
||||||
dispatcher = new HandleDispatcher(context, line.getOptionValue('a'));
|
|
||||||
} else if (line.hasOption('d')) {
|
|
||||||
// run checker process for specified duration
|
|
||||||
try {
|
|
||||||
dispatcher = new LimitedDurationDispatcher(
|
|
||||||
new SimpleDispatcher(context, processStart, true), new Date(
|
|
||||||
System.currentTimeMillis()
|
|
||||||
+ Utils.parseDuration(line
|
|
||||||
.getOptionValue('d'))));
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.fatal("Couldn't parse " + line.getOptionValue('d')
|
|
||||||
+ " as a duration: ", e);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
} else if (line.hasOption('c')) {
|
|
||||||
int count = Integer.valueOf(line.getOptionValue('c'));
|
|
||||||
|
|
||||||
// run checker process for specified number of bitstreams
|
|
||||||
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
|
|
||||||
context, processStart, false), count);
|
|
||||||
} else {
|
|
||||||
dispatcher = new LimitedCountDispatcher(new SimpleDispatcher(
|
|
||||||
context, processStart, false), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResultsLogger logger = new ResultsLogger(processStart);
|
|
||||||
CheckerCommand checker = new CheckerCommand(context);
|
|
||||||
// verbose reporting
|
|
||||||
if (line.hasOption('v')) {
|
|
||||||
checker.setReportVerbose(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
checker.setProcessStartDate(processStart);
|
|
||||||
checker.setDispatcher(dispatcher);
|
|
||||||
checker.setCollector(logger);
|
|
||||||
checker.process();
|
|
||||||
context.complete();
|
|
||||||
context = null;
|
|
||||||
} finally {
|
|
||||||
if (context != null) {
|
|
||||||
context.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print the help options for the user
|
|
||||||
*
|
|
||||||
* @param options that are available for the user
|
|
||||||
*/
|
|
||||||
private static void printHelp(Options options) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
|
|
||||||
myhelp.printHelp("Checksum Checker\n", options);
|
|
||||||
System.out.println("\nSpecify a duration for checker process, using s(seconds),"
|
|
||||||
+ "m(minutes), or h(hours): ChecksumChecker -d 30s"
|
|
||||||
+ " OR ChecksumChecker -d 30m"
|
|
||||||
+ " OR ChecksumChecker -d 2h");
|
|
||||||
System.out.println("\nSpecify bitstream IDs: ChecksumChecker -b 13 15 17 20");
|
|
||||||
System.out.println("\nLoop once through all bitstreams: "
|
|
||||||
+ "ChecksumChecker -l");
|
|
||||||
System.out.println("\nLoop continuously through all bitstreams: ChecksumChecker -L");
|
|
||||||
System.out.println("\nCheck a defined number of bitstreams: ChecksumChecker -c 10");
|
|
||||||
System.out.println("\nReport all processing (verbose)(default reports only errors): ChecksumChecker -v");
|
|
||||||
System.out.println("\nDefault (no arguments) is equivalent to '-c 1'");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,19 +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/
|
|
||||||
|
|
||||||
-->
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>org.dspace.app.checker Package Documentation</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<p>org.dspace.app.checker provides user interfaces to the org.dspace.checker
|
|
||||||
package. Command line options are detailed in the ChecksumChecker javadoc.
|
|
||||||
</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.configuration;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
|
|
||||||
import org.dspace.kernel.config.SpringLoader;
|
|
||||||
import org.dspace.services.ConfigurationService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Kevin Van de Velde (kevin at atmire dot com)
|
|
||||||
*/
|
|
||||||
public class APISpringLoader implements SpringLoader {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getResourcePaths(ConfigurationService configurationService) {
|
|
||||||
StringBuffer filePath = new StringBuffer();
|
|
||||||
filePath.append(configurationService.getProperty("dspace.dir"));
|
|
||||||
filePath.append(File.separator);
|
|
||||||
filePath.append("config");
|
|
||||||
filePath.append(File.separator);
|
|
||||||
filePath.append("spring");
|
|
||||||
filePath.append(File.separator);
|
|
||||||
filePath.append("api");
|
|
||||||
filePath.append(File.separator);
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new String[] {new File(filePath.toString()).toURI().toURL().toString() + XML_SUFFIX};
|
|
||||||
} catch (MalformedURLException e) {
|
|
||||||
return new String[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,484 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.harvest;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
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.PosixParser;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.CollectionService;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.EPersonService;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.harvest.HarvestedCollection;
|
|
||||||
import org.dspace.harvest.HarvestingException;
|
|
||||||
import org.dspace.harvest.OAIHarvester;
|
|
||||||
import org.dspace.harvest.factory.HarvestServiceFactory;
|
|
||||||
import org.dspace.harvest.service.HarvestedCollectionService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test class for harvested collections.
|
|
||||||
*
|
|
||||||
* @author Alexey Maslov
|
|
||||||
*/
|
|
||||||
public class Harvest {
|
|
||||||
private static Context context;
|
|
||||||
|
|
||||||
private static final HarvestedCollectionService harvestedCollectionService =
|
|
||||||
HarvestServiceFactory.getInstance().getHarvestedCollectionService();
|
|
||||||
private static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
|
||||||
private static final CollectionService collectionService =
|
|
||||||
ContentServiceFactory.getInstance().getCollectionService();
|
|
||||||
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("p", "purge", false, "delete all items in the collection");
|
|
||||||
options.addOption("r", "run", false, "run the standard harvest procedure");
|
|
||||||
options.addOption("g", "ping", false, "test the OAI server and set");
|
|
||||||
options.addOption("o", "once", false, "run the harvest procedure with specified parameters");
|
|
||||||
options.addOption("s", "setup", false, "Set the collection up for harvesting");
|
|
||||||
options.addOption("S", "start", false, "start the harvest loop");
|
|
||||||
options.addOption("R", "reset", false, "reset harvest status on all collections");
|
|
||||||
options.addOption("P", "purge", false, "purge all harvestable collections");
|
|
||||||
|
|
||||||
|
|
||||||
options.addOption("e", "eperson", true,
|
|
||||||
"eperson");
|
|
||||||
options.addOption("c", "collection", true,
|
|
||||||
"harvesting collection (handle or id)");
|
|
||||||
options.addOption("t", "type", true,
|
|
||||||
"type of harvesting (0 for none)");
|
|
||||||
options.addOption("a", "address", true,
|
|
||||||
"address of the OAI-PMH server");
|
|
||||||
options.addOption("i", "oai_set_id", true,
|
|
||||||
"id of the PMH set representing the harvested collection");
|
|
||||||
options.addOption("m", "metadata_format", true,
|
|
||||||
"the name of the desired metadata format for harvesting, resolved to namespace and " +
|
|
||||||
"crosswalk in dspace.cfg");
|
|
||||||
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
String command = null;
|
|
||||||
String eperson = null;
|
|
||||||
String collection = null;
|
|
||||||
String oaiSource = null;
|
|
||||||
String oaiSetID = null;
|
|
||||||
String metadataKey = null;
|
|
||||||
int harvestType = 0;
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("Harvest\n", options);
|
|
||||||
System.out.println("\nPING OAI server: Harvest -g -a oai_source -i oai_set_id");
|
|
||||||
System.out.println(
|
|
||||||
"RUNONCE harvest with arbitrary options: Harvest -o -e eperson -c collection -t harvest_type -a " +
|
|
||||||
"oai_source -i oai_set_id -m metadata_format");
|
|
||||||
System.out.println(
|
|
||||||
"SETUP a collection for harvesting: Harvest -s -c collection -t harvest_type -a oai_source -i " +
|
|
||||||
"oai_set_id -m metadata_format");
|
|
||||||
System.out.println("RUN harvest once: Harvest -r -e eperson -c collection");
|
|
||||||
System.out.println("START harvest scheduler: Harvest -S");
|
|
||||||
System.out.println("RESET all harvest status: Harvest -R");
|
|
||||||
System.out.println("PURGE a collection of items and settings: Harvest -p -e eperson -c collection");
|
|
||||||
System.out.println("PURGE all harvestable collections: Harvest -P -e eperson");
|
|
||||||
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('s')) {
|
|
||||||
command = "config";
|
|
||||||
}
|
|
||||||
if (line.hasOption('p')) {
|
|
||||||
command = "purge";
|
|
||||||
}
|
|
||||||
if (line.hasOption('r')) {
|
|
||||||
command = "run";
|
|
||||||
}
|
|
||||||
if (line.hasOption('g')) {
|
|
||||||
command = "ping";
|
|
||||||
}
|
|
||||||
if (line.hasOption('o')) {
|
|
||||||
command = "runOnce";
|
|
||||||
}
|
|
||||||
if (line.hasOption('S')) {
|
|
||||||
command = "start";
|
|
||||||
}
|
|
||||||
if (line.hasOption('R')) {
|
|
||||||
command = "reset";
|
|
||||||
}
|
|
||||||
if (line.hasOption('P')) {
|
|
||||||
command = "purgeAll";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (line.hasOption('e')) {
|
|
||||||
eperson = line.getOptionValue('e');
|
|
||||||
}
|
|
||||||
if (line.hasOption('c')) {
|
|
||||||
collection = line.getOptionValue('c');
|
|
||||||
}
|
|
||||||
if (line.hasOption('t')) {
|
|
||||||
harvestType = Integer.parseInt(line.getOptionValue('t'));
|
|
||||||
} else {
|
|
||||||
harvestType = 0;
|
|
||||||
}
|
|
||||||
if (line.hasOption('a')) {
|
|
||||||
oaiSource = line.getOptionValue('a');
|
|
||||||
}
|
|
||||||
if (line.hasOption('i')) {
|
|
||||||
oaiSetID = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
if (line.hasOption('m')) {
|
|
||||||
metadataKey = line.getOptionValue('m');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Instantiate our class
|
|
||||||
Harvest harvester = new Harvest();
|
|
||||||
harvester.context = new Context(Context.Mode.BATCH_EDIT);
|
|
||||||
|
|
||||||
|
|
||||||
// Check our options
|
|
||||||
if (command == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - no parameters specified (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
} else if ("run".equals(command)) {
|
|
||||||
// Run a single harvest cycle on a collection using saved settings.
|
|
||||||
if (collection == null || eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a target collection and eperson must be provided");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
harvester.runHarvest(collection, eperson);
|
|
||||||
} else if ("start".equals(command)) {
|
|
||||||
// start the harvest loop
|
|
||||||
startHarvester();
|
|
||||||
} else if ("reset".equals(command)) {
|
|
||||||
// reset harvesting status
|
|
||||||
resetHarvesting();
|
|
||||||
} else if ("purgeAll".equals(command)) {
|
|
||||||
// purge all collections that are set up for harvesting (obviously for testing purposes only)
|
|
||||||
if (eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - an eperson must be provided");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
|
|
||||||
for (HarvestedCollection harvestedCollection : harvestedCollections) {
|
|
||||||
System.out.println(
|
|
||||||
"Purging the following collections (deleting items and resetting harvest status): " +
|
|
||||||
harvestedCollection
|
|
||||||
.getCollection().getID().toString());
|
|
||||||
harvester.purgeCollection(harvestedCollection.getCollection().getID().toString(), eperson);
|
|
||||||
}
|
|
||||||
context.complete();
|
|
||||||
} else if ("purge".equals(command)) {
|
|
||||||
// Delete all items in a collection. Useful for testing fresh harvests.
|
|
||||||
if (collection == null || eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a target collection and eperson must be provided");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
harvester.purgeCollection(collection, eperson);
|
|
||||||
context.complete();
|
|
||||||
|
|
||||||
//TODO: implement this... remove all items and remember to unset "last-harvested" settings
|
|
||||||
} else if ("config".equals(command)) {
|
|
||||||
// Configure a collection with the three main settings
|
|
||||||
if (collection == null) {
|
|
||||||
System.out.println("Error - a target collection must be provided");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
if (oaiSource == null || oaiSetID == null) {
|
|
||||||
System.out.println("Error - both the OAI server address and OAI set id must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
if (metadataKey == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a metadata key (commonly the prefix) must be specified for this collection");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
harvester.configureCollection(collection, harvestType, oaiSource, oaiSetID, metadataKey);
|
|
||||||
} else if ("ping".equals(command)) {
|
|
||||||
if (oaiSource == null || oaiSetID == null) {
|
|
||||||
System.out.println("Error - both the OAI server address and OAI set id must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pingResponder(oaiSource, oaiSetID, metadataKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Resolve the ID into a collection and check to see if its harvesting options are set. If so, return
|
|
||||||
* the collection, if not, bail out.
|
|
||||||
*/
|
|
||||||
private Collection resolveCollection(String collectionID) {
|
|
||||||
|
|
||||||
DSpaceObject dso;
|
|
||||||
Collection targetCollection = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// is the ID a handle?
|
|
||||||
if (collectionID != null) {
|
|
||||||
if (collectionID.indexOf('/') != -1) {
|
|
||||||
// string has a / so it must be a handle - try and resolve it
|
|
||||||
dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, collectionID);
|
|
||||||
|
|
||||||
// resolved, now make sure it's a collection
|
|
||||||
if (dso == null || dso.getType() != Constants.COLLECTION) {
|
|
||||||
targetCollection = null;
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
targetCollection = collectionService.find(context, UUID.fromString(collectionID));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// was the collection valid?
|
|
||||||
if (targetCollection == null) {
|
|
||||||
System.out.println("Cannot resolve " + collectionID + " to collection");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} catch (SQLException se) {
|
|
||||||
se.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void configureCollection(String collectionID, int type, String oaiSource, String oaiSetId,
|
|
||||||
String mdConfigId) {
|
|
||||||
System.out.println("Running: configure collection");
|
|
||||||
|
|
||||||
Collection collection = resolveCollection(collectionID);
|
|
||||||
System.out.println(collection.getID());
|
|
||||||
|
|
||||||
try {
|
|
||||||
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
|
|
||||||
if (hc == null) {
|
|
||||||
hc = harvestedCollectionService.create(context, collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
hc.setHarvestParams(type, oaiSource, oaiSetId, mdConfigId);
|
|
||||||
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
|
|
||||||
harvestedCollectionService.update(context, hc);
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
context.complete();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("Changes could not be committed");
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
} finally {
|
|
||||||
if (context != null) {
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Purges a collection of all harvest-related data and settings. All items in the collection will be deleted.
|
|
||||||
*
|
|
||||||
* @param collectionID
|
|
||||||
* @param email
|
|
||||||
*/
|
|
||||||
private void purgeCollection(String collectionID, String email) {
|
|
||||||
System.out.println(
|
|
||||||
"Purging collection of all items and resetting last_harvested and harvest_message: " + collectionID);
|
|
||||||
Collection collection = resolveCollection(collectionID);
|
|
||||||
|
|
||||||
try {
|
|
||||||
EPerson eperson = ePersonService.findByEmail(context, email);
|
|
||||||
context.setCurrentUser(eperson);
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
Iterator<Item> it = itemService.findByCollection(context, collection);
|
|
||||||
int i = 0;
|
|
||||||
while (it.hasNext()) {
|
|
||||||
i++;
|
|
||||||
Item item = it.next();
|
|
||||||
System.out.println("Deleting: " + item.getHandle());
|
|
||||||
collectionService.removeItem(context, collection, item);
|
|
||||||
context.uncacheEntity(item);// Dispatch events every 50 items
|
|
||||||
if (i % 50 == 0) {
|
|
||||||
context.dispatchEvents();
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
|
|
||||||
if (hc != null) {
|
|
||||||
hc.setLastHarvested(null);
|
|
||||||
hc.setHarvestMessage("");
|
|
||||||
hc.setHarvestStatus(HarvestedCollection.STATUS_READY);
|
|
||||||
hc.setHarvestStartTime(null);
|
|
||||||
harvestedCollectionService.update(context, hc);
|
|
||||||
}
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
context.dispatchEvents();
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("Changes could not be committed");
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
} finally {
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run a single harvest cycle on the specified collection under the authorization of the supplied EPerson
|
|
||||||
*/
|
|
||||||
private void runHarvest(String collectionID, String email) {
|
|
||||||
System.out.println("Running: a harvest cycle on " + collectionID);
|
|
||||||
|
|
||||||
System.out.print("Initializing the harvester... ");
|
|
||||||
OAIHarvester harvester = null;
|
|
||||||
try {
|
|
||||||
Collection collection = resolveCollection(collectionID);
|
|
||||||
HarvestedCollection hc = harvestedCollectionService.find(context, collection);
|
|
||||||
harvester = new OAIHarvester(context, collection, hc);
|
|
||||||
System.out.println("success. ");
|
|
||||||
} catch (HarvestingException hex) {
|
|
||||||
System.out.print("failed. ");
|
|
||||||
System.out.println(hex.getMessage());
|
|
||||||
throw new IllegalStateException("Unable to harvest", hex);
|
|
||||||
} catch (SQLException se) {
|
|
||||||
System.out.print("failed. ");
|
|
||||||
System.out.println(se.getMessage());
|
|
||||||
throw new IllegalStateException("Unable to access database", se);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Harvest will not work for an anonymous user
|
|
||||||
EPerson eperson = ePersonService.findByEmail(context, email);
|
|
||||||
System.out.println("Harvest started... ");
|
|
||||||
context.setCurrentUser(eperson);
|
|
||||||
harvester.runHarvest();
|
|
||||||
context.complete();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new IllegalStateException("Failed to run harvester", e);
|
|
||||||
} catch (AuthorizeException e) {
|
|
||||||
throw new IllegalStateException("Failed to run harvester", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Failed to run harvester", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("Harvest complete. ");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets harvest_status and harvest_start_time flags for all collections that have a row in the
|
|
||||||
* harvested_collections table
|
|
||||||
*/
|
|
||||||
private static void resetHarvesting() {
|
|
||||||
System.out.print("Resetting harvest status flag on all collections... ");
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<HarvestedCollection> harvestedCollections = harvestedCollectionService.findAll(context);
|
|
||||||
for (HarvestedCollection harvestedCollection : harvestedCollections) {
|
|
||||||
//hc.setHarvestResult(null,"");
|
|
||||||
harvestedCollection.setHarvestStartTime(null);
|
|
||||||
harvestedCollection.setHarvestStatus(HarvestedCollection.STATUS_READY);
|
|
||||||
harvestedCollectionService.update(context, harvestedCollection);
|
|
||||||
}
|
|
||||||
System.out.println("success. ");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println("failed. ");
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts up the harvest scheduler. Terminating this process will stop the scheduler.
|
|
||||||
*/
|
|
||||||
private static void startHarvester() {
|
|
||||||
try {
|
|
||||||
System.out.print("Starting harvest loop... ");
|
|
||||||
HarvestServiceFactory.getInstance().getHarvestSchedulingService().startNewScheduler();
|
|
||||||
System.out.println("running. ");
|
|
||||||
} catch (Exception ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See if the responder is alive and working.
|
|
||||||
*
|
|
||||||
* @param server address of the responder's host.
|
|
||||||
* @param set name of an item set.
|
|
||||||
* @param metadataFormat local prefix name, or null for "dc".
|
|
||||||
*/
|
|
||||||
private static void pingResponder(String server, String set, String metadataFormat) {
|
|
||||||
List<String> errors;
|
|
||||||
|
|
||||||
System.out.print("Testing basic PMH access: ");
|
|
||||||
errors = OAIHarvester.verifyOAIharvester(server, set,
|
|
||||||
(null != metadataFormat) ? metadataFormat : "dc", false);
|
|
||||||
if (errors.isEmpty()) {
|
|
||||||
System.out.println("OK");
|
|
||||||
} else {
|
|
||||||
for (String error : errors) {
|
|
||||||
System.err.println(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.print("Testing ORE support: ");
|
|
||||||
errors = OAIHarvester.verifyOAIharvester(server, set,
|
|
||||||
(null != metadataFormat) ? metadataFormat : "dc", true);
|
|
||||||
if (errors.isEmpty()) {
|
|
||||||
System.out.println("OK");
|
|
||||||
} else {
|
|
||||||
for (String error : errors) {
|
|
||||||
System.err.println(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemexport;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
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.PosixParser;
|
|
||||||
import org.dspace.app.itemexport.factory.ItemExportServiceFactory;
|
|
||||||
import org.dspace.app.itemexport.service.ItemExportService;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.CollectionService;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.handle.service.HandleService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Item exporter to create simple AIPs for DSpace content. Currently exports
|
|
||||||
* individual items, or entire collections. For instructions on use, see
|
|
||||||
* printUsage() method.
|
|
||||||
* <P>
|
|
||||||
* ItemExport creates the simple AIP package that the importer also uses. It
|
|
||||||
* consists of:
|
|
||||||
* <P>
|
|
||||||
* /exportdir/42/ (one directory per item) / dublin_core.xml - qualified dublin
|
|
||||||
* core in RDF schema / contents - text file, listing one file per line / file1
|
|
||||||
* - files contained in the item / file2 / ...
|
|
||||||
* <P>
|
|
||||||
* issues -doesn't handle special characters in metadata (needs to turn {@code &'s} into
|
|
||||||
* {@code &}, etc.)
|
|
||||||
* <P>
|
|
||||||
* Modified by David Little, UCSD Libraries 12/21/04 to allow the registration
|
|
||||||
* of files (bitstreams) into DSpace.
|
|
||||||
*
|
|
||||||
* @author David Little
|
|
||||||
* @author Jay Paz
|
|
||||||
*/
|
|
||||||
public class ItemExportCLITool {
|
|
||||||
|
|
||||||
protected static ItemExportService itemExportService = ItemExportServiceFactory.getInstance()
|
|
||||||
.getItemExportService();
|
|
||||||
protected static HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
|
|
||||||
protected static ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
protected static CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private ItemExportCLITool() { }
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("t", "type", true, "type: COLLECTION or ITEM");
|
|
||||||
options.addOption("i", "id", true, "ID or handle of thing to export");
|
|
||||||
options.addOption("d", "dest", true,
|
|
||||||
"destination where you want items to go");
|
|
||||||
options.addOption("m", "migrate", false,
|
|
||||||
"export for migration (remove handle and metadata that will be re-created in new system)");
|
|
||||||
options.addOption("n", "number", true,
|
|
||||||
"sequence number to begin exporting items with");
|
|
||||||
options.addOption("z", "zip", true, "export as zip file (specify filename e.g. export.zip)");
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
// as pointed out by Peter Dietz this provides similar functionality to export metadata
|
|
||||||
// but it is needed since it directly exports to Simple Archive Format (SAF)
|
|
||||||
options.addOption("x", "exclude-bitstreams", false, "do not export bitstreams");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
String typeString = null;
|
|
||||||
String destDirName = null;
|
|
||||||
String myIDString = null;
|
|
||||||
int seqStart = -1;
|
|
||||||
int myType = -1;
|
|
||||||
|
|
||||||
Item myItem = null;
|
|
||||||
Collection mycollection = null;
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("ItemExport\n", options);
|
|
||||||
System.out
|
|
||||||
.println("\nfull collection: ItemExport -t COLLECTION -i ID -d dest -n number");
|
|
||||||
System.out
|
|
||||||
.println("singleitem: ItemExport -t ITEM -i ID -d dest -n number");
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('t')) { // type
|
|
||||||
typeString = line.getOptionValue('t');
|
|
||||||
|
|
||||||
if ("ITEM".equals(typeString)) {
|
|
||||||
myType = Constants.ITEM;
|
|
||||||
} else if ("COLLECTION".equals(typeString)) {
|
|
||||||
myType = Constants.COLLECTION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('i')) { // id
|
|
||||||
myIDString = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('d')) { // dest
|
|
||||||
destDirName = line.getOptionValue('d');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('n')) { // number
|
|
||||||
seqStart = Integer.parseInt(line.getOptionValue('n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean migrate = false;
|
|
||||||
if (line.hasOption('m')) { // number
|
|
||||||
migrate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean zip = false;
|
|
||||||
String zipFileName = "";
|
|
||||||
if (line.hasOption('z')) {
|
|
||||||
zip = true;
|
|
||||||
zipFileName = line.getOptionValue('z');
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean excludeBitstreams = false;
|
|
||||||
if (line.hasOption('x')) {
|
|
||||||
excludeBitstreams = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// now validate the args
|
|
||||||
if (myType == -1) {
|
|
||||||
System.out
|
|
||||||
.println("type must be either COLLECTION or ITEM (-h for help)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (destDirName == null) {
|
|
||||||
System.out
|
|
||||||
.println("destination directory must be set (-h for help)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seqStart == -1) {
|
|
||||||
System.out
|
|
||||||
.println("sequence start number must be set (-h for help)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myIDString == null) {
|
|
||||||
System.out
|
|
||||||
.println("ID must be set to either a database ID or a handle (-h for help)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Context c = new Context(Context.Mode.READ_ONLY);
|
|
||||||
c.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
if (myType == Constants.ITEM) {
|
|
||||||
// first, is myIDString a handle?
|
|
||||||
if (myIDString.indexOf('/') != -1) {
|
|
||||||
myItem = (Item) handleService.resolveToObject(c, myIDString);
|
|
||||||
|
|
||||||
if ((myItem == null) || (myItem.getType() != Constants.ITEM)) {
|
|
||||||
myItem = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
myItem = itemService.find(c, UUID.fromString(myIDString));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myItem == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error, item cannot be found: " + myIDString);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (myIDString.indexOf('/') != -1) {
|
|
||||||
// has a / must be a handle
|
|
||||||
mycollection = (Collection) handleService.resolveToObject(c,
|
|
||||||
myIDString);
|
|
||||||
|
|
||||||
// ensure it's a collection
|
|
||||||
if ((mycollection == null)
|
|
||||||
|| (mycollection.getType() != Constants.COLLECTION)) {
|
|
||||||
mycollection = null;
|
|
||||||
}
|
|
||||||
} else if (myIDString != null) {
|
|
||||||
mycollection = collectionService.find(c, UUID.fromString(myIDString));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mycollection == null) {
|
|
||||||
System.out.println("Error, collection cannot be found: "
|
|
||||||
+ myIDString);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zip) {
|
|
||||||
Iterator<Item> items;
|
|
||||||
if (myItem != null) {
|
|
||||||
List<Item> myItems = new ArrayList<>();
|
|
||||||
myItems.add(myItem);
|
|
||||||
items = myItems.iterator();
|
|
||||||
} else {
|
|
||||||
System.out.println("Exporting from collection: " + myIDString);
|
|
||||||
items = itemService.findByCollection(c, mycollection);
|
|
||||||
}
|
|
||||||
itemExportService.exportAsZip(c, items, destDirName, zipFileName, seqStart, migrate, excludeBitstreams);
|
|
||||||
} else {
|
|
||||||
if (myItem != null) {
|
|
||||||
// it's only a single item
|
|
||||||
itemExportService
|
|
||||||
.exportItem(c, Collections.singletonList(myItem).iterator(), destDirName, seqStart, migrate,
|
|
||||||
excludeBitstreams);
|
|
||||||
} else {
|
|
||||||
System.out.println("Exporting from collection: " + myIDString);
|
|
||||||
|
|
||||||
// it's a collection, so do a bunch of items
|
|
||||||
Iterator<Item> i = itemService.findByCollection(c, mycollection);
|
|
||||||
itemExportService.exportItem(c, i, destDirName, seqStart, migrate, excludeBitstreams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.complete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemexport;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception that can be thrown when error occur during item export
|
|
||||||
*/
|
|
||||||
public class ItemExportException extends Exception {
|
|
||||||
public static final int EXPORT_TOO_LARGE = 0;
|
|
||||||
|
|
||||||
private int reason;
|
|
||||||
|
|
||||||
public ItemExportException(int r, String message) {
|
|
||||||
super(message);
|
|
||||||
reason = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getReason() {
|
|
||||||
return reason;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemexport.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.itemexport.service.ItemExportService;
|
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract factory to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to
|
|
||||||
* retrieve an implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public abstract class ItemExportServiceFactory {
|
|
||||||
|
|
||||||
public abstract ItemExportService getItemExportService();
|
|
||||||
|
|
||||||
public static ItemExportServiceFactory getInstance() {
|
|
||||||
return DSpaceServicesFactory.getInstance().getServiceManager()
|
|
||||||
.getServiceByName("itemExportServiceFactory", ItemExportServiceFactory.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemexport.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.itemexport.service.ItemExportService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory implementation to get services for the itemexport package, use ItemExportServiceFactory.getInstance() to
|
|
||||||
* retrieve an implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public class ItemExportServiceFactoryImpl extends ItemExportServiceFactory {
|
|
||||||
|
|
||||||
@Autowired(required = true)
|
|
||||||
private ItemExportService itemExportService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemExportService getItemExportService() {
|
|
||||||
return itemExportService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,270 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemexport.service;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.mail.MessagingException;
|
|
||||||
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Item exporter to create simple AIPs for DSpace content. Currently exports
|
|
||||||
* individual items, or entire collections. For instructions on use, see
|
|
||||||
* printUsage() method.
|
|
||||||
* <P>
|
|
||||||
* ItemExport creates the simple AIP package that the importer also uses. It
|
|
||||||
* consists of:
|
|
||||||
* <P>
|
|
||||||
* /exportdir/42/ (one directory per item) / dublin_core.xml - qualified dublin
|
|
||||||
* core in RDF schema / contents - text file, listing one file per line / file1
|
|
||||||
* - files contained in the item / file2 / ...
|
|
||||||
* <P>
|
|
||||||
* issues -doesn't handle special characters in metadata (needs to turn {@code &'s} into
|
|
||||||
* {@code &}, etc.)
|
|
||||||
* <P>
|
|
||||||
* Modified by David Little, UCSD Libraries 12/21/04 to allow the registration
|
|
||||||
* of files (bitstreams) into DSpace.
|
|
||||||
*
|
|
||||||
* @author David Little
|
|
||||||
* @author Jay Paz
|
|
||||||
*/
|
|
||||||
public interface ItemExportService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* used for export download
|
|
||||||
*/
|
|
||||||
public static final String COMPRESSED_EXPORT_MIME_TYPE = "application/zip";
|
|
||||||
|
|
||||||
public void exportItem(Context c, Iterator<Item> i,
|
|
||||||
String destDirName, int seqStart, boolean migrate,
|
|
||||||
boolean excludeBitstreams) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to perform an export and save it as a zip file.
|
|
||||||
*
|
|
||||||
* @param context The DSpace Context
|
|
||||||
* @param items The items to export
|
|
||||||
* @param destDirName The directory to save the export in
|
|
||||||
* @param zipFileName The name to save the zip file as
|
|
||||||
* @param seqStart The first number in the sequence
|
|
||||||
* @param migrate Whether to use the migrate option or not
|
|
||||||
* @param excludeBitstreams Whether to exclude bitstreams or not
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void exportAsZip(Context context, Iterator<Item> items,
|
|
||||||
String destDirName, String zipFileName,
|
|
||||||
int seqStart, boolean migrate,
|
|
||||||
boolean excludeBitstreams) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience methot to create export a single Community, Collection, or
|
|
||||||
* Item
|
|
||||||
*
|
|
||||||
* @param dso - the dspace object to export
|
|
||||||
* @param context - the dspace context
|
|
||||||
* @param migrate Whether to use the migrate option or not
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void createDownloadableExport(DSpaceObject dso,
|
|
||||||
Context context, boolean migrate) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to export a List of dspace objects (Community,
|
|
||||||
* Collection or Item)
|
|
||||||
*
|
|
||||||
* @param dsObjects - List containing dspace objects
|
|
||||||
* @param context - the dspace context
|
|
||||||
* @param migrate Whether to use the migrate option or not
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void createDownloadableExport(List<DSpaceObject> dsObjects,
|
|
||||||
Context context, boolean migrate) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience methot to create export a single Community, Collection, or
|
|
||||||
* Item
|
|
||||||
*
|
|
||||||
* @param dso - the dspace object to export
|
|
||||||
* @param context - the dspace context
|
|
||||||
* @param additionalEmail - cc email to use
|
|
||||||
* @param migrate Whether to use the migrate option or not
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void createDownloadableExport(DSpaceObject dso,
|
|
||||||
Context context, String additionalEmail, boolean migrate) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method to export a List of dspace objects (Community,
|
|
||||||
* Collection or Item)
|
|
||||||
*
|
|
||||||
* @param dsObjects - List containing dspace objects
|
|
||||||
* @param context - the dspace context
|
|
||||||
* @param additionalEmail - cc email to use
|
|
||||||
* @param migrate Whether to use the migrate option or not
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void createDownloadableExport(List<DSpaceObject> dsObjects,
|
|
||||||
Context context, String additionalEmail, boolean migrate) throws Exception;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a file name based on the date and eperson
|
|
||||||
*
|
|
||||||
* @param type Type of object (as string)
|
|
||||||
* @param eperson - eperson who requested export and will be able to download it
|
|
||||||
* @param date - the date the export process was created
|
|
||||||
* @return String representing the file name in the form of
|
|
||||||
* 'export_yyy_MMM_dd_count_epersonID'
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public String assembleFileName(String type, EPerson eperson,
|
|
||||||
Date date) throws Exception;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use config file entry for org.dspace.app.itemexport.download.dir and id
|
|
||||||
* of the eperson to create a download directory name
|
|
||||||
*
|
|
||||||
* @param ePerson - the eperson who requested export archive
|
|
||||||
* @return String representing a directory in the form of
|
|
||||||
* org.dspace.app.itemexport.download.dir/epersonID
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public String getExportDownloadDirectory(EPerson ePerson)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns config file entry for org.dspace.app.itemexport.work.dir
|
|
||||||
*
|
|
||||||
* @return String representing config file entry for
|
|
||||||
* org.dspace.app.itemexport.work.dir
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public String getExportWorkDirectory() throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to read the export archived. Inteded for download.
|
|
||||||
*
|
|
||||||
* @param fileName the name of the file to download
|
|
||||||
* @param eperson the eperson requesting the download
|
|
||||||
* @return an input stream of the file to be downloaded
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public InputStream getExportDownloadInputStream(String fileName,
|
|
||||||
EPerson eperson) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file size of the export archive represented by the file name.
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param fileName name of the file to get the size.
|
|
||||||
* @return size as long
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public long getExportFileSize(Context context, String fileName) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the last modified date of the export archive represented by the file name.
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param fileName name of the file to get the size.
|
|
||||||
* @return date as long
|
|
||||||
* @throws Exception if error
|
|
||||||
* @see java.io.File#lastModified()
|
|
||||||
*/
|
|
||||||
public long getExportFileLastModified(Context context, String fileName)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The file name of the export archive contains the eperson id of the person
|
|
||||||
* who created it When requested for download this method can check if the
|
|
||||||
* person requesting it is the same one that created it
|
|
||||||
*
|
|
||||||
* @param context dspace context
|
|
||||||
* @param fileName the file name to check auths for
|
|
||||||
* @return true if it is the same person false otherwise
|
|
||||||
*/
|
|
||||||
public boolean canDownload(Context context, String fileName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the download directory for the eperson to see if any export
|
|
||||||
* archives are available
|
|
||||||
*
|
|
||||||
* @param eperson EPerson object
|
|
||||||
* @return a list of file names representing export archives that have been
|
|
||||||
* processed
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public List<String> getExportsAvailable(EPerson eperson)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A clean up method that is ran before a new export archive is created. It
|
|
||||||
* uses the config file entry 'org.dspace.app.itemexport.life.span.hours' to
|
|
||||||
* determine if the current exports are too old and need pruging
|
|
||||||
*
|
|
||||||
* @param eperson - the eperson to clean up
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void deleteOldExportArchives(EPerson eperson) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A clean up method that is ran before a new export archive is created. It
|
|
||||||
* uses the config file entry 'org.dspace.app.itemexport.life.span.hours' to
|
|
||||||
* determine if the current exports are too old and need purgeing
|
|
||||||
* Removes all old exports, not just those for the person doing the export.
|
|
||||||
*
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void deleteOldExportArchives() throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since the archive is created in a new thread we are unable to communicate
|
|
||||||
* with calling method about success or failure. We accomplis this
|
|
||||||
* communication with email instead. Send a success email once the export
|
|
||||||
* archive is complete and ready for download
|
|
||||||
*
|
|
||||||
* @param context - the current Context
|
|
||||||
* @param eperson - eperson to send the email to
|
|
||||||
* @param fileName - the file name to be downloaded. It is added to the url in
|
|
||||||
* the email
|
|
||||||
* @throws MessagingException if error
|
|
||||||
*/
|
|
||||||
public void emailSuccessMessage(Context context, EPerson eperson,
|
|
||||||
String fileName) throws MessagingException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since the archive is created in a new thread we are unable to communicate
|
|
||||||
* with calling method about success or failure. We accomplis this
|
|
||||||
* communication with email instead. Send an error email if the export
|
|
||||||
* archive fails
|
|
||||||
*
|
|
||||||
* @param eperson - EPerson to send the error message to
|
|
||||||
* @param error - the error message
|
|
||||||
* @throws MessagingException if error
|
|
||||||
*/
|
|
||||||
public void emailErrorMessage(EPerson eperson, String error)
|
|
||||||
throws MessagingException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zip source to target
|
|
||||||
*
|
|
||||||
* @param strSource source file
|
|
||||||
* @param target target file
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void zip(String strSource, String target) throws Exception;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import gr.ekt.bte.core.DataLoader;
|
|
||||||
import gr.ekt.bte.core.TransformationEngine;
|
|
||||||
import gr.ekt.bte.dataloader.FileDataLoader;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class acts as a Service in the procedure to batch import using the Biblio-Transformation-Engine
|
|
||||||
*/
|
|
||||||
public class BTEBatchImportService {
|
|
||||||
|
|
||||||
TransformationEngine transformationEngine;
|
|
||||||
Map<String, DataLoader> dataLoaders = new HashMap<String, DataLoader>();
|
|
||||||
Map<String, String> outputMap = new HashMap<String, String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
public BTEBatchImportService() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter method for dataLoaders parameter
|
|
||||||
*
|
|
||||||
* @param dataLoaders map of data loaders
|
|
||||||
*/
|
|
||||||
public void setDataLoaders(Map<String, DataLoader> dataLoaders) {
|
|
||||||
this.dataLoaders = dataLoaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get data loaders
|
|
||||||
*
|
|
||||||
* @return the map of DataLoaders
|
|
||||||
*/
|
|
||||||
public Map<String, DataLoader> getDataLoaders() {
|
|
||||||
return dataLoaders;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get output map
|
|
||||||
*
|
|
||||||
* @return the outputMapping
|
|
||||||
*/
|
|
||||||
public Map<String, String> getOutputMap() {
|
|
||||||
return outputMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Setter method for the outputMapping
|
|
||||||
*
|
|
||||||
* @param outputMap the output mapping
|
|
||||||
*/
|
|
||||||
public void setOutputMap(Map<String, String> outputMap) {
|
|
||||||
this.outputMap = outputMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get transformation engine
|
|
||||||
*
|
|
||||||
* @return transformation engine
|
|
||||||
*/
|
|
||||||
public TransformationEngine getTransformationEngine() {
|
|
||||||
return transformationEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set transformation engine
|
|
||||||
*
|
|
||||||
* @param transformationEngine transformation engine
|
|
||||||
*/
|
|
||||||
public void setTransformationEngine(TransformationEngine transformationEngine) {
|
|
||||||
this.transformationEngine = transformationEngine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter of file data loaders
|
|
||||||
*
|
|
||||||
* @return List of file data loaders
|
|
||||||
*/
|
|
||||||
public List<String> getFileDataLoaders() {
|
|
||||||
List<String> result = new ArrayList<String>();
|
|
||||||
|
|
||||||
for (String key : dataLoaders.keySet()) {
|
|
||||||
DataLoader dl = dataLoaders.get(key);
|
|
||||||
if (dl instanceof FileDataLoader) {
|
|
||||||
result.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.LineNumberReader;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author kstamatis
|
|
||||||
*/
|
|
||||||
public class BatchUpload {
|
|
||||||
|
|
||||||
private Date date;
|
|
||||||
private File dir;
|
|
||||||
private boolean successful;
|
|
||||||
private int itemsImported;
|
|
||||||
private int totalItems = 0;
|
|
||||||
private List<String> handlesImported = new ArrayList<String>();
|
|
||||||
private String errorMsg = "";
|
|
||||||
private String errorMsgHTML = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize with directory
|
|
||||||
*
|
|
||||||
* @param dirPath directory path
|
|
||||||
*/
|
|
||||||
public BatchUpload(String dirPath) {
|
|
||||||
|
|
||||||
this.initializeWithFile(new File(dirPath));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize with directory
|
|
||||||
*
|
|
||||||
* @param dir directory path
|
|
||||||
*/
|
|
||||||
public BatchUpload(File dir) {
|
|
||||||
|
|
||||||
this.initializeWithFile(dir);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize with directory
|
|
||||||
*
|
|
||||||
* @param dir directory path
|
|
||||||
*/
|
|
||||||
private void initializeWithFile(File dir) {
|
|
||||||
|
|
||||||
this.dir = dir;
|
|
||||||
|
|
||||||
String dirName = dir.getName();
|
|
||||||
long timeMillis = Long.parseLong(dirName);
|
|
||||||
Calendar calendar = new GregorianCalendar();
|
|
||||||
calendar.setTimeInMillis(timeMillis);
|
|
||||||
this.date = calendar.getTime();
|
|
||||||
|
|
||||||
try {
|
|
||||||
this.itemsImported = countLines(dir + File.separator + "mapfile");
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (File file : dir.listFiles()) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
this.totalItems = file.list().length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.successful = this.totalItems == this.itemsImported;
|
|
||||||
|
|
||||||
//Parse possible error message
|
|
||||||
|
|
||||||
File errorFile = new File(dir + File.separator + "error.txt");
|
|
||||||
if (errorFile.exists()) {
|
|
||||||
try {
|
|
||||||
readFile(dir + File.separator + "error.txt");
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO Auto-generated catch block
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count lines in file
|
|
||||||
*
|
|
||||||
* @param filename file name
|
|
||||||
* @return lines in file
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
private int countLines(String filename) throws IOException {
|
|
||||||
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
|
|
||||||
int cnt = 0;
|
|
||||||
String lineRead = "";
|
|
||||||
while ((lineRead = reader.readLine()) != null) {
|
|
||||||
String[] parts = lineRead.split(" ");
|
|
||||||
if (parts.length > 1) {
|
|
||||||
handlesImported.add(parts[1].trim());
|
|
||||||
} else {
|
|
||||||
handlesImported.add(lineRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cnt = reader.getLineNumber();
|
|
||||||
reader.close();
|
|
||||||
return cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a file
|
|
||||||
*
|
|
||||||
* @param filename file name
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
private void readFile(String filename) throws IOException {
|
|
||||||
LineNumberReader reader = new LineNumberReader(new FileReader(filename));
|
|
||||||
String lineRead = "";
|
|
||||||
while ((lineRead = reader.readLine()) != null) {
|
|
||||||
this.errorMsg += lineRead + "\n";
|
|
||||||
|
|
||||||
if (lineRead.startsWith("\tat ")) {
|
|
||||||
this.errorMsgHTML += "<span class=\"batchimport-error-tab\">" + lineRead + "</span><br/>";
|
|
||||||
} else if (lineRead.startsWith("Caused by")) {
|
|
||||||
this.errorMsgHTML += "<span class=\"batchimport-error-caused\">" + lineRead + "</span><br/>";
|
|
||||||
} else {
|
|
||||||
this.errorMsgHTML += lineRead + "<br/>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reader.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get date
|
|
||||||
*
|
|
||||||
* @return Date
|
|
||||||
*/
|
|
||||||
public Date getDate() {
|
|
||||||
return date;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get path to directory
|
|
||||||
*
|
|
||||||
* @return directory
|
|
||||||
*/
|
|
||||||
public File getDir() {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether successulf
|
|
||||||
*
|
|
||||||
* @return true or false
|
|
||||||
*/
|
|
||||||
public boolean isSuccessful() {
|
|
||||||
return successful;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get items imported
|
|
||||||
*
|
|
||||||
* @return number of items
|
|
||||||
*/
|
|
||||||
public int getItemsImported() {
|
|
||||||
return itemsImported;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get total items
|
|
||||||
*
|
|
||||||
* @return total
|
|
||||||
*/
|
|
||||||
public int getTotalItems() {
|
|
||||||
return totalItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get formatted date (DD/MM/YY)
|
|
||||||
*
|
|
||||||
* @return date as string
|
|
||||||
*/
|
|
||||||
public String getDateFormatted() {
|
|
||||||
SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy - HH:mm");
|
|
||||||
|
|
||||||
return df.format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get handles of imported files
|
|
||||||
*
|
|
||||||
* @return list of handles
|
|
||||||
*/
|
|
||||||
public List<String> getHandlesImported() {
|
|
||||||
return handlesImported;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get error message
|
|
||||||
*
|
|
||||||
* @return error message
|
|
||||||
*/
|
|
||||||
public String getErrorMsg() {
|
|
||||||
return errorMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get error message as HTML
|
|
||||||
*
|
|
||||||
* @return error message string as HTML
|
|
||||||
*/
|
|
||||||
public String getErrorMsgHTML() {
|
|
||||||
return errorMsgHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,431 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
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.PosixParser;
|
|
||||||
import org.dspace.app.itemimport.factory.ItemImportServiceFactory;
|
|
||||||
import org.dspace.app.itemimport.service.ItemImportService;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.CollectionService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.EPersonService;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.handle.service.HandleService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import items into DSpace. The conventional use is upload files by copying
|
|
||||||
* them. DSpace writes the item's bitstreams into its assetstore. Metadata is
|
|
||||||
* also loaded to the DSpace database.
|
|
||||||
* <P>
|
|
||||||
* A second use assumes the bitstream files already exist in a storage
|
|
||||||
* resource accessible to DSpace. In this case the bitstreams are 'registered'.
|
|
||||||
* That is, the metadata is loaded to the DSpace database and DSpace is given
|
|
||||||
* the location of the file which is subsumed into DSpace.
|
|
||||||
* <P>
|
|
||||||
* The distinction is controlled by the format of lines in the 'contents' file.
|
|
||||||
* See comments in processContentsFile() below.
|
|
||||||
* <P>
|
|
||||||
* Modified by David Little, UCSD Libraries 12/21/04 to
|
|
||||||
* allow the registration of files (bitstreams) into DSpace.
|
|
||||||
*/
|
|
||||||
public class ItemImportCLITool {
|
|
||||||
|
|
||||||
private static boolean template = false;
|
|
||||||
|
|
||||||
private static final CollectionService collectionService = ContentServiceFactory.getInstance()
|
|
||||||
.getCollectionService();
|
|
||||||
private static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
|
||||||
private static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private ItemImportCLITool() { }
|
|
||||||
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
Date startTime = new Date();
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("a", "add", false, "add items to DSpace");
|
|
||||||
options.addOption("b", "add-bte", false, "add items to DSpace via Biblio-Transformation-Engine (BTE)");
|
|
||||||
options.addOption("r", "replace", false, "replace items in mapfile");
|
|
||||||
options.addOption("d", "delete", false,
|
|
||||||
"delete items listed in mapfile");
|
|
||||||
options.addOption("i", "inputtype", true, "input type in case of BTE import");
|
|
||||||
options.addOption("s", "source", true, "source of items (directory)");
|
|
||||||
options.addOption("z", "zip", true, "name of zip file");
|
|
||||||
options.addOption("c", "collection", true,
|
|
||||||
"destination collection(s) Handle or database ID");
|
|
||||||
options.addOption("m", "mapfile", true, "mapfile items in mapfile");
|
|
||||||
options.addOption("e", "eperson", true,
|
|
||||||
"email of eperson doing importing");
|
|
||||||
options.addOption("w", "workflow", false,
|
|
||||||
"send submission through collection's workflow");
|
|
||||||
options.addOption("n", "notify", false,
|
|
||||||
"if sending submissions through the workflow, send notification emails");
|
|
||||||
options.addOption("t", "test", false,
|
|
||||||
"test run - do not actually import items");
|
|
||||||
options.addOption("p", "template", false, "apply template");
|
|
||||||
options.addOption("R", "resume", false,
|
|
||||||
"resume a failed import (add only)");
|
|
||||||
options.addOption("q", "quiet", false, "don't display metadata");
|
|
||||||
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
String command = null; // add replace remove, etc
|
|
||||||
String bteInputType = null; //ris, endnote, tsv, csv, bibtex
|
|
||||||
String sourcedir = null;
|
|
||||||
String mapfile = null;
|
|
||||||
String eperson = null; // db ID or email
|
|
||||||
String[] collections = null; // db ID or handles
|
|
||||||
boolean isTest = false;
|
|
||||||
boolean isResume = false;
|
|
||||||
boolean useWorkflow = false;
|
|
||||||
boolean useWorkflowSendEmail = false;
|
|
||||||
boolean isQuiet = false;
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("ItemImport\n", options);
|
|
||||||
System.out
|
|
||||||
.println("\nadding items: ItemImport -a -e eperson -c collection -s sourcedir -m mapfile");
|
|
||||||
System.out
|
|
||||||
.println(
|
|
||||||
"\nadding items from zip file: ItemImport -a -e eperson -c collection -s sourcedir -z " +
|
|
||||||
"filename.zip -m mapfile");
|
|
||||||
System.out
|
|
||||||
.println("replacing items: ItemImport -r -e eperson -c collection -s sourcedir -m mapfile");
|
|
||||||
System.out
|
|
||||||
.println("deleting items: ItemImport -d -e eperson -m mapfile");
|
|
||||||
System.out
|
|
||||||
.println(
|
|
||||||
"If multiple collections are specified, the first collection will be the one that owns the " +
|
|
||||||
"item.");
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('a')) {
|
|
||||||
command = "add";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('r')) {
|
|
||||||
command = "replace";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('d')) {
|
|
||||||
command = "delete";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('b')) {
|
|
||||||
command = "add-bte";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('i')) {
|
|
||||||
bteInputType = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('w')) {
|
|
||||||
useWorkflow = true;
|
|
||||||
if (line.hasOption('n')) {
|
|
||||||
useWorkflowSendEmail = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('t')) {
|
|
||||||
isTest = true;
|
|
||||||
System.out.println("**Test Run** - not actually importing items.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('p')) {
|
|
||||||
template = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('s')) { // source
|
|
||||||
sourcedir = line.getOptionValue('s');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('m')) { // mapfile
|
|
||||||
mapfile = line.getOptionValue('m');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('e')) { // eperson
|
|
||||||
eperson = line.getOptionValue('e');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('c')) { // collections
|
|
||||||
collections = line.getOptionValues('c');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('R')) {
|
|
||||||
isResume = true;
|
|
||||||
System.out
|
|
||||||
.println("**Resume import** - attempting to import items not already imported");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('q')) {
|
|
||||||
isQuiet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean zip = false;
|
|
||||||
String zipfilename = "";
|
|
||||||
if (line.hasOption('z')) {
|
|
||||||
zip = true;
|
|
||||||
zipfilename = line.getOptionValue('z');
|
|
||||||
}
|
|
||||||
|
|
||||||
//By default assume collections will be given on the command line
|
|
||||||
boolean commandLineCollections = true;
|
|
||||||
// now validate
|
|
||||||
// must have a command set
|
|
||||||
if (command == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - must run with either add, replace, or remove (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
} else if ("add".equals(command) || "replace".equals(command)) {
|
|
||||||
if (sourcedir == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a source directory containing items must be set");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapfile == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a map file to hold importing results must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - an eperson to do the importing must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collections == null) {
|
|
||||||
System.out.println("No collections given. Assuming 'collections' file inside item directory");
|
|
||||||
commandLineCollections = false;
|
|
||||||
}
|
|
||||||
} else if ("add-bte".equals(command)) {
|
|
||||||
//Source dir can be null, the user can specify the parameters for his loader in the Spring XML
|
|
||||||
// configuration file
|
|
||||||
|
|
||||||
if (mapfile == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - a map file to hold importing results must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - an eperson to do the importing must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collections == null) {
|
|
||||||
System.out.println("No collections given. Assuming 'collections' file inside item directory");
|
|
||||||
commandLineCollections = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bteInputType == null) {
|
|
||||||
System.out
|
|
||||||
.println(
|
|
||||||
"Error - an input type (tsv, csv, ris, endnote, bibtex or any other type you have " +
|
|
||||||
"specified in BTE Spring XML configuration file) must be specified");
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else if ("delete".equals(command)) {
|
|
||||||
if (eperson == null) {
|
|
||||||
System.out
|
|
||||||
.println("Error - an eperson to do the importing must be specified");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mapfile == null) {
|
|
||||||
System.out.println("Error - a map file must be specified");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// can only resume for adds
|
|
||||||
if (isResume && !"add".equals(command) && !"add-bte".equals(command)) {
|
|
||||||
System.out
|
|
||||||
.println("Error - resume option only works with the --add or the --add-bte commands");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// do checks around mapfile - if mapfile exists and 'add' is selected,
|
|
||||||
// resume must be chosen
|
|
||||||
File myFile = new File(mapfile);
|
|
||||||
|
|
||||||
if (!isResume && "add".equals(command) && myFile.exists()) {
|
|
||||||
System.out.println("Error - the mapfile " + mapfile
|
|
||||||
+ " already exists.");
|
|
||||||
System.out
|
|
||||||
.println("Either delete it or use --resume if attempting to resume an aborted import.");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemImportService myloader = ItemImportServiceFactory.getInstance().getItemImportService();
|
|
||||||
myloader.setTest(isTest);
|
|
||||||
myloader.setResume(isResume);
|
|
||||||
myloader.setUseWorkflow(useWorkflow);
|
|
||||||
myloader.setUseWorkflowSendEmail(useWorkflowSendEmail);
|
|
||||||
myloader.setQuiet(isQuiet);
|
|
||||||
|
|
||||||
// create a context
|
|
||||||
Context c = new Context(Context.Mode.BATCH_EDIT);
|
|
||||||
|
|
||||||
// find the EPerson, assign to context
|
|
||||||
EPerson myEPerson = null;
|
|
||||||
|
|
||||||
if (eperson.indexOf('@') != -1) {
|
|
||||||
// @ sign, must be an email
|
|
||||||
myEPerson = epersonService.findByEmail(c, eperson);
|
|
||||||
} else {
|
|
||||||
myEPerson = epersonService.find(c, UUID.fromString(eperson));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myEPerson == null) {
|
|
||||||
System.out.println("Error, eperson cannot be found: " + eperson);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
c.setCurrentUser(myEPerson);
|
|
||||||
|
|
||||||
// find collections
|
|
||||||
List<Collection> mycollections = null;
|
|
||||||
|
|
||||||
// don't need to validate collections set if command is "delete"
|
|
||||||
// also if no collections are given in the command line
|
|
||||||
if (!"delete".equals(command) && commandLineCollections) {
|
|
||||||
System.out.println("Destination collections:");
|
|
||||||
|
|
||||||
mycollections = new ArrayList<>();
|
|
||||||
|
|
||||||
// validate each collection arg to see if it's a real collection
|
|
||||||
for (int i = 0; i < collections.length; i++) {
|
|
||||||
// is the ID a handle?
|
|
||||||
if (collections[i].indexOf('/') != -1) {
|
|
||||||
// string has a / so it must be a handle - try and resolve
|
|
||||||
// it
|
|
||||||
mycollections.add((Collection) handleService
|
|
||||||
.resolveToObject(c, collections[i]));
|
|
||||||
|
|
||||||
// resolved, now make sure it's a collection
|
|
||||||
if ((mycollections.get(i) == null)
|
|
||||||
|| (mycollections.get(i).getType() != Constants.COLLECTION)) {
|
|
||||||
mycollections.set(i, null);
|
|
||||||
}
|
|
||||||
} else if (collections[i] != null) {
|
|
||||||
// not a handle, try and treat it as an integer collection database ID
|
|
||||||
mycollections.set(i, collectionService.find(c, UUID.fromString(collections[i])));
|
|
||||||
}
|
|
||||||
|
|
||||||
// was the collection valid?
|
|
||||||
if (mycollections.get(i) == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot resolve "
|
|
||||||
+ collections[i] + " to collection");
|
|
||||||
}
|
|
||||||
|
|
||||||
// print progress info
|
|
||||||
String owningPrefix = "";
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
owningPrefix = "Owning ";
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(owningPrefix + " Collection: "
|
|
||||||
+ mycollections.get(i).getName());
|
|
||||||
}
|
|
||||||
} // end of validating collections
|
|
||||||
|
|
||||||
try {
|
|
||||||
// If this is a zip archive, unzip it first
|
|
||||||
if (zip) {
|
|
||||||
sourcedir = myloader.unzip(sourcedir, zipfilename);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
c.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
if ("add".equals(command)) {
|
|
||||||
myloader.addItems(c, mycollections, sourcedir, mapfile, template);
|
|
||||||
} else if ("replace".equals(command)) {
|
|
||||||
myloader.replaceItems(c, mycollections, sourcedir, mapfile, template);
|
|
||||||
} else if ("delete".equals(command)) {
|
|
||||||
myloader.deleteItems(c, mapfile);
|
|
||||||
} else if ("add-bte".equals(command)) {
|
|
||||||
myloader.addBTEItems(c, mycollections, sourcedir, mapfile, template, bteInputType, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// complete all transactions
|
|
||||||
c.complete();
|
|
||||||
} catch (Exception e) {
|
|
||||||
c.abort();
|
|
||||||
e.printStackTrace();
|
|
||||||
System.out.println(e);
|
|
||||||
status = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the unzipped file
|
|
||||||
try {
|
|
||||||
if (zip) {
|
|
||||||
System.gc();
|
|
||||||
System.out.println(
|
|
||||||
"Deleting temporary zip directory: " + myloader.getTempWorkDirFile().getAbsolutePath());
|
|
||||||
myloader.cleanupZipTemp();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.out.println("Unable to delete temporary zip archive location: " + myloader.getTempWorkDirFile()
|
|
||||||
.getAbsolutePath());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isTest) {
|
|
||||||
System.out.println("***End of Test Run***");
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
Date endTime = new Date();
|
|
||||||
System.out.println("Started: " + startTime.getTime());
|
|
||||||
System.out.println("Ended: " + endTime.getTime());
|
|
||||||
System.out.println(
|
|
||||||
"Elapsed time: " + ((endTime.getTime() - startTime.getTime()) / 1000) + " secs (" + (endTime
|
|
||||||
.getTime() - startTime.getTime()) + " msecs)");
|
|
||||||
}
|
|
||||||
|
|
||||||
System.exit(status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.itemimport.service.ItemImportService;
|
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract factory to get services for the itemimport package, use ItemImportService.getInstance() to retrieve an
|
|
||||||
* implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public abstract class ItemImportServiceFactory {
|
|
||||||
|
|
||||||
public abstract ItemImportService getItemImportService();
|
|
||||||
|
|
||||||
public static ItemImportServiceFactory getInstance() {
|
|
||||||
return DSpaceServicesFactory.getInstance().getServiceManager()
|
|
||||||
.getServiceByName("itemImportServiceFactory", ItemImportServiceFactory.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.itemimport.service.ItemImportService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory implementation to get services for the itemimport package, use ItemImportService.getInstance() to retrieve
|
|
||||||
* an implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public class ItemImportServiceFactoryImpl extends ItemImportServiceFactory {
|
|
||||||
|
|
||||||
@Autowired(required = true)
|
|
||||||
private ItemImportService itemImportService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemImportService getItemImportService() {
|
|
||||||
return itemImportService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,253 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemimport.service;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.mail.MessagingException;
|
|
||||||
|
|
||||||
import org.dspace.app.itemimport.BatchUpload;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import items into DSpace. The conventional use is upload files by copying
|
|
||||||
* them. DSpace writes the item's bitstreams into its assetstore. Metadata is
|
|
||||||
* also loaded to the DSpace database.
|
|
||||||
* <P>
|
|
||||||
* A second use assumes the bitstream files already exist in a storage
|
|
||||||
* resource accessible to DSpace. In this case the bitstreams are 'registered'.
|
|
||||||
* That is, the metadata is loaded to the DSpace database and DSpace is given
|
|
||||||
* the location of the file which is subsumed into DSpace.
|
|
||||||
* <P>
|
|
||||||
* The distinction is controlled by the format of lines in the 'contents' file.
|
|
||||||
* See comments in processContentsFile() below.
|
|
||||||
* <P>
|
|
||||||
* Modified by David Little, UCSD Libraries 12/21/04 to
|
|
||||||
* allow the registration of files (bitstreams) into DSpace.
|
|
||||||
*/
|
|
||||||
public interface ItemImportService {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param mycollections List of Collections
|
|
||||||
* @param sourceDir source location
|
|
||||||
* @param mapFile map file
|
|
||||||
* @param template whether to use template item
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void addItemsAtomic(Context c, List<Collection> mycollections, String sourceDir, String mapFile,
|
|
||||||
boolean template) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add items
|
|
||||||
*
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param mycollections List of Collections
|
|
||||||
* @param sourceDir source location
|
|
||||||
* @param mapFile map file
|
|
||||||
* @param template whether to use template item
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void addItems(Context c, List<Collection> mycollections,
|
|
||||||
String sourceDir, String mapFile, boolean template) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unzip a file
|
|
||||||
*
|
|
||||||
* @param zipfile file
|
|
||||||
* @return unzip location
|
|
||||||
* @throws IOException if error
|
|
||||||
*/
|
|
||||||
public String unzip(File zipfile) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unzip a file to a destination
|
|
||||||
*
|
|
||||||
* @param zipfile file
|
|
||||||
* @param destDir destination directory
|
|
||||||
* @return unzip location
|
|
||||||
* @throws IOException if error
|
|
||||||
*/
|
|
||||||
public String unzip(File zipfile, String destDir) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unzip a file in a specific source directory
|
|
||||||
*
|
|
||||||
* @param sourcedir source directory
|
|
||||||
* @param zipfilename file name
|
|
||||||
* @return unzip location
|
|
||||||
* @throws IOException if error
|
|
||||||
*/
|
|
||||||
public String unzip(String sourcedir, String zipfilename) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a public URL to a zip file that has the Simple Archive Format, this method imports the contents to DSpace
|
|
||||||
*
|
|
||||||
* @param url The public URL of the zip file
|
|
||||||
* @param owningCollection The owning collection the items will belong to
|
|
||||||
* @param collections The collections the created items will be inserted to, apart from the owning one
|
|
||||||
* @param resumeDir In case of a resume request, the directory that containsthe old mapfile and data
|
|
||||||
* @param inputType The input type of the data (bibtex, csv, etc.), in case of local file
|
|
||||||
* @param context The context
|
|
||||||
* @param template whether to use template item
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void processUIImport(String url, Collection owningCollection, String[] collections, String resumeDir,
|
|
||||||
String inputType, Context context, boolean template) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since the BTE batch import is done in a new thread we are unable to communicate
|
|
||||||
* with calling method about success or failure. We accomplish this
|
|
||||||
* communication with email instead. Send a success email once the batch
|
|
||||||
* import is complete
|
|
||||||
*
|
|
||||||
* @param context - the current Context
|
|
||||||
* @param eperson - eperson to send the email to
|
|
||||||
* @param fileName - the filepath to the mapfile created by the batch import
|
|
||||||
* @throws MessagingException if error
|
|
||||||
*/
|
|
||||||
public void emailSuccessMessage(Context context, EPerson eperson,
|
|
||||||
String fileName) throws MessagingException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since the BTE batch import is done in a new thread we are unable to communicate
|
|
||||||
* with calling method about success or failure. We accomplis this
|
|
||||||
* communication with email instead. Send an error email if the batch
|
|
||||||
* import fails
|
|
||||||
*
|
|
||||||
* @param eperson - EPerson to send the error message to
|
|
||||||
* @param error - the error message
|
|
||||||
* @throws MessagingException if error
|
|
||||||
*/
|
|
||||||
public void emailErrorMessage(EPerson eperson, String error)
|
|
||||||
throws MessagingException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get imports available for a person
|
|
||||||
*
|
|
||||||
* @param eperson EPerson object
|
|
||||||
* @return List of batch uploads
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public List<BatchUpload> getImportsAvailable(EPerson eperson)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get import upload directory
|
|
||||||
*
|
|
||||||
* @param ePerson EPerson object
|
|
||||||
* @return directory
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public String getImportUploadableDirectory(EPerson ePerson)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete a batch by ID
|
|
||||||
*
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param uploadId identifier
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void deleteBatchUpload(Context c, String uploadId) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace items
|
|
||||||
*
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param mycollections List of Collections
|
|
||||||
* @param sourcedir source directory
|
|
||||||
* @param mapfile map file
|
|
||||||
* @param template whether to use template item
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void replaceItems(Context c, List<Collection> mycollections, String sourcedir, String mapfile,
|
|
||||||
boolean template) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete items via mapfile
|
|
||||||
*
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param mapfile map file
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void deleteItems(Context c, String mapfile) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add items
|
|
||||||
*
|
|
||||||
* @param c DSpace Context
|
|
||||||
* @param mycollections List of Collections
|
|
||||||
* @param sourcedir source directory
|
|
||||||
* @param mapfile map file
|
|
||||||
* @param template whether to use template item
|
|
||||||
* @param bteInputType The input type of the data (bibtex, csv, etc.), in case of local file
|
|
||||||
* @param workingDir working directory
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void addBTEItems(Context c, List<Collection> mycollections, String sourcedir, String mapfile,
|
|
||||||
boolean template, String bteInputType, String workingDir) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get temporary work directory
|
|
||||||
*
|
|
||||||
* @return directory as string
|
|
||||||
*/
|
|
||||||
public String getTempWorkDir();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get temporary work directory (as File)
|
|
||||||
*
|
|
||||||
* @return directory as File
|
|
||||||
* @throws java.io.IOException if the directory cannot be created.
|
|
||||||
*/
|
|
||||||
public File getTempWorkDirFile() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cleanup
|
|
||||||
*/
|
|
||||||
public void cleanupZipTemp();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set test flag
|
|
||||||
*
|
|
||||||
* @param isTest true or false
|
|
||||||
*/
|
|
||||||
public void setTest(boolean isTest);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set resume flag
|
|
||||||
*
|
|
||||||
* @param isResume true or false
|
|
||||||
*/
|
|
||||||
public void setResume(boolean isResume);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set use workflow
|
|
||||||
*
|
|
||||||
* @param useWorkflow whether to enable workflow
|
|
||||||
*/
|
|
||||||
public void setUseWorkflow(boolean useWorkflow);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param useWorkflowSendMail whether to send mail
|
|
||||||
*/
|
|
||||||
public void setUseWorkflowSendEmail(boolean useWorkflowSendMail);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set quiet flag
|
|
||||||
*
|
|
||||||
* @param isQuiet true or false
|
|
||||||
*/
|
|
||||||
public void setQuiet(boolean isQuiet);
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemmarking;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.app.util.Util;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an item marking Strategy class that tries to mark an item availability
|
|
||||||
* based on the existence of bitstreams within the ORIGINAL bundle.
|
|
||||||
*
|
|
||||||
* @author Kostas Stamatis
|
|
||||||
*/
|
|
||||||
public class ItemMarkingAvailabilityBitstreamStrategy implements ItemMarkingExtractor {
|
|
||||||
|
|
||||||
private String availableImageName;
|
|
||||||
private String nonAvailableImageName;
|
|
||||||
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected ItemService itemService;
|
|
||||||
|
|
||||||
public ItemMarkingAvailabilityBitstreamStrategy() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
List<Bundle> bundles = itemService.getBundles(item, "ORIGINAL");
|
|
||||||
if (bundles.size() == 0) {
|
|
||||||
ItemMarkingInfo markInfo = new ItemMarkingInfo();
|
|
||||||
markInfo.setImageName(nonAvailableImageName);
|
|
||||||
|
|
||||||
return markInfo;
|
|
||||||
} else {
|
|
||||||
Bundle originalBundle = bundles.iterator().next();
|
|
||||||
if (originalBundle.getBitstreams().size() == 0) {
|
|
||||||
ItemMarkingInfo markInfo = new ItemMarkingInfo();
|
|
||||||
markInfo.setImageName(nonAvailableImageName);
|
|
||||||
|
|
||||||
return markInfo;
|
|
||||||
} else {
|
|
||||||
Bitstream bitstream = originalBundle.getBitstreams().get(0);
|
|
||||||
|
|
||||||
ItemMarkingInfo signInfo = new ItemMarkingInfo();
|
|
||||||
signInfo.setImageName(availableImageName);
|
|
||||||
signInfo.setTooltip(bitstream.getName());
|
|
||||||
|
|
||||||
|
|
||||||
String bsLink = "";
|
|
||||||
|
|
||||||
bsLink = bsLink + "bitstream/"
|
|
||||||
+ item.getHandle() + "/"
|
|
||||||
+ bitstream.getSequenceID() + "/";
|
|
||||||
|
|
||||||
try {
|
|
||||||
bsLink = bsLink + Util.encodeBitstreamName(bitstream.getName(), Constants.DEFAULT_ENCODING);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
signInfo.setLink(bsLink);
|
|
||||||
|
|
||||||
return signInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAvailableImageName(String availableImageName) {
|
|
||||||
this.availableImageName = availableImageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNonAvailableImageName(String nonAvailableImageName) {
|
|
||||||
this.nonAvailableImageName = nonAvailableImageName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemmarking;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an item marking Strategy class that tries to mark an item
|
|
||||||
* based on the collection the items belong to
|
|
||||||
*
|
|
||||||
* @author Kostas Stamatis
|
|
||||||
*/
|
|
||||||
public class ItemMarkingCollectionStrategy implements ItemMarkingExtractor {
|
|
||||||
|
|
||||||
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
|
|
||||||
|
|
||||||
public ItemMarkingCollectionStrategy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
if (mapping != null) {
|
|
||||||
for (Collection collection : item.getCollections()) {
|
|
||||||
if (mapping.containsKey(collection.getHandle())) {
|
|
||||||
return mapping.get(collection.getHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
|
|
||||||
this.mapping = mapping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemmarking;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to abstract the strategy for item signing
|
|
||||||
*
|
|
||||||
* @author Kostas Stamatis
|
|
||||||
*/
|
|
||||||
public interface ItemMarkingExtractor {
|
|
||||||
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
|
|
||||||
throws SQLException;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemmarking;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple DTO to transfer data about the marking info for an item
|
|
||||||
*
|
|
||||||
* @author Kostas Stamatis
|
|
||||||
*/
|
|
||||||
public class ItemMarkingInfo {
|
|
||||||
private String imageName;
|
|
||||||
private String classInfo;
|
|
||||||
private String tooltip;
|
|
||||||
private String link;
|
|
||||||
|
|
||||||
public ItemMarkingInfo() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getImageName() {
|
|
||||||
return imageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setImageName(String imageName) {
|
|
||||||
this.imageName = imageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTooltip() {
|
|
||||||
return tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTooltip(String tooltip) {
|
|
||||||
this.tooltip = tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLink() {
|
|
||||||
return link;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLink(String link) {
|
|
||||||
this.link = link;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getClassInfo() {
|
|
||||||
return classInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setClassInfo(String classInfo) {
|
|
||||||
this.classInfo = classInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemmarking;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.MetadataValue;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is an item marking Strategy class that tries to mark an item
|
|
||||||
* based on the existence of a specific value within the values of a specific
|
|
||||||
* metadata field
|
|
||||||
*
|
|
||||||
* @author Kostas Stamatis
|
|
||||||
*/
|
|
||||||
public class ItemMarkingMetadataStrategy implements ItemMarkingExtractor {
|
|
||||||
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected ItemService itemService;
|
|
||||||
|
|
||||||
private String metadataField;
|
|
||||||
Map<String, ItemMarkingInfo> mapping = new HashMap<String, ItemMarkingInfo>();
|
|
||||||
|
|
||||||
public ItemMarkingMetadataStrategy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemMarkingInfo getItemMarkingInfo(Context context, Item item)
|
|
||||||
throws SQLException {
|
|
||||||
|
|
||||||
if (metadataField != null && mapping != null) {
|
|
||||||
List<MetadataValue> vals = itemService.getMetadataByMetadataString(item, metadataField);
|
|
||||||
if (vals.size() > 0) {
|
|
||||||
for (MetadataValue value : vals) {
|
|
||||||
String type = value.getValue();
|
|
||||||
if (mapping.containsKey(type)) {
|
|
||||||
return mapping.get(type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMetadataField(String metadataField) {
|
|
||||||
this.metadataField = metadataField;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMapping(Map<String, ItemMarkingInfo> mapping) {
|
|
||||||
this.mapping = mapping;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Container for UpdateActions
|
|
||||||
* Order of actions is very import for correct processing. This implementation
|
|
||||||
* supports an iterator that returns the actions in the order in which they are
|
|
||||||
* put in. Adding the same action a second time has no effect on this order.
|
|
||||||
*/
|
|
||||||
public class ActionManager implements Iterable<UpdateAction> {
|
|
||||||
|
|
||||||
protected Map<Class<? extends UpdateAction>, UpdateAction> registry
|
|
||||||
= new LinkedHashMap<Class<? extends UpdateAction>, UpdateAction>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get update action
|
|
||||||
*
|
|
||||||
* @param actionClass UpdateAction class
|
|
||||||
* @return instantiation of UpdateAction class
|
|
||||||
* @throws InstantiationException if instantiation error
|
|
||||||
* @throws IllegalAccessException if illegal access error
|
|
||||||
*/
|
|
||||||
public UpdateAction getUpdateAction(Class<? extends UpdateAction> actionClass)
|
|
||||||
throws InstantiationException, IllegalAccessException {
|
|
||||||
UpdateAction action = registry.get(actionClass);
|
|
||||||
|
|
||||||
if (action == null) {
|
|
||||||
action = actionClass.newInstance();
|
|
||||||
registry.put(actionClass, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return whether any actions have been registered with this manager
|
|
||||||
*/
|
|
||||||
public boolean hasActions() {
|
|
||||||
return !registry.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This implementation guarantees the iterator order is the same as the order
|
|
||||||
* in which updateActions have been added
|
|
||||||
*
|
|
||||||
* @return iterator for UpdateActions
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<UpdateAction> iterator() {
|
|
||||||
return new Iterator<UpdateAction>() {
|
|
||||||
private Iterator<Class<? extends UpdateAction>> itr = registry.keySet().iterator();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return itr.hasNext();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UpdateAction next() {
|
|
||||||
return registry.get(itr.next());
|
|
||||||
}
|
|
||||||
|
|
||||||
//not supported
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.authorize.factory.AuthorizeServiceFactory;
|
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.BitstreamFormat;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.BitstreamFormatService;
|
|
||||||
import org.dspace.content.service.InstallItemService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.Group;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.GroupService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to add bitstreams listed in item contents file to the item in DSpace
|
|
||||||
*/
|
|
||||||
public class AddBitstreamsAction extends UpdateBitstreamsAction {
|
|
||||||
|
|
||||||
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
|
|
||||||
protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
|
|
||||||
.getBitstreamFormatService();
|
|
||||||
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
|
|
||||||
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
|
|
||||||
|
|
||||||
public AddBitstreamsAction() {
|
|
||||||
//empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds bitstreams from the archive as listed in the contents file.
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch Item Archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws IllegalArgumentException if arg exception
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest,
|
|
||||||
boolean suppressUndo) throws IllegalArgumentException,
|
|
||||||
ParseException, IOException, AuthorizeException, SQLException {
|
|
||||||
Item item = itarch.getItem();
|
|
||||||
File dir = itarch.getDirectory();
|
|
||||||
|
|
||||||
List<ContentsEntry> contents = MetadataUtilities.readContentsFile(new File(dir, ItemUpdate.CONTENTS_FILE));
|
|
||||||
|
|
||||||
if (contents.isEmpty()) {
|
|
||||||
ItemUpdate.pr("Contents is empty - no bitstreams to add");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemUpdate.pr("Contents bitstream count: " + contents.size());
|
|
||||||
|
|
||||||
String[] files = dir.list(ItemUpdate.fileFilter);
|
|
||||||
List<String> fileList = new ArrayList<String>();
|
|
||||||
for (String filename : files) {
|
|
||||||
fileList.add(filename);
|
|
||||||
ItemUpdate.pr("file: " + filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ContentsEntry ce : contents) {
|
|
||||||
//validate match to existing file in archive
|
|
||||||
if (!fileList.contains(ce.filename)) {
|
|
||||||
throw new IllegalArgumentException("File listed in contents is missing: " + ce.filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int bitstream_bundles_updated = 0;
|
|
||||||
|
|
||||||
//now okay to add
|
|
||||||
for (ContentsEntry ce : contents) {
|
|
||||||
String targetBundleName = addBitstream(context, itarch, item, dir, ce, suppressUndo, isTest);
|
|
||||||
if (!targetBundleName.equals("")
|
|
||||||
&& !targetBundleName.equals("THUMBNAIL")
|
|
||||||
&& !targetBundleName.equals("TEXT")) {
|
|
||||||
bitstream_bundles_updated++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alterProvenance && bitstream_bundles_updated > 0) {
|
|
||||||
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
|
|
||||||
|
|
||||||
String append = ". Added " + Integer.toString(bitstream_bundles_updated)
|
|
||||||
+ " bitstream(s) on " + DCDate.getCurrent() + " : "
|
|
||||||
+ installItemService.getBitstreamProvenanceMessage(context, item);
|
|
||||||
MetadataUtilities.appendMetadata(context, item, dtom, false, append);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add bitstream
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch Item Archive
|
|
||||||
* @param item DSpace Item
|
|
||||||
* @param dir directory
|
|
||||||
* @param ce contents entry for bitstream
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @param isTest test flag
|
|
||||||
* @return bundle name
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws IllegalArgumentException if arg exception
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
protected String addBitstream(Context context, ItemArchive itarch, Item item, File dir,
|
|
||||||
ContentsEntry ce, boolean suppressUndo, boolean isTest)
|
|
||||||
throws IOException, IllegalArgumentException, SQLException, AuthorizeException, ParseException {
|
|
||||||
ItemUpdate.pr("contents entry for bitstream: " + ce.toString());
|
|
||||||
File f = new File(dir, ce.filename);
|
|
||||||
|
|
||||||
// get an input stream
|
|
||||||
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));
|
|
||||||
|
|
||||||
Bitstream bs = null;
|
|
||||||
String newBundleName = ce.bundlename;
|
|
||||||
|
|
||||||
if (ce.bundlename == null) { // should be required but default convention established
|
|
||||||
if (ce.filename.equals("license.txt")) {
|
|
||||||
newBundleName = "LICENSE";
|
|
||||||
} else {
|
|
||||||
newBundleName = "ORIGINAL";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemUpdate.pr(" Bitstream " + ce.filename + " to be added to bundle: " + newBundleName);
|
|
||||||
|
|
||||||
if (!isTest) {
|
|
||||||
// find the bundle
|
|
||||||
List<Bundle> bundles = itemService.getBundles(item, newBundleName);
|
|
||||||
Bundle targetBundle = null;
|
|
||||||
|
|
||||||
if (bundles.size() < 1) {
|
|
||||||
// not found, create a new one
|
|
||||||
targetBundle = bundleService.create(context, item, newBundleName);
|
|
||||||
} else {
|
|
||||||
//verify bundle + name are not duplicates
|
|
||||||
for (Bundle b : bundles) {
|
|
||||||
List<Bitstream> bitstreams = b.getBitstreams();
|
|
||||||
for (Bitstream bsm : bitstreams) {
|
|
||||||
if (bsm.getName().equals(ce.filename)) {
|
|
||||||
throw new IllegalArgumentException("Duplicate bundle + filename cannot be added: "
|
|
||||||
+ b.getName() + " + " + bsm.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// select first bundle
|
|
||||||
targetBundle = bundles.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
bs = bitstreamService.create(context, targetBundle, bis);
|
|
||||||
bs.setName(context, ce.filename);
|
|
||||||
|
|
||||||
// Identify the format
|
|
||||||
// FIXME - guessing format guesses license.txt incorrectly as a text file format!
|
|
||||||
BitstreamFormat fmt = bitstreamFormatService.guessFormat(context, bs);
|
|
||||||
bitstreamService.setFormat(context, bs, fmt);
|
|
||||||
|
|
||||||
if (ce.description != null) {
|
|
||||||
bs.setDescription(context, ce.description);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ce.permissionsActionId != -1) && (ce.permissionsGroupName != null)) {
|
|
||||||
Group group = groupService.findByName(context, ce.permissionsGroupName);
|
|
||||||
|
|
||||||
if (group != null) {
|
|
||||||
authorizeService.removeAllPolicies(context, bs); // remove the default policy
|
|
||||||
authorizeService.createResourcePolicy(context, bs, group, null, ce.permissionsActionId, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//update after all changes are applied
|
|
||||||
bitstreamService.update(context, bs);
|
|
||||||
|
|
||||||
if (!suppressUndo) {
|
|
||||||
itarch.addUndoDeleteContents(bs.getID());
|
|
||||||
}
|
|
||||||
return targetBundle.getName();
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.MetadataValue;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.MetadataFieldService;
|
|
||||||
import org.dspace.content.service.MetadataSchemaService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to add metadata to item
|
|
||||||
*/
|
|
||||||
public class AddMetadataAction extends UpdateMetadataAction {
|
|
||||||
|
|
||||||
protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
|
|
||||||
.getMetadataSchemaService();
|
|
||||||
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds metadata specified in the source archive
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch item archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest,
|
|
||||||
boolean suppressUndo) throws AuthorizeException, SQLException {
|
|
||||||
Item item = itarch.getItem();
|
|
||||||
String dirname = itarch.getDirectoryName();
|
|
||||||
|
|
||||||
for (DtoMetadata dtom : itarch.getMetadataFields()) {
|
|
||||||
for (String f : targetFields) {
|
|
||||||
if (dtom.matches(f, false)) {
|
|
||||||
// match against metadata for this field/value in repository
|
|
||||||
// qualifier must be strictly matched, possibly null
|
|
||||||
List<MetadataValue> ardcv = null;
|
|
||||||
ardcv = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
for (MetadataValue dcv : ardcv) {
|
|
||||||
if (dcv.getValue().equals(dtom.value)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
ItemUpdate.pr("Warning: No new metadata found to add to item " + dirname
|
|
||||||
+ " for element " + f);
|
|
||||||
} else {
|
|
||||||
if (isTest) {
|
|
||||||
ItemUpdate.pr("Metadata to add: " + dtom.toString());
|
|
||||||
//validity tests that would occur in actual processing
|
|
||||||
// If we're just test the import, let's check that the actual metadata field exists.
|
|
||||||
MetadataSchema foundSchema = metadataSchemaService.find(context, dtom.schema);
|
|
||||||
|
|
||||||
if (foundSchema == null) {
|
|
||||||
ItemUpdate.pr("ERROR: schema '"
|
|
||||||
+ dtom.schema + "' was not found in the registry; found on item " +
|
|
||||||
dirname);
|
|
||||||
} else {
|
|
||||||
MetadataField foundField = metadataFieldService
|
|
||||||
.findByElement(context, foundSchema, dtom.element, dtom.qualifier);
|
|
||||||
|
|
||||||
if (foundField == null) {
|
|
||||||
ItemUpdate.pr("ERROR: Metadata field: '" + dtom.schema + "." + dtom.element + "."
|
|
||||||
+ dtom.qualifier + "' not found in registry; found on item " +
|
|
||||||
dirname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
itemService
|
|
||||||
.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language,
|
|
||||||
dtom.value);
|
|
||||||
ItemUpdate.pr("Metadata added: " + dtom.toString());
|
|
||||||
|
|
||||||
if (!suppressUndo) {
|
|
||||||
//itarch.addUndoDtom(dtom);
|
|
||||||
//ItemUpdate.pr("Undo metadata: " + dtom);
|
|
||||||
|
|
||||||
// add all as a replace record to be preceded by delete
|
|
||||||
for (MetadataValue dcval : ardcv) {
|
|
||||||
MetadataField metadataField = dcval.getMetadataField();
|
|
||||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
|
||||||
itarch.addUndoMetadataField(
|
|
||||||
DtoMetadata.create(metadataSchema.getName(), metadataField.getElement(),
|
|
||||||
metadataField.getQualifier(), dcval.getLanguage(),
|
|
||||||
dcval.getValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break; // don't need to check if this field matches any other target fields
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter interface to be used by ItemUpdate
|
|
||||||
* to determine which bitstreams in an Item
|
|
||||||
* acceptable for removal.
|
|
||||||
*/
|
|
||||||
public abstract class BitstreamFilter {
|
|
||||||
|
|
||||||
protected Properties props = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The filter method
|
|
||||||
*
|
|
||||||
* @param bitstream Bitstream
|
|
||||||
* @return whether the bitstream matches the criteria
|
|
||||||
* @throws BitstreamFilterException if filter error
|
|
||||||
*/
|
|
||||||
public abstract boolean accept(Bitstream bitstream) throws BitstreamFilterException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param filepath - The complete path for the properties file
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
public void initProperties(String filepath)
|
|
||||||
throws IOException {
|
|
||||||
props = new Properties();
|
|
||||||
|
|
||||||
InputStream in = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
in = new FileInputStream(filepath);
|
|
||||||
props.load(in);
|
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BitstreamFilter implementation to filter by bundle name
|
|
||||||
*/
|
|
||||||
public class BitstreamFilterByBundleName extends BitstreamFilter {
|
|
||||||
|
|
||||||
protected String bundleName;
|
|
||||||
|
|
||||||
public BitstreamFilterByBundleName() {
|
|
||||||
//empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter bitstream based on bundle name found in properties file
|
|
||||||
*
|
|
||||||
* @param bitstream Bitstream
|
|
||||||
* @return whether bitstream is in bundle
|
|
||||||
* @throws BitstreamFilterException if filter error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean accept(Bitstream bitstream)
|
|
||||||
throws BitstreamFilterException {
|
|
||||||
if (bundleName == null) {
|
|
||||||
bundleName = props.getProperty("bundle");
|
|
||||||
if (bundleName == null) {
|
|
||||||
throw new BitstreamFilterException("Property 'bundle' not found.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
List<Bundle> bundles = bitstream.getBundles();
|
|
||||||
for (Bundle b : bundles) {
|
|
||||||
if (b.getName().equals(bundleName)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new BitstreamFilterException(e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BitstreamFilter implementation to filter by filename pattern
|
|
||||||
*/
|
|
||||||
public class BitstreamFilterByFilename extends BitstreamFilter {
|
|
||||||
|
|
||||||
protected Pattern pattern;
|
|
||||||
protected String filenameRegex;
|
|
||||||
|
|
||||||
public BitstreamFilterByFilename() {
|
|
||||||
//empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests bitstream by matching the regular expression in the
|
|
||||||
* properties against the bitstream name
|
|
||||||
*
|
|
||||||
* @param bitstream Bitstream
|
|
||||||
* @return whether bitstream name matches the regular expression
|
|
||||||
* @throws BitstreamFilterException if filter error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean accept(Bitstream bitstream) throws BitstreamFilterException {
|
|
||||||
if (filenameRegex == null) {
|
|
||||||
filenameRegex = props.getProperty("filename");
|
|
||||||
if (filenameRegex == null) {
|
|
||||||
throw new BitstreamFilterException("BitstreamFilter property 'filename' not found.");
|
|
||||||
}
|
|
||||||
pattern = Pattern.compile(filenameRegex);
|
|
||||||
}
|
|
||||||
|
|
||||||
Matcher m = pattern.matcher(bitstream.getName());
|
|
||||||
return m.matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception class for BitstreamFilters
|
|
||||||
*/
|
|
||||||
public class BitstreamFilterException extends Exception {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public BitstreamFilterException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param msg exception message
|
|
||||||
*/
|
|
||||||
public BitstreamFilterException(String msg) {
|
|
||||||
super(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param e exception
|
|
||||||
*/
|
|
||||||
public BitstreamFilterException(Exception e) {
|
|
||||||
super(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holds the elements of a line in the Contents Entry file
|
|
||||||
*
|
|
||||||
* Based on private methods in ItemImport
|
|
||||||
*
|
|
||||||
* Lacking a spec or full documentation for the file format,
|
|
||||||
* it looks from the source code that the ordering or elements is not fixed
|
|
||||||
*
|
|
||||||
* e.g.:
|
|
||||||
* {@code
|
|
||||||
* 48217870-MIT.pdf\tbundle: bundlename\tpermissions: -r 'MIT Users'\tdescription: Full printable version (MIT only)
|
|
||||||
* permissions: -[r|w] ['group name']
|
|
||||||
* description: <the description of the file>
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
public class ContentsEntry {
|
|
||||||
public static final String HDR_BUNDLE = "bundle:";
|
|
||||||
public static final String HDR_PERMISSIONS = "permissions:";
|
|
||||||
public static final String HDR_DESCRIPTION = "description:";
|
|
||||||
|
|
||||||
public static final Pattern permissionsPattern = Pattern.compile("-([rw])\\s*'?([^']+)'?");
|
|
||||||
|
|
||||||
final String filename;
|
|
||||||
final String bundlename;
|
|
||||||
final String permissionsGroupName;
|
|
||||||
final int permissionsActionId;
|
|
||||||
final String description;
|
|
||||||
|
|
||||||
protected ContentsEntry(String filename,
|
|
||||||
String bundlename,
|
|
||||||
int permissionsActionId,
|
|
||||||
String permissionsGroupName,
|
|
||||||
String description) {
|
|
||||||
this.filename = filename;
|
|
||||||
this.bundlename = bundlename;
|
|
||||||
this.permissionsActionId = permissionsActionId;
|
|
||||||
this.permissionsGroupName = permissionsGroupName;
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method parses a line from the Contents Entry file
|
|
||||||
*
|
|
||||||
* @param line line as string
|
|
||||||
* @return the parsed ContentsEntry object
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
public static ContentsEntry parse(String line)
|
|
||||||
throws ParseException {
|
|
||||||
String[] ar = line.split("\t");
|
|
||||||
ItemUpdate.pr("ce line split: " + ar.length);
|
|
||||||
|
|
||||||
String[] arp = new String[4];
|
|
||||||
arp[0] = ar[0]; //bitstream name doesn't have header and is always first
|
|
||||||
|
|
||||||
String groupName = null;
|
|
||||||
int actionId = -1;
|
|
||||||
|
|
||||||
if (ar.length > 1) {
|
|
||||||
for (int i = 1; i < ar.length; i++) {
|
|
||||||
ItemUpdate.pr("ce " + i + " : " + ar[i]);
|
|
||||||
if (ar[i].startsWith(HDR_BUNDLE)) {
|
|
||||||
arp[1] = ar[i].substring(HDR_BUNDLE.length()).trim();
|
|
||||||
|
|
||||||
} else if (ar[i].startsWith(HDR_PERMISSIONS)) {
|
|
||||||
arp[2] = ar[i].substring(HDR_PERMISSIONS.length()).trim();
|
|
||||||
|
|
||||||
// parse into actionId and group name
|
|
||||||
|
|
||||||
Matcher m = permissionsPattern.matcher(arp[2]);
|
|
||||||
if (m.matches()) {
|
|
||||||
String action = m.group(1); //
|
|
||||||
if (action.equals("r")) {
|
|
||||||
actionId = Constants.READ;
|
|
||||||
} else if (action.equals("w")) {
|
|
||||||
actionId = Constants.WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
groupName = m.group(2).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (ar[i].startsWith(HDR_DESCRIPTION)) {
|
|
||||||
arp[3] = ar[i].substring(HDR_DESCRIPTION.length()).trim();
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new ParseException("Unknown text in contents file: " + ar[i], 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new ContentsEntry(arp[0], arp[1], actionId, groupName, arp[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
StringBuilder sb = new StringBuilder(filename);
|
|
||||||
if (bundlename != null) {
|
|
||||||
sb.append(HDR_BUNDLE).append(" ").append(bundlename);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (permissionsGroupName != null) {
|
|
||||||
sb.append(HDR_PERMISSIONS);
|
|
||||||
if (permissionsActionId == Constants.READ) {
|
|
||||||
sb.append(" -r ");
|
|
||||||
} else if (permissionsActionId == Constants.WRITE) {
|
|
||||||
sb.append(" -w ");
|
|
||||||
}
|
|
||||||
sb.append(permissionsGroupName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description != null) {
|
|
||||||
sb.append(HDR_DESCRIPTION).append(" ").append(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to delete bitstreams
|
|
||||||
*
|
|
||||||
* Undo not supported for this UpdateAction
|
|
||||||
*
|
|
||||||
* Derivatives of the bitstream to be deleted are not also deleted
|
|
||||||
*/
|
|
||||||
public class DeleteBitstreamsAction extends UpdateBitstreamsAction {
|
|
||||||
/**
|
|
||||||
* Delete bitstream from item
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch item archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws IllegalArgumentException if arg exception
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest,
|
|
||||||
boolean suppressUndo) throws IllegalArgumentException, IOException,
|
|
||||||
SQLException, AuthorizeException, ParseException {
|
|
||||||
File f = new File(itarch.getDirectory(), ItemUpdate.DELETE_CONTENTS_FILE);
|
|
||||||
if (!f.exists()) {
|
|
||||||
ItemUpdate.pr("Warning: Delete_contents file for item " + itarch.getDirectoryName() + " not found.");
|
|
||||||
} else {
|
|
||||||
List<String> list = MetadataUtilities.readDeleteContentsFile(f);
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
ItemUpdate.pr("Warning: empty delete_contents file for item " + itarch.getDirectoryName());
|
|
||||||
} else {
|
|
||||||
for (String id : list) {
|
|
||||||
try {
|
|
||||||
Bitstream bs = bitstreamService.findByIdOrLegacyId(context, id);
|
|
||||||
if (bs == null) {
|
|
||||||
ItemUpdate.pr("Bitstream not found by id: " + id);
|
|
||||||
} else {
|
|
||||||
List<Bundle> bundles = bs.getBundles();
|
|
||||||
for (Bundle b : bundles) {
|
|
||||||
if (isTest) {
|
|
||||||
ItemUpdate.pr("Delete bitstream with id = " + id);
|
|
||||||
} else {
|
|
||||||
bundleService.removeBitstream(context, b, bs);
|
|
||||||
ItemUpdate.pr("Deleted bitstream with id = " + id);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alterProvenance) {
|
|
||||||
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
|
|
||||||
|
|
||||||
String append = "Bitstream " + bs.getName() + " deleted on " + DCDate
|
|
||||||
.getCurrent() + "; ";
|
|
||||||
Item item = bundles.iterator().next().getItems().iterator().next();
|
|
||||||
ItemUpdate.pr("Append provenance with: " + append);
|
|
||||||
|
|
||||||
if (!isTest) {
|
|
||||||
MetadataUtilities.appendMetadata(context, item, dtom, false, append);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
ItemUpdate.pr("Error finding bitstream from id: " + id + " : " + e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to delete bitstreams using a specified filter implementing BitstreamFilter
|
|
||||||
* Derivatives for the target bitstreams are not deleted.
|
|
||||||
*
|
|
||||||
* The dc.description.provenance field is amended to reflect the deletions
|
|
||||||
*
|
|
||||||
* Note: Multiple filters are impractical if trying to manage multiple properties files
|
|
||||||
* in a commandline environment
|
|
||||||
*/
|
|
||||||
public class DeleteBitstreamsByFilterAction extends UpdateBitstreamsAction {
|
|
||||||
|
|
||||||
protected BitstreamFilter filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set filter
|
|
||||||
*
|
|
||||||
* @param filter BitstreamFilter
|
|
||||||
*/
|
|
||||||
public void setBitstreamFilter(BitstreamFilter filter) {
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get filter
|
|
||||||
*
|
|
||||||
* @return filter
|
|
||||||
*/
|
|
||||||
public BitstreamFilter getBitstreamFilter() {
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete bitstream
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch item archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
* @throws BitstreamFilterException if filter error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest,
|
|
||||||
boolean suppressUndo) throws AuthorizeException,
|
|
||||||
BitstreamFilterException, IOException, ParseException, SQLException {
|
|
||||||
|
|
||||||
List<String> deleted = new ArrayList<String>();
|
|
||||||
|
|
||||||
Item item = itarch.getItem();
|
|
||||||
List<Bundle> bundles = item.getBundles();
|
|
||||||
|
|
||||||
for (Bundle b : bundles) {
|
|
||||||
List<Bitstream> bitstreams = b.getBitstreams();
|
|
||||||
String bundleName = b.getName();
|
|
||||||
|
|
||||||
for (Bitstream bs : bitstreams) {
|
|
||||||
if (filter.accept(bs)) {
|
|
||||||
if (isTest) {
|
|
||||||
ItemUpdate.pr("Delete from bundle " + bundleName + " bitstream " + bs.getName()
|
|
||||||
+ " with id = " + bs.getID());
|
|
||||||
} else {
|
|
||||||
//provenance is not maintained for derivative bitstreams
|
|
||||||
if (!bundleName.equals("THUMBNAIL") && !bundleName.equals("TEXT")) {
|
|
||||||
deleted.add(bs.getName());
|
|
||||||
}
|
|
||||||
bundleService.removeBitstream(context, b, bs);
|
|
||||||
ItemUpdate.pr("Deleted " + bundleName + " bitstream " + bs.getName()
|
|
||||||
+ " with id = " + bs.getID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alterProvenance && !deleted.isEmpty()) {
|
|
||||||
StringBuilder sb = new StringBuilder(" Bitstreams deleted on ");
|
|
||||||
sb.append(DCDate.getCurrent()).append(": ");
|
|
||||||
|
|
||||||
for (String s : deleted) {
|
|
||||||
sb.append(s).append(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", "");
|
|
||||||
|
|
||||||
ItemUpdate.pr("Append provenance with: " + sb.toString());
|
|
||||||
|
|
||||||
if (!isTest) {
|
|
||||||
MetadataUtilities.appendMetadata(context, item, dtom, false, sb.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.MetadataValue;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to delete metadata
|
|
||||||
*/
|
|
||||||
public class DeleteMetadataAction extends UpdateMetadataAction {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete metadata from item
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param itarch Item Archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest,
|
|
||||||
boolean suppressUndo) throws AuthorizeException, ParseException, SQLException {
|
|
||||||
Item item = itarch.getItem();
|
|
||||||
for (String f : targetFields) {
|
|
||||||
DtoMetadata dummy = DtoMetadata.create(f, Item.ANY, "");
|
|
||||||
List<MetadataValue> ardcv = itemService.getMetadataByMetadataString(item, f);
|
|
||||||
|
|
||||||
ItemUpdate.pr("Metadata to be deleted: ");
|
|
||||||
for (MetadataValue dcv : ardcv) {
|
|
||||||
ItemUpdate.pr(" " + MetadataUtilities.getDCValueString(dcv));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isTest) {
|
|
||||||
if (!suppressUndo) {
|
|
||||||
for (MetadataValue dcv : ardcv) {
|
|
||||||
MetadataField metadataField = dcv.getMetadataField();
|
|
||||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
|
||||||
itarch.addUndoMetadataField(
|
|
||||||
DtoMetadata.create(metadataSchema.getName(), metadataField.getElement(),
|
|
||||||
metadataField.getQualifier(), dcv.getLanguage(), dcv.getValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
itemService.clearMetadata(context, item, dummy.schema, dummy.element, dummy.qualifier, Item.ANY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bitstream filter to delete from TEXT bundle
|
|
||||||
*/
|
|
||||||
public class DerivativeTextBitstreamFilter extends BitstreamFilterByBundleName {
|
|
||||||
|
|
||||||
public DerivativeTextBitstreamFilter() {
|
|
||||||
props = new Properties();
|
|
||||||
props.setProperty("bundle", "TEXT");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A data transfer object class enhancement of org.dspace.content.DCValue, which is deprecated
|
|
||||||
* Name intended to not conflict with DSpace API classes for similar concepts but not usable in this context
|
|
||||||
*
|
|
||||||
* Adds some utility methods
|
|
||||||
*
|
|
||||||
* Really not at all general enough but supports Dublin Core and the compound form notation {@code <schema>
|
|
||||||
* .<element>[.<qualifier>]}
|
|
||||||
*
|
|
||||||
* Does not support wildcard for qualifier
|
|
||||||
*/
|
|
||||||
class DtoMetadata {
|
|
||||||
final String schema;
|
|
||||||
final String element;
|
|
||||||
final String qualifier;
|
|
||||||
final String language;
|
|
||||||
final String value;
|
|
||||||
|
|
||||||
protected DtoMetadata(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method
|
|
||||||
*
|
|
||||||
* @param schema not null, not empty - 'dc' is the standard case
|
|
||||||
* @param element not null, not empty
|
|
||||||
* @param qualifier null; don't allow empty string or * indicating 'any'
|
|
||||||
* @param language null or empty
|
|
||||||
* @param value value
|
|
||||||
* @return DtoMetadata object
|
|
||||||
* @throws IllegalArgumentException if arg error
|
|
||||||
*/
|
|
||||||
public static DtoMetadata create(String schema,
|
|
||||||
String element,
|
|
||||||
String qualifier,
|
|
||||||
String language,
|
|
||||||
String value)
|
|
||||||
throws IllegalArgumentException {
|
|
||||||
if ((qualifier != null) && (qualifier.equals(Item.ANY) || qualifier.equals(""))) {
|
|
||||||
throw new IllegalArgumentException("Invalid qualifier: " + qualifier);
|
|
||||||
}
|
|
||||||
return new DtoMetadata(schema, element, qualifier, language, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create metadata object
|
|
||||||
*
|
|
||||||
* @param compoundForm of the form <schema>.<element>[.<qualifier>]
|
|
||||||
* @param language null or empty
|
|
||||||
* @param value value
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
* @throws IllegalArgumentException if arg error
|
|
||||||
*/
|
|
||||||
public static DtoMetadata create(String compoundForm, String language, String value)
|
|
||||||
throws ParseException, IllegalArgumentException {
|
|
||||||
String[] ar = MetadataUtilities.parseCompoundForm(compoundForm);
|
|
||||||
|
|
||||||
String qual = null;
|
|
||||||
if (ar.length > 2) {
|
|
||||||
qual = ar[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return create(ar[0], ar[1], qual, language, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if this metadata field matches the specified type:
|
|
||||||
* schema.element or schema.element.qualifier
|
|
||||||
*
|
|
||||||
* @param compoundForm of the form <schema>.<element>[.<qualifier>|.*]
|
|
||||||
* @param wildcard allow wildcards in compoundForm param
|
|
||||||
* @return whether matches
|
|
||||||
*/
|
|
||||||
public boolean matches(String compoundForm, boolean wildcard) {
|
|
||||||
String[] ar = compoundForm.split("\\s*\\.\\s*"); //MetadataUtilities.parseCompoundForm(compoundForm);
|
|
||||||
|
|
||||||
if ((ar.length < 2) || (ar.length > 3)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.schema.equals(ar[0]) || !this.element.equals(ar[1])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ar.length == 2) {
|
|
||||||
if (this.qualifier != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ar.length == 3) {
|
|
||||||
if (this.qualifier == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (wildcard && ar[2].equals(Item.ANY)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!this.qualifier.equals(ar[2])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
String s = "\tSchema: " + schema + " Element: " + element;
|
|
||||||
if (qualifier != null) {
|
|
||||||
s += " Qualifier: " + qualifier;
|
|
||||||
}
|
|
||||||
s += " Language: " + ((language == null) ? "[null]" : language);
|
|
||||||
s += " Value: " + value;
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,343 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.TransformerFactory;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.dspace.app.util.LocalSchemaFilenameFilter;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.handle.service.HandleService;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates the Item in the context of the DSpace Archive Format
|
|
||||||
*/
|
|
||||||
public class ItemArchive {
|
|
||||||
private static final Logger log = Logger.getLogger(ItemArchive.class);
|
|
||||||
|
|
||||||
public static final String DUBLIN_CORE_XML = "dublin_core.xml";
|
|
||||||
|
|
||||||
protected static DocumentBuilder builder = null;
|
|
||||||
protected Transformer transformer = null;
|
|
||||||
|
|
||||||
protected List<DtoMetadata> dtomList = null;
|
|
||||||
protected List<DtoMetadata> undoDtomList = new ArrayList<DtoMetadata>();
|
|
||||||
|
|
||||||
protected List<UUID> undoAddContents = new ArrayList<>(); // for undo of add
|
|
||||||
|
|
||||||
protected Item item;
|
|
||||||
protected File dir; // directory name in source archive for this item
|
|
||||||
protected String dirname; //convenience
|
|
||||||
|
|
||||||
protected HandleService handleService;
|
|
||||||
protected ItemService itemService;
|
|
||||||
|
|
||||||
//constructors
|
|
||||||
protected ItemArchive() {
|
|
||||||
handleService = HandleServiceFactory.getInstance().getHandleService();
|
|
||||||
itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* factory method
|
|
||||||
*
|
|
||||||
* Minimal requirements for dublin_core.xml for this application
|
|
||||||
* is the presence of dc.identifier.uri
|
|
||||||
* which must contain the handle for the item
|
|
||||||
*
|
|
||||||
* @param context - The DSpace context
|
|
||||||
* @param dir - The directory File in the source archive
|
|
||||||
* @param itemField - The metadata field in which the Item identifier is located
|
|
||||||
* if null, the default is the handle in the dc.identifier.uri field
|
|
||||||
* @return ItemArchive object
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public static ItemArchive create(Context context, File dir, String itemField)
|
|
||||||
throws Exception {
|
|
||||||
ItemArchive itarch = new ItemArchive();
|
|
||||||
itarch.dir = dir;
|
|
||||||
itarch.dirname = dir.getName();
|
|
||||||
InputStream is = null;
|
|
||||||
try {
|
|
||||||
is = new FileInputStream(new File(dir, DUBLIN_CORE_XML));
|
|
||||||
itarch.dtomList = MetadataUtilities.loadDublinCore(getDocumentBuilder(), is);
|
|
||||||
|
|
||||||
//The code to search for local schema files was copied from org.dspace.app.itemimport
|
|
||||||
// .ItemImportServiceImpl.java
|
|
||||||
File file[] = dir.listFiles(new LocalSchemaFilenameFilter());
|
|
||||||
for (int i = 0; i < file.length; i++) {
|
|
||||||
is = new FileInputStream(file[i]);
|
|
||||||
itarch.dtomList.addAll(MetadataUtilities.loadDublinCore(getDocumentBuilder(), is));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (is != null) {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ItemUpdate.pr("Loaded metadata with " + itarch.dtomList.size() + " fields");
|
|
||||||
|
|
||||||
if (itemField == null) {
|
|
||||||
itarch.item = itarch.itemFromHandleInput(context); // sets the item instance var and seeds the undo list
|
|
||||||
} else {
|
|
||||||
itarch.item = itarch.itemFromMetadataField(context, itemField);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itarch.item == null) {
|
|
||||||
throw new Exception("Item not instantiated: " + itarch.dirname);
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemUpdate.prv("item instantiated: " + itarch.item.getHandle());
|
|
||||||
|
|
||||||
return itarch;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static DocumentBuilder getDocumentBuilder()
|
|
||||||
throws ParserConfigurationException {
|
|
||||||
if (builder == null) {
|
|
||||||
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for Transformer
|
|
||||||
*
|
|
||||||
* @return Transformer
|
|
||||||
* @throws TransformerConfigurationException if config error
|
|
||||||
*/
|
|
||||||
protected Transformer getTransformer()
|
|
||||||
throws TransformerConfigurationException {
|
|
||||||
if (transformer == null) {
|
|
||||||
transformer = TransformerFactory.newInstance().newTransformer();
|
|
||||||
}
|
|
||||||
return transformer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for the DSpace item referenced in the archive
|
|
||||||
*
|
|
||||||
* @return DSpace item
|
|
||||||
*/
|
|
||||||
public Item getItem() {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for directory in archive on disk
|
|
||||||
*
|
|
||||||
* @return directory in archive
|
|
||||||
*/
|
|
||||||
public File getDirectory() {
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for directory name in archive
|
|
||||||
*
|
|
||||||
* @return directory name in archive
|
|
||||||
*/
|
|
||||||
public String getDirectoryName() {
|
|
||||||
return dirname;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add metadata field to undo list
|
|
||||||
*
|
|
||||||
* @param dtom DtoMetadata (represents metadata field)
|
|
||||||
*/
|
|
||||||
public void addUndoMetadataField(DtoMetadata dtom) {
|
|
||||||
this.undoDtomList.add(dtom);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getter for list of metadata fields
|
|
||||||
*
|
|
||||||
* @return list of metadata fields
|
|
||||||
*/
|
|
||||||
public List<DtoMetadata> getMetadataFields() {
|
|
||||||
return dtomList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add bitstream id to delete contents file
|
|
||||||
*
|
|
||||||
* @param bitstreamId bitstream ID
|
|
||||||
*/
|
|
||||||
public void addUndoDeleteContents(UUID bitstreamId) {
|
|
||||||
this.undoAddContents.add(bitstreamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain item from DSpace based on handle
|
|
||||||
* This is the default implementation
|
|
||||||
* that uses the dc.identifier.uri metadatafield
|
|
||||||
* that contains the item handle as its value
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
private Item itemFromHandleInput(Context context)
|
|
||||||
throws SQLException, Exception {
|
|
||||||
DtoMetadata dtom = getMetadataField("dc.identifier.uri");
|
|
||||||
if (dtom == null) {
|
|
||||||
throw new Exception("No dc.identier.uri field found for handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addUndoMetadataField(dtom); //seed the undo list with the uri
|
|
||||||
|
|
||||||
String uri = dtom.value;
|
|
||||||
|
|
||||||
if (!uri.startsWith(ItemUpdate.HANDLE_PREFIX)) {
|
|
||||||
throw new Exception("dc.identifier.uri for item " + uri
|
|
||||||
+ " does not begin with prefix: " + ItemUpdate.HANDLE_PREFIX);
|
|
||||||
}
|
|
||||||
|
|
||||||
String handle = uri.substring(ItemUpdate.HANDLE_PREFIX.length());
|
|
||||||
|
|
||||||
DSpaceObject dso = handleService.resolveToObject(context, handle);
|
|
||||||
if (dso instanceof Item) {
|
|
||||||
item = (Item) dso;
|
|
||||||
} else {
|
|
||||||
ItemUpdate.pr("Warning: item not instantiated");
|
|
||||||
throw new IllegalArgumentException("Item " + handle + " not instantiated.");
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find and instantiate Item from the dublin_core.xml based
|
|
||||||
* on the specified itemField for the item identifier,
|
|
||||||
*
|
|
||||||
* @param context - the DSpace context
|
|
||||||
* @param itemField - the compound form of the metadata element <schema>.<element>.<qualifier>
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
private Item itemFromMetadataField(Context context, String itemField)
|
|
||||||
throws SQLException, AuthorizeException, Exception {
|
|
||||||
DtoMetadata dtom = getMetadataField(itemField);
|
|
||||||
|
|
||||||
Item item = null;
|
|
||||||
|
|
||||||
if (dtom == null) {
|
|
||||||
throw new IllegalArgumentException("No field found for item identifier field: " + itemField);
|
|
||||||
}
|
|
||||||
ItemUpdate.prv("Metadata field to match for item: " + dtom.toString());
|
|
||||||
|
|
||||||
this.addUndoMetadataField(dtom); //seed the undo list with the identifier field
|
|
||||||
|
|
||||||
Iterator<Item> itr = itemService
|
|
||||||
.findByMetadataField(context, dtom.schema, dtom.element, dtom.qualifier, dtom.value);
|
|
||||||
int count = 0;
|
|
||||||
while (itr.hasNext()) {
|
|
||||||
item = itr.next();
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemUpdate.prv("items matching = " + count);
|
|
||||||
|
|
||||||
if (count != 1) {
|
|
||||||
throw new Exception("" + count + " items matching item identifier: " + dtom.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get DtoMetadata field
|
|
||||||
*
|
|
||||||
* @param compoundForm compound form
|
|
||||||
* @return DtoMetadata field
|
|
||||||
*/
|
|
||||||
private DtoMetadata getMetadataField(String compoundForm) {
|
|
||||||
for (DtoMetadata dtom : dtomList) {
|
|
||||||
if (dtom.matches(compoundForm, false)) {
|
|
||||||
return dtom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write undo directory and files to Disk in archive format
|
|
||||||
*
|
|
||||||
* @param undoDir - the root directory of the undo archive
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws ParserConfigurationException if config error
|
|
||||||
* @throws TransformerConfigurationException if transformer config error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws FileNotFoundException if file not found
|
|
||||||
*/
|
|
||||||
public void writeUndo(File undoDir)
|
|
||||||
throws IOException, ParserConfigurationException, TransformerConfigurationException,
|
|
||||||
TransformerException, FileNotFoundException {
|
|
||||||
// create directory for item
|
|
||||||
File dir = new File(undoDir, dirname);
|
|
||||||
if (!dir.exists() && !dir.mkdir()) {
|
|
||||||
log.error("Unable to create undo directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream out = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
out = new FileOutputStream(new File(dir, "dublin_core.xml"));
|
|
||||||
Document doc = MetadataUtilities.writeDublinCore(getDocumentBuilder(), undoDtomList);
|
|
||||||
MetadataUtilities.writeDocument(doc, getTransformer(), out);
|
|
||||||
|
|
||||||
// if undo has delete bitstream
|
|
||||||
if (undoAddContents.size() > 0) {
|
|
||||||
PrintWriter pw = null;
|
|
||||||
try {
|
|
||||||
File f = new File(dir, ItemUpdate.DELETE_CONTENTS_FILE);
|
|
||||||
pw = new PrintWriter(new BufferedWriter(new FileWriter(f)));
|
|
||||||
for (UUID i : undoAddContents) {
|
|
||||||
pw.println(i);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
pw.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (out != null) {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} //end class
|
|
||||||
@@ -1,566 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.eperson.service.EPersonService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides some batch editing capabilities for items in DSpace:
|
|
||||||
* Metadata fields - Add, Delete
|
|
||||||
* Bitstreams - Add, Delete
|
|
||||||
*
|
|
||||||
* The design has been for compatibility with ItemImporter
|
|
||||||
* in the use of the DSpace archive format which is used to
|
|
||||||
* specify changes on a per item basis. The directory names
|
|
||||||
* to correspond to each item are arbitrary and will only be
|
|
||||||
* used for logging purposes. The reference to the item is
|
|
||||||
* from a required dc.identifier with the item handle to be
|
|
||||||
* included in the dublin_core.xml (or similar metadata) file.
|
|
||||||
*
|
|
||||||
* Any combination of these actions is permitted in a single run of this class
|
|
||||||
* The order of actions is important when used in combination.
|
|
||||||
* It is the responsibility of the calling class (here, ItemUpdate)
|
|
||||||
* to register UpdateAction classes in the order to which they are
|
|
||||||
* to be performed.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* It is unfortunate that so much code needs to be borrowed
|
|
||||||
* from ItemImport as it is not reusable in private methods, etc.
|
|
||||||
* Some of this has been placed into the MetadataUtilities class
|
|
||||||
* for possible reuse elsewhere.
|
|
||||||
*
|
|
||||||
* @author W. Hays based on a conceptual design by R. Rodgers
|
|
||||||
*/
|
|
||||||
public class ItemUpdate {
|
|
||||||
|
|
||||||
public static final String SUPPRESS_UNDO_FILENAME = "suppress_undo";
|
|
||||||
|
|
||||||
public static final String CONTENTS_FILE = "contents";
|
|
||||||
public static final String DELETE_CONTENTS_FILE = "delete_contents";
|
|
||||||
|
|
||||||
public static String HANDLE_PREFIX = null;
|
|
||||||
public static final Map<String, String> filterAliases = new HashMap<String, String>();
|
|
||||||
|
|
||||||
public static boolean verbose = false;
|
|
||||||
|
|
||||||
protected static final EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService();
|
|
||||||
protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
static {
|
|
||||||
filterAliases.put("ORIGINAL", "org.dspace.app.itemupdate.OriginalBitstreamFilter");
|
|
||||||
filterAliases
|
|
||||||
.put("ORIGINAL_AND_DERIVATIVES", "org.dspace.app.itemupdate.OriginalWithDerivativesBitstreamFilter");
|
|
||||||
filterAliases.put("TEXT", "org.dspace.app.itemupdate.DerivativeTextBitstreamFilter");
|
|
||||||
filterAliases.put("THUMBNAIL", "org.dspace.app.itemupdate.ThumbnailBitstreamFilter");
|
|
||||||
}
|
|
||||||
|
|
||||||
// File listing filter to check for folders
|
|
||||||
static FilenameFilter directoryFilter = new FilenameFilter() {
|
|
||||||
@Override
|
|
||||||
public boolean accept(File dir, String n) {
|
|
||||||
File f = new File(dir.getAbsolutePath() + File.separatorChar + n);
|
|
||||||
return f.isDirectory();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// File listing filter to check for files (not directories)
|
|
||||||
static FilenameFilter fileFilter = new FilenameFilter() {
|
|
||||||
@Override
|
|
||||||
public boolean accept(File dir, String n) {
|
|
||||||
File f = new File(dir.getAbsolutePath() + File.separatorChar + n);
|
|
||||||
return (f.isFile());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// instance variables
|
|
||||||
protected ActionManager actionMgr = new ActionManager();
|
|
||||||
protected List<String> undoActionList = new ArrayList<String>();
|
|
||||||
protected String eperson;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param argv the command line arguments given
|
|
||||||
*/
|
|
||||||
public static void main(String[] argv) {
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
//processing basis for determining items
|
|
||||||
//item-specific changes with metadata in source directory with dublin_core.xml files
|
|
||||||
options.addOption("s", "source", true, "root directory of source dspace archive ");
|
|
||||||
|
|
||||||
//actions on items
|
|
||||||
options.addOption("a", "addmetadata", true,
|
|
||||||
"add metadata specified for each item; multiples separated by semicolon ';'");
|
|
||||||
options.addOption("d", "deletemetadata", true, "delete metadata specified for each item");
|
|
||||||
|
|
||||||
options.addOption("A", "addbitstreams", false, "add bitstreams as specified for each item");
|
|
||||||
|
|
||||||
// extra work to get optional argument
|
|
||||||
Option delBitstreamOption = new Option("D", "deletebitstreams", true,
|
|
||||||
"delete bitstreams as specified for each item");
|
|
||||||
delBitstreamOption.setOptionalArg(true);
|
|
||||||
delBitstreamOption.setArgName("BitstreamFilter");
|
|
||||||
options.addOption(delBitstreamOption);
|
|
||||||
|
|
||||||
//other params
|
|
||||||
options.addOption("e", "eperson", true, "email of eperson doing the update");
|
|
||||||
options.addOption("i", "itemfield", true,
|
|
||||||
"optional metadata field that containing item identifier; default is dc.identifier.uri");
|
|
||||||
options.addOption("F", "filter-properties", true, "filter class name; only for deleting bitstream");
|
|
||||||
options.addOption("v", "verbose", false, "verbose logging");
|
|
||||||
|
|
||||||
//special run states
|
|
||||||
options.addOption("t", "test", false, "test run - do not actually import items");
|
|
||||||
options.addOption("P", "provenance", false, "suppress altering provenance field for bitstream changes");
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
int status = 0;
|
|
||||||
boolean isTest = false;
|
|
||||||
boolean alterProvenance = true;
|
|
||||||
String itemField = null;
|
|
||||||
String metadataIndexName = null;
|
|
||||||
|
|
||||||
Context context = null;
|
|
||||||
ItemUpdate iu = new ItemUpdate();
|
|
||||||
|
|
||||||
try {
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("ItemUpdate", options);
|
|
||||||
pr("");
|
|
||||||
pr("Examples:");
|
|
||||||
pr(" adding metadata: ItemUpdate -e jsmith@mit.edu -s sourcedir -a dc.contributor -a dc.subject ");
|
|
||||||
pr(" deleting metadata: ItemUpdate -e jsmith@mit.edu -s sourcedir -d dc.description.other");
|
|
||||||
pr(" adding bitstreams: ItemUpdate -e jsmith@mit.edu -s sourcedir -A -i dc.identifier");
|
|
||||||
pr(" deleting bitstreams: ItemUpdate -e jsmith@mit.edu -s sourcedir -D ORIGINAL ");
|
|
||||||
pr("");
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('v')) {
|
|
||||||
verbose = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (line.hasOption('P')) {
|
|
||||||
alterProvenance = false;
|
|
||||||
pr("Suppressing changes to Provenance field option");
|
|
||||||
}
|
|
||||||
|
|
||||||
iu.eperson = line.getOptionValue('e'); // db ID or email
|
|
||||||
|
|
||||||
if (!line.hasOption('s')) { // item specific changes from archive dir
|
|
||||||
pr("Missing source archive option");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
String sourcedir = line.getOptionValue('s');
|
|
||||||
|
|
||||||
if (line.hasOption('t')) { //test
|
|
||||||
isTest = true;
|
|
||||||
pr("**Test Run** - not actually updating items.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('i')) {
|
|
||||||
itemField = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('d')) {
|
|
||||||
String[] targetFields = line.getOptionValues('d');
|
|
||||||
|
|
||||||
DeleteMetadataAction delMetadataAction = (DeleteMetadataAction) iu.actionMgr
|
|
||||||
.getUpdateAction(DeleteMetadataAction.class);
|
|
||||||
delMetadataAction.addTargetFields(targetFields);
|
|
||||||
|
|
||||||
//undo is an add
|
|
||||||
for (String field : targetFields) {
|
|
||||||
iu.undoActionList.add(" -a " + field + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
pr("Delete metadata for fields: ");
|
|
||||||
for (String s : targetFields) {
|
|
||||||
pr(" " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('a')) {
|
|
||||||
String[] targetFields = line.getOptionValues('a');
|
|
||||||
|
|
||||||
AddMetadataAction addMetadataAction = (AddMetadataAction) iu.actionMgr
|
|
||||||
.getUpdateAction(AddMetadataAction.class);
|
|
||||||
addMetadataAction.addTargetFields(targetFields);
|
|
||||||
|
|
||||||
//undo is a delete followed by an add of a replace record for target fields
|
|
||||||
for (String field : targetFields) {
|
|
||||||
iu.undoActionList.add(" -d " + field + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String field : targetFields) {
|
|
||||||
iu.undoActionList.add(" -a " + field + " ");
|
|
||||||
}
|
|
||||||
|
|
||||||
pr("Add metadata for fields: ");
|
|
||||||
for (String s : targetFields) {
|
|
||||||
pr(" " + s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('D')) { // undo not supported
|
|
||||||
pr("Delete bitstreams ");
|
|
||||||
|
|
||||||
String[] filterNames = line.getOptionValues('D');
|
|
||||||
if ((filterNames != null) && (filterNames.length > 1)) {
|
|
||||||
pr("Error: Only one filter can be a used at a time.");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
String filterName = line.getOptionValue('D');
|
|
||||||
pr("Filter argument: " + filterName);
|
|
||||||
|
|
||||||
if (filterName == null) { // indicates using delete_contents files
|
|
||||||
DeleteBitstreamsAction delAction = (DeleteBitstreamsAction) iu.actionMgr
|
|
||||||
.getUpdateAction(DeleteBitstreamsAction.class);
|
|
||||||
delAction.setAlterProvenance(alterProvenance);
|
|
||||||
} else {
|
|
||||||
// check if param is on ALIAS list
|
|
||||||
String filterClassname = filterAliases.get(filterName);
|
|
||||||
|
|
||||||
if (filterClassname == null) {
|
|
||||||
filterClassname = filterName;
|
|
||||||
}
|
|
||||||
|
|
||||||
BitstreamFilter filter = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class<?> cfilter = Class.forName(filterClassname);
|
|
||||||
pr("BitstreamFilter class to instantiate: " + cfilter.toString());
|
|
||||||
|
|
||||||
filter = (BitstreamFilter) cfilter.newInstance(); //unfortunate cast, an erasure consequence
|
|
||||||
} catch (Exception e) {
|
|
||||||
pr("Error: Failure instantiating bitstream filter class: " + filterClassname);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
String filterPropertiesName = line.getOptionValue('F');
|
|
||||||
if (filterPropertiesName != null) { //not always required
|
|
||||||
try {
|
|
||||||
// TODO try multiple relative locations, e.g. source dir
|
|
||||||
if (!filterPropertiesName.startsWith("/")) {
|
|
||||||
filterPropertiesName = sourcedir + File.separator + filterPropertiesName;
|
|
||||||
}
|
|
||||||
|
|
||||||
filter.initProperties(filterPropertiesName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
pr("Error: Failure finding properties file for bitstream filter class: " +
|
|
||||||
filterPropertiesName);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DeleteBitstreamsByFilterAction delAction =
|
|
||||||
(DeleteBitstreamsByFilterAction) iu.actionMgr
|
|
||||||
.getUpdateAction(DeleteBitstreamsByFilterAction.class);
|
|
||||||
delAction.setAlterProvenance(alterProvenance);
|
|
||||||
delAction.setBitstreamFilter(filter);
|
|
||||||
//undo not supported
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('A')) {
|
|
||||||
pr("Add bitstreams ");
|
|
||||||
AddBitstreamsAction addAction = (AddBitstreamsAction) iu.actionMgr
|
|
||||||
.getUpdateAction(AddBitstreamsAction.class);
|
|
||||||
addAction.setAlterProvenance(alterProvenance);
|
|
||||||
|
|
||||||
iu.undoActionList.add(" -D "); // delete_contents file will be written, no arg required
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!iu.actionMgr.hasActions()) {
|
|
||||||
pr("Error - an action must be specified");
|
|
||||||
System.exit(1);
|
|
||||||
} else {
|
|
||||||
pr("Actions to be performed: ");
|
|
||||||
|
|
||||||
for (UpdateAction ua : iu.actionMgr) {
|
|
||||||
pr(" " + ua.getClass().getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pr("ItemUpdate - initializing run on " + (new Date()).toString());
|
|
||||||
|
|
||||||
context = new Context(Context.Mode.BATCH_EDIT);
|
|
||||||
iu.setEPerson(context, iu.eperson);
|
|
||||||
context.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
HANDLE_PREFIX = ConfigurationManager.getProperty("handle.canonical.prefix");
|
|
||||||
if (HANDLE_PREFIX == null || HANDLE_PREFIX.length() == 0) {
|
|
||||||
HANDLE_PREFIX = "http://hdl.handle.net/";
|
|
||||||
}
|
|
||||||
|
|
||||||
iu.processArchive(context, sourcedir, itemField, metadataIndexName, alterProvenance, isTest);
|
|
||||||
|
|
||||||
context.complete(); // complete all transactions
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (context != null && context.isValid()) {
|
|
||||||
context.abort();
|
|
||||||
}
|
|
||||||
e.printStackTrace();
|
|
||||||
pr(e.toString());
|
|
||||||
status = 1;
|
|
||||||
} finally {
|
|
||||||
context.restoreAuthSystemState();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTest) {
|
|
||||||
pr("***End of Test Run***");
|
|
||||||
} else {
|
|
||||||
pr("End.");
|
|
||||||
|
|
||||||
}
|
|
||||||
System.exit(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* process an archive
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param sourceDirPath source path
|
|
||||||
* @param itemField item field
|
|
||||||
* @param metadataIndexName index name
|
|
||||||
* @param alterProvenance whether to alter provenance
|
|
||||||
* @param isTest test flag
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
protected void processArchive(Context context, String sourceDirPath, String itemField,
|
|
||||||
String metadataIndexName, boolean alterProvenance, boolean isTest)
|
|
||||||
throws Exception {
|
|
||||||
// open and process the source directory
|
|
||||||
File sourceDir = new File(sourceDirPath);
|
|
||||||
|
|
||||||
if ((sourceDir == null) || !sourceDir.exists() || !sourceDir.isDirectory()) {
|
|
||||||
pr("Error, cannot open archive source directory " + sourceDirPath);
|
|
||||||
throw new Exception("error with archive source directory " + sourceDirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] dircontents = sourceDir.list(directoryFilter); //just the names, not the path
|
|
||||||
Arrays.sort(dircontents);
|
|
||||||
|
|
||||||
//Undo is suppressed to prevent undo of undo
|
|
||||||
boolean suppressUndo = false;
|
|
||||||
File fSuppressUndo = new File(sourceDir, SUPPRESS_UNDO_FILENAME);
|
|
||||||
if (fSuppressUndo.exists()) {
|
|
||||||
suppressUndo = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
File undoDir = null; //sibling directory of source archive
|
|
||||||
|
|
||||||
if (!suppressUndo && !isTest) {
|
|
||||||
undoDir = initUndoArchive(sourceDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
int itemCount = 0;
|
|
||||||
int successItemCount = 0;
|
|
||||||
|
|
||||||
for (String dirname : dircontents) {
|
|
||||||
itemCount++;
|
|
||||||
pr("");
|
|
||||||
pr("processing item " + dirname);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ItemArchive itarch = ItemArchive.create(context, new File(sourceDir, dirname), itemField);
|
|
||||||
|
|
||||||
for (UpdateAction action : actionMgr) {
|
|
||||||
pr("action: " + action.getClass().getName());
|
|
||||||
action.execute(context, itarch, isTest, suppressUndo);
|
|
||||||
if (!isTest && !suppressUndo) {
|
|
||||||
itarch.writeUndo(undoDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!isTest) {
|
|
||||||
Item item = itarch.getItem();
|
|
||||||
itemService.update(context, item); //need to update before commit
|
|
||||||
context.uncacheEntity(item);
|
|
||||||
}
|
|
||||||
ItemUpdate.pr("Item " + dirname + " completed");
|
|
||||||
successItemCount++;
|
|
||||||
} catch (Exception e) {
|
|
||||||
pr("Exception processing item " + dirname + ": " + e.toString());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!suppressUndo && !isTest) {
|
|
||||||
StringBuilder sb = new StringBuilder("dsrun org.dspace.app.itemupdate.ItemUpdate ");
|
|
||||||
sb.append(" -e ").append(this.eperson);
|
|
||||||
sb.append(" -s ").append(undoDir);
|
|
||||||
|
|
||||||
if (itemField != null) {
|
|
||||||
sb.append(" -i ").append(itemField);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!alterProvenance) {
|
|
||||||
sb.append(" -P ");
|
|
||||||
}
|
|
||||||
if (isTest) {
|
|
||||||
sb.append(" -t ");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String actionOption : undoActionList) {
|
|
||||||
sb.append(actionOption);
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintWriter pw = null;
|
|
||||||
try {
|
|
||||||
File cmdFile = new File(undoDir.getParent(), undoDir.getName() + "_command.sh");
|
|
||||||
pw = new PrintWriter(new BufferedWriter(new FileWriter(cmdFile)));
|
|
||||||
pw.println(sb.toString());
|
|
||||||
} finally {
|
|
||||||
pw.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pr("");
|
|
||||||
pr("Done processing. Successful items: " + successItemCount + " of " + itemCount + " items in source archive");
|
|
||||||
pr("");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* to avoid overwriting the undo source tree on repeated processing
|
|
||||||
* sequence numbers are added and checked
|
|
||||||
*
|
|
||||||
* @param sourceDir - the original source directory
|
|
||||||
* @return the directory of the undo archive
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws IOException if IO error
|
|
||||||
*/
|
|
||||||
protected File initUndoArchive(File sourceDir)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
File parentDir = sourceDir.getCanonicalFile().getParentFile();
|
|
||||||
if (parentDir == null) {
|
|
||||||
throw new FileNotFoundException(
|
|
||||||
"Parent directory of archive directory not found; unable to write UndoArchive; no processing " +
|
|
||||||
"performed");
|
|
||||||
}
|
|
||||||
|
|
||||||
String sourceDirName = sourceDir.getName();
|
|
||||||
int seqNo = 1;
|
|
||||||
|
|
||||||
File undoDir = new File(parentDir, "undo_" + sourceDirName + "_" + seqNo);
|
|
||||||
while (undoDir.exists()) {
|
|
||||||
undoDir = new File(parentDir, "undo_" + sourceDirName + "_" + ++seqNo); //increment
|
|
||||||
}
|
|
||||||
|
|
||||||
// create root directory
|
|
||||||
if (!undoDir.mkdir()) {
|
|
||||||
pr("ERROR creating Undo Archive directory " + undoDir.getCanonicalPath());
|
|
||||||
throw new IOException("ERROR creating Undo Archive directory " + undoDir.getCanonicalPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Undo is suppressed to prevent undo of undo
|
|
||||||
File fSuppressUndo = new File(undoDir, ItemUpdate.SUPPRESS_UNDO_FILENAME);
|
|
||||||
try {
|
|
||||||
fSuppressUndo.createNewFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
pr("ERROR creating Suppress Undo File " + e.toString());
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return undoDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
//private void write
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set EPerson doing import
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param eperson EPerson obj
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
protected void setEPerson(Context context, String eperson)
|
|
||||||
throws Exception {
|
|
||||||
if (eperson == null) {
|
|
||||||
pr("Error - an eperson to do the importing must be specified");
|
|
||||||
pr(" (run with -h flag for details)");
|
|
||||||
throw new Exception("EPerson not specified.");
|
|
||||||
}
|
|
||||||
|
|
||||||
EPerson myEPerson = null;
|
|
||||||
|
|
||||||
if (eperson.indexOf('@') != -1) {
|
|
||||||
// @ sign, must be an email
|
|
||||||
myEPerson = epersonService.findByEmail(context, eperson);
|
|
||||||
} else {
|
|
||||||
myEPerson = epersonService.find(context, UUID.fromString(eperson));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myEPerson == null) {
|
|
||||||
pr("Error, eperson cannot be found: " + eperson);
|
|
||||||
throw new Exception("Invalid EPerson");
|
|
||||||
}
|
|
||||||
|
|
||||||
context.setCurrentUser(myEPerson);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* poor man's logging
|
|
||||||
* As with ItemImport, API logging goes through log4j to the DSpace.log files
|
|
||||||
* whereas the batch logging goes to the console to be captured there.
|
|
||||||
*
|
|
||||||
* @param s String
|
|
||||||
*/
|
|
||||||
static void pr(String s) {
|
|
||||||
System.out.println(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* print if verbose flag is set
|
|
||||||
*
|
|
||||||
* @param s String
|
|
||||||
*/
|
|
||||||
static void prv(String s) {
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} //end of class
|
|
||||||
|
|
||||||
@@ -1,465 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
|
||||||
import javax.xml.transform.Result;
|
|
||||||
import javax.xml.transform.Source;
|
|
||||||
import javax.xml.transform.Transformer;
|
|
||||||
import javax.xml.transform.TransformerConfigurationException;
|
|
||||||
import javax.xml.transform.TransformerException;
|
|
||||||
import javax.xml.transform.dom.DOMSource;
|
|
||||||
import javax.xml.transform.stream.StreamResult;
|
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
|
||||||
import org.apache.xpath.XPathAPI;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.MetadataField;
|
|
||||||
import org.dspace.content.MetadataSchema;
|
|
||||||
import org.dspace.content.MetadataValue;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.Element;
|
|
||||||
import org.w3c.dom.NamedNodeMap;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
import org.xml.sax.SAXException;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Miscellaneous methods for metadata handling that build on the API
|
|
||||||
* which might have general utility outside of the specific use
|
|
||||||
* in context in ItemUpdate.
|
|
||||||
*
|
|
||||||
* The XML methods were based on those in ItemImport
|
|
||||||
*/
|
|
||||||
public class MetadataUtilities {
|
|
||||||
|
|
||||||
protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private MetadataUtilities() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Working around Item API to delete a value-specific Metadatum
|
|
||||||
* For a given element/qualifier/lang:
|
|
||||||
* get all DCValues
|
|
||||||
* clear (i.e. delete) all of these DCValues
|
|
||||||
* add them back, minus the one to actually delete
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param item Item Object
|
|
||||||
* @param dtom metadata field
|
|
||||||
* @param isLanguageStrict whether strict or not
|
|
||||||
* @return true if metadata field is found with matching value and was deleted
|
|
||||||
* @throws SQLException if database error
|
|
||||||
*/
|
|
||||||
public static boolean deleteMetadataByValue(Context context, Item item, DtoMetadata dtom, boolean isLanguageStrict)
|
|
||||||
throws SQLException {
|
|
||||||
List<MetadataValue> ar = null;
|
|
||||||
|
|
||||||
if (isLanguageStrict) { // get all for given type
|
|
||||||
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
|
|
||||||
} else {
|
|
||||||
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean found = false;
|
|
||||||
|
|
||||||
//build new set minus the one to delete
|
|
||||||
List<String> vals = new ArrayList<String>();
|
|
||||||
for (MetadataValue dcv : ar) {
|
|
||||||
if (dcv.getValue().equals(dtom.value)) {
|
|
||||||
found = true;
|
|
||||||
} else {
|
|
||||||
vals.add(dcv.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found) { //remove all for given type ??synchronize this block??
|
|
||||||
if (isLanguageStrict) {
|
|
||||||
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
|
|
||||||
} else {
|
|
||||||
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
itemService.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals);
|
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append text to value metadata field to item
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param item DSpace Item
|
|
||||||
* @param dtom metadata field
|
|
||||||
* @param isLanguageStrict if strict
|
|
||||||
* @param textToAppend text to append
|
|
||||||
* @throws IllegalArgumentException - When target metadata field is not found
|
|
||||||
* @throws SQLException if database error
|
|
||||||
*/
|
|
||||||
public static void appendMetadata(Context context, Item item, DtoMetadata dtom, boolean isLanguageStrict,
|
|
||||||
String textToAppend)
|
|
||||||
throws IllegalArgumentException, SQLException {
|
|
||||||
List<MetadataValue> ar = null;
|
|
||||||
|
|
||||||
// get all values for given element/qualifier
|
|
||||||
if (isLanguageStrict) { // get all for given element/qualifier
|
|
||||||
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
|
|
||||||
} else {
|
|
||||||
ar = itemService.getMetadata(item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ar.size() == 0) {
|
|
||||||
throw new IllegalArgumentException("Metadata to append to not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
int idx = 0; //index of field to change
|
|
||||||
if (ar.size() > 1) { //need to pick one, can't be sure it's the last one
|
|
||||||
// TODO maybe get highest id ?
|
|
||||||
}
|
|
||||||
|
|
||||||
//build new set minus the one to delete
|
|
||||||
List<String> vals = new ArrayList<String>();
|
|
||||||
for (int i = 0; i < ar.size(); i++) {
|
|
||||||
if (i == idx) {
|
|
||||||
vals.add(ar.get(i).getValue() + textToAppend);
|
|
||||||
} else {
|
|
||||||
vals.add(ar.get(i).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLanguageStrict) {
|
|
||||||
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language);
|
|
||||||
} else {
|
|
||||||
itemService.clearMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, Item.ANY);
|
|
||||||
}
|
|
||||||
|
|
||||||
itemService.addMetadata(context, item, dtom.schema, dtom.element, dtom.qualifier, dtom.language, vals);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Modification of method from ItemImporter.loadDublinCore
|
|
||||||
* as a Factory method
|
|
||||||
*
|
|
||||||
* @param docBuilder DocumentBuilder
|
|
||||||
* @param is - InputStream of dublin_core.xml
|
|
||||||
* @return list of DtoMetadata representing the metadata fields relating to an Item
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws ParserConfigurationException if parser config error
|
|
||||||
* @throws SAXException if XML error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
*/
|
|
||||||
public static List<DtoMetadata> loadDublinCore(DocumentBuilder docBuilder, InputStream is)
|
|
||||||
throws SQLException, IOException, ParserConfigurationException,
|
|
||||||
SAXException, TransformerException, AuthorizeException {
|
|
||||||
Document document = docBuilder.parse(is);
|
|
||||||
|
|
||||||
List<DtoMetadata> dtomList = new ArrayList<DtoMetadata>();
|
|
||||||
|
|
||||||
// Get the schema, for backward compatibility we will default to the
|
|
||||||
// dublin core schema if the schema name is not available in the import file
|
|
||||||
String schema = null;
|
|
||||||
NodeList metadata = XPathAPI.selectNodeList(document, "/dublin_core");
|
|
||||||
Node schemaAttr = metadata.item(0).getAttributes().getNamedItem("schema");
|
|
||||||
if (schemaAttr == null) {
|
|
||||||
schema = MetadataSchema.DC_SCHEMA;
|
|
||||||
} else {
|
|
||||||
schema = schemaAttr.getNodeValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the nodes corresponding to formats
|
|
||||||
NodeList dcNodes = XPathAPI.selectNodeList(document, "/dublin_core/dcvalue");
|
|
||||||
|
|
||||||
for (int i = 0; i < dcNodes.getLength(); i++) {
|
|
||||||
Node n = dcNodes.item(i);
|
|
||||||
String value = getStringValue(n).trim();
|
|
||||||
// compensate for empty value getting read as "null", which won't display
|
|
||||||
if (value == null) {
|
|
||||||
value = "";
|
|
||||||
}
|
|
||||||
String element = getAttributeValue(n, "element");
|
|
||||||
if (element != null) {
|
|
||||||
element = element.trim();
|
|
||||||
}
|
|
||||||
String qualifier = getAttributeValue(n, "qualifier");
|
|
||||||
if (qualifier != null) {
|
|
||||||
qualifier = qualifier.trim();
|
|
||||||
}
|
|
||||||
String language = getAttributeValue(n, "language");
|
|
||||||
if (language != null) {
|
|
||||||
language = language.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("none".equals(qualifier) || "".equals(qualifier)) {
|
|
||||||
qualifier = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// a goofy default, but consistent with DSpace treatment elsewhere
|
|
||||||
if (language == null) {
|
|
||||||
language = "en";
|
|
||||||
} else if ("".equals(language)) {
|
|
||||||
language = ConfigurationManager.getProperty("default.language");
|
|
||||||
}
|
|
||||||
|
|
||||||
DtoMetadata dtom = DtoMetadata.create(schema, element, qualifier, language, value);
|
|
||||||
ItemUpdate.pr(dtom.toString());
|
|
||||||
dtomList.add(dtom);
|
|
||||||
}
|
|
||||||
return dtomList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write dublin_core.xml
|
|
||||||
*
|
|
||||||
* @param docBuilder DocumentBuilder
|
|
||||||
* @param dtomList List of metadata fields
|
|
||||||
* @return xml document
|
|
||||||
* @throws ParserConfigurationException if parser config error
|
|
||||||
* @throws TransformerConfigurationException if transformer config error
|
|
||||||
* @throws TransformerException if transformer error
|
|
||||||
*/
|
|
||||||
public static Document writeDublinCore(DocumentBuilder docBuilder, List<DtoMetadata> dtomList)
|
|
||||||
throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
|
|
||||||
Document doc = docBuilder.newDocument();
|
|
||||||
Element root = doc.createElement("dublin_core");
|
|
||||||
doc.appendChild(root);
|
|
||||||
|
|
||||||
for (DtoMetadata dtom : dtomList) {
|
|
||||||
Element mel = doc.createElement("dcvalue");
|
|
||||||
mel.setAttribute("element", dtom.element);
|
|
||||||
if (dtom.qualifier == null) {
|
|
||||||
mel.setAttribute("qualifier", "none");
|
|
||||||
} else {
|
|
||||||
mel.setAttribute("qualifier", dtom.qualifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(dtom.language)) {
|
|
||||||
mel.setAttribute("language", "en");
|
|
||||||
} else {
|
|
||||||
mel.setAttribute("language", dtom.language);
|
|
||||||
}
|
|
||||||
mel.setTextContent(dtom.value);
|
|
||||||
root.appendChild(mel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* write xml document to output stream
|
|
||||||
*
|
|
||||||
* @param doc XML Document
|
|
||||||
* @param transformer XML Transformer
|
|
||||||
* @param out OutputStream
|
|
||||||
* @throws IOException if IO Error
|
|
||||||
* @throws TransformerException if Transformer error
|
|
||||||
*/
|
|
||||||
public static void writeDocument(Document doc, Transformer transformer, OutputStream out)
|
|
||||||
throws IOException, TransformerException {
|
|
||||||
Source src = new DOMSource(doc);
|
|
||||||
Result dest = new StreamResult(out);
|
|
||||||
transformer.transform(src, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// XML utility methods
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lookup an attribute from a DOM node.
|
|
||||||
*
|
|
||||||
* @param n Node
|
|
||||||
* @param name name
|
|
||||||
* @return attribute value
|
|
||||||
*/
|
|
||||||
private static String getAttributeValue(Node n, String name) {
|
|
||||||
NamedNodeMap nm = n.getAttributes();
|
|
||||||
|
|
||||||
for (int i = 0; i < nm.getLength(); i++) {
|
|
||||||
Node node = nm.item(i);
|
|
||||||
|
|
||||||
if (name.equals(node.getNodeName())) {
|
|
||||||
return node.getNodeValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the String value of a Node.
|
|
||||||
*
|
|
||||||
* @param node node
|
|
||||||
* @return string value
|
|
||||||
*/
|
|
||||||
private static String getStringValue(Node node) {
|
|
||||||
String value = node.getNodeValue();
|
|
||||||
|
|
||||||
if (node.hasChildNodes()) {
|
|
||||||
Node first = node.getFirstChild();
|
|
||||||
|
|
||||||
if (first.getNodeType() == Node.TEXT_NODE) {
|
|
||||||
return first.getNodeValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewrite of ItemImport's functionality
|
|
||||||
* but just the parsing of the file, not the processing of its elements.
|
|
||||||
*
|
|
||||||
* @param f file
|
|
||||||
* @return list of ContentsEntry
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws ParseException if parse error
|
|
||||||
*/
|
|
||||||
public static List<ContentsEntry> readContentsFile(File f)
|
|
||||||
throws FileNotFoundException, IOException, ParseException {
|
|
||||||
List<ContentsEntry> list = new ArrayList<ContentsEntry>();
|
|
||||||
|
|
||||||
BufferedReader in = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
in = new BufferedReader(new FileReader(f));
|
|
||||||
String line = null;
|
|
||||||
|
|
||||||
while ((line = in.readLine()) != null) {
|
|
||||||
line = line.trim();
|
|
||||||
if ("".equals(line)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ItemUpdate.pr("Contents entry: " + line);
|
|
||||||
list.add(ContentsEntry.parse(line));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
//skip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param f file
|
|
||||||
* @return list of lines as strings
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws IOException if IO Error
|
|
||||||
*/
|
|
||||||
public static List<String> readDeleteContentsFile(File f)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
|
|
||||||
BufferedReader in = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
in = new BufferedReader(new FileReader(f));
|
|
||||||
String line = null;
|
|
||||||
|
|
||||||
while ((line = in.readLine()) != null) {
|
|
||||||
line = line.trim();
|
|
||||||
if ("".equals(line)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.add(line);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
in.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
//skip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get display of Metadatum
|
|
||||||
*
|
|
||||||
* @param dcv MetadataValue
|
|
||||||
* @return string displaying elements of the Metadatum
|
|
||||||
*/
|
|
||||||
public static String getDCValueString(MetadataValue dcv) {
|
|
||||||
MetadataField metadataField = dcv.getMetadataField();
|
|
||||||
MetadataSchema metadataSchema = metadataField.getMetadataSchema();
|
|
||||||
return "schema: " + metadataSchema.getName() + "; element: " + metadataField
|
|
||||||
.getElement() + "; qualifier: " + metadataField.getQualifier() +
|
|
||||||
"; language: " + dcv.getLanguage() + "; value: " + dcv.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return compound form of a metadata field (i.e. schema.element.qualifier)
|
|
||||||
*
|
|
||||||
* @param schema schema
|
|
||||||
* @param element element
|
|
||||||
* @param qualifier qualifier
|
|
||||||
* @return a String representation of the two- or three-part form of a metadata element
|
|
||||||
* e.g. dc.identifier.uri
|
|
||||||
*/
|
|
||||||
public static String getCompoundForm(String schema, String element, String qualifier) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append(schema).append(".").append(element);
|
|
||||||
|
|
||||||
if (qualifier != null) {
|
|
||||||
sb.append(".").append(qualifier);
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses metadata field given in the form {@code <schema>.<element>[.<qualifier>|.*]}
|
|
||||||
* checks for correct number of elements (2 or 3) and for empty strings
|
|
||||||
*
|
|
||||||
* @param compoundForm compound form of metadata field
|
|
||||||
* @return String Array
|
|
||||||
* @throws ParseException if validity checks fail
|
|
||||||
*/
|
|
||||||
public static String[] parseCompoundForm(String compoundForm)
|
|
||||||
throws ParseException {
|
|
||||||
String[] ar = compoundForm.split("\\s*\\.\\s*"); //trim ends
|
|
||||||
|
|
||||||
if ("".equals(ar[0])) {
|
|
||||||
throw new ParseException("schema is empty string: " + compoundForm, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ar.length < 2) || (ar.length > 3) || "".equals(ar[1])) {
|
|
||||||
throw new ParseException("element is malformed or empty string: " + compoundForm, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ar;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter all bitstreams in the ORIGINAL bundle
|
|
||||||
* Also delete all derivative bitstreams, i.e.
|
|
||||||
* all bitstreams in the TEXT and THUMBNAIL bundles
|
|
||||||
*/
|
|
||||||
public class OriginalBitstreamFilter extends BitstreamFilterByBundleName {
|
|
||||||
public OriginalBitstreamFilter() {
|
|
||||||
//empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests bitstreams for containment in an ORIGINAL bundle
|
|
||||||
*
|
|
||||||
* @param bitstream Bitstream
|
|
||||||
* @return true if the bitstream is in the ORIGINAL bundle
|
|
||||||
* @throws BitstreamFilterException if filter error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean accept(Bitstream bitstream)
|
|
||||||
throws BitstreamFilterException {
|
|
||||||
try {
|
|
||||||
List<Bundle> bundles = bitstream.getBundles();
|
|
||||||
for (Bundle bundle : bundles) {
|
|
||||||
if (bundle.getName().equals("ORIGINAL")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new BitstreamFilterException(e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter all bitstreams in the ORIGINAL bundle
|
|
||||||
* Also delete all derivative bitstreams, i.e.
|
|
||||||
* all bitstreams in the TEXT and THUMBNAIL bundles
|
|
||||||
*/
|
|
||||||
public class OriginalWithDerivativesBitstreamFilter extends BitstreamFilter {
|
|
||||||
protected String[] bundlesToEmpty = {"ORIGINAL", "TEXT", "THUMBNAIL"};
|
|
||||||
|
|
||||||
public OriginalWithDerivativesBitstreamFilter() {
|
|
||||||
//empty
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests bitstream for membership in specified bundles (ORIGINAL, TEXT, THUMBNAIL)
|
|
||||||
*
|
|
||||||
* @param bitstream Bitstream
|
|
||||||
* @return true if bitstream is in specified bundles
|
|
||||||
* @throws BitstreamFilterException if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean accept(Bitstream bitstream)
|
|
||||||
throws BitstreamFilterException {
|
|
||||||
try {
|
|
||||||
List<Bundle> bundles = bitstream.getBundles();
|
|
||||||
for (Bundle b : bundles) {
|
|
||||||
for (String bn : bundlesToEmpty) {
|
|
||||||
if (b.getName().equals(bn)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
throw new BitstreamFilterException(e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bitstream filter targetting the THUMBNAIL bundle
|
|
||||||
*/
|
|
||||||
public class ThumbnailBitstreamFilter extends BitstreamFilterByBundleName {
|
|
||||||
|
|
||||||
public ThumbnailBitstreamFilter() {
|
|
||||||
props = new Properties();
|
|
||||||
props.setProperty("bundle", "THUMBNAIL");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for actions to update an item
|
|
||||||
*/
|
|
||||||
public interface UpdateAction {
|
|
||||||
public ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action to update item
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param itarch item archive
|
|
||||||
* @param isTest test flag
|
|
||||||
* @param suppressUndo undo flag
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void execute(Context context, ItemArchive itarch, boolean isTest, boolean suppressUndo)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.BitstreamService;
|
|
||||||
import org.dspace.content.service.BundleService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for Bitstream actions
|
|
||||||
*/
|
|
||||||
public abstract class UpdateBitstreamsAction implements UpdateAction {
|
|
||||||
|
|
||||||
protected boolean alterProvenance = true;
|
|
||||||
|
|
||||||
|
|
||||||
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
|
|
||||||
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set variable to indicate that the dc.description.provenance field may
|
|
||||||
* be changed as a result of Bitstream changes by ItemUpdate
|
|
||||||
*
|
|
||||||
* @param alterProvenance whether to alter provenance
|
|
||||||
*/
|
|
||||||
public void setAlterProvenance(boolean alterProvenance) {
|
|
||||||
this.alterProvenance = alterProvenance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return boolean value to indicate whether the dc.description.provenance field may
|
|
||||||
* be changed as a result of Bitstream changes by ItemUpdate
|
|
||||||
*/
|
|
||||||
public boolean getAlterProvenance() {
|
|
||||||
return alterProvenance;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.itemupdate;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This abstract subclass for metadata actions
|
|
||||||
* maintains a collection for the target metadata fields
|
|
||||||
* expressed as a string in the compound notation ( {@code <schema>.<element>.<qualifier>} )
|
|
||||||
* on which to apply the action when the method execute is called.
|
|
||||||
*
|
|
||||||
* Implemented as a Set to avoid problems with duplicates
|
|
||||||
*/
|
|
||||||
public abstract class UpdateMetadataAction implements UpdateAction {
|
|
||||||
|
|
||||||
protected Set<String> targetFields = new HashSet<String>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get target fields
|
|
||||||
*
|
|
||||||
* @return set of fields to update
|
|
||||||
*/
|
|
||||||
public Set<String> getTargetFields() {
|
|
||||||
return targetFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set target fields
|
|
||||||
*
|
|
||||||
* @param targetFields Set of target fields to update
|
|
||||||
*/
|
|
||||||
public void addTargetFields(Set<String> targetFields) {
|
|
||||||
for (String tf : targetFields) {
|
|
||||||
this.targetFields.add(tf);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add array of target fields to update
|
|
||||||
*
|
|
||||||
* @param targetFields array of target fields to update
|
|
||||||
*/
|
|
||||||
public void addTargetFields(String[] targetFields) {
|
|
||||||
for (String tf : targetFields) {
|
|
||||||
this.targetFields.add(tf);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add single field to update
|
|
||||||
*
|
|
||||||
* @param targetField target field to update
|
|
||||||
*/
|
|
||||||
public void addTargetField(String targetField) {
|
|
||||||
this.targetFields.add(targetField);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.launcher;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.StreamTokenizer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.jdom.Document;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author mwood
|
|
||||||
*/
|
|
||||||
public class CommandRunner {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private CommandRunner() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param args the command line arguments given
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
*/
|
|
||||||
public static void main(String[] args)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
if (args.length > 0) {
|
|
||||||
runManyCommands(args[0]);
|
|
||||||
} else {
|
|
||||||
runManyCommands("-");
|
|
||||||
}
|
|
||||||
// There is no sensible way to use the status returned by runManyCommands().
|
|
||||||
// If called from the command line then we would want to return it
|
|
||||||
// through System.exit(). But if called (normally) from ScriptLauncher,
|
|
||||||
// there is no way to return it and we don't want to interrupt
|
|
||||||
// ScriptLauncher.
|
|
||||||
//
|
|
||||||
// "'tis a puzzlement." -- the King of Siam
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read a file of command lines and execute each in turn.
|
|
||||||
*
|
|
||||||
* @param script the file of command lines to be executed.
|
|
||||||
* @return status code
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
*/
|
|
||||||
static int runManyCommands(String script)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
Reader input;
|
|
||||||
if ("-".equals(script)) {
|
|
||||||
input = new InputStreamReader(System.in);
|
|
||||||
} else {
|
|
||||||
input = new FileReader(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
StreamTokenizer tokenizer = new StreamTokenizer(input);
|
|
||||||
|
|
||||||
tokenizer.eolIsSignificant(true);
|
|
||||||
|
|
||||||
tokenizer.ordinaryChar('-');
|
|
||||||
tokenizer.wordChars('-', '-');
|
|
||||||
|
|
||||||
tokenizer.ordinaryChars('0', '9');
|
|
||||||
tokenizer.wordChars('0', '9');
|
|
||||||
|
|
||||||
tokenizer.ordinaryChar('.');
|
|
||||||
tokenizer.wordChars('.', '.');
|
|
||||||
|
|
||||||
tokenizer.ordinaryChar('@');
|
|
||||||
tokenizer.wordChars('@', '@');
|
|
||||||
|
|
||||||
int status = 0;
|
|
||||||
List<String> tokens = new ArrayList<String>();
|
|
||||||
Document commandConfigs = ScriptLauncher.getConfig();
|
|
||||||
while (StreamTokenizer.TT_EOF != tokenizer.nextToken()) {
|
|
||||||
if (StreamTokenizer.TT_EOL == tokenizer.ttype) {
|
|
||||||
if (tokens.size() > 0) {
|
|
||||||
status = ScriptLauncher.runOneCommand(commandConfigs, tokens.toArray(new String[tokens.size()]));
|
|
||||||
if (status > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tokens.clear();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tokens.add(tokenizer.sval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,281 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.launcher;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import org.dspace.servicemanager.DSpaceKernelImpl;
|
|
||||||
import org.dspace.servicemanager.DSpaceKernelInit;
|
|
||||||
import org.dspace.services.RequestService;
|
|
||||||
import org.jdom.Document;
|
|
||||||
import org.jdom.Element;
|
|
||||||
import org.jdom.input.SAXBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A DSpace script launcher.
|
|
||||||
*
|
|
||||||
* @author Stuart Lewis
|
|
||||||
* @author Mark Diggory
|
|
||||||
*/
|
|
||||||
public class ScriptLauncher {
|
|
||||||
/**
|
|
||||||
* The service manager kernel
|
|
||||||
*/
|
|
||||||
private static transient DSpaceKernelImpl kernelImpl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private ScriptLauncher() { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the DSpace script launcher
|
|
||||||
*
|
|
||||||
* @param args Any parameters required to be passed to the scripts it executes
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
*/
|
|
||||||
public static void main(String[] args)
|
|
||||||
throws FileNotFoundException, IOException {
|
|
||||||
// Initialise the service manager kernel
|
|
||||||
try {
|
|
||||||
kernelImpl = DSpaceKernelInit.getKernel(null);
|
|
||||||
if (!kernelImpl.isRunning()) {
|
|
||||||
kernelImpl.start();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Failed to start so destroy it and log and throw an exception
|
|
||||||
try {
|
|
||||||
kernelImpl.destroy();
|
|
||||||
} catch (Exception e1) {
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
String message = "Failure during kernel init: " + e.getMessage();
|
|
||||||
System.err.println(message);
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new IllegalStateException(message, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load up the ScriptLauncher's configuration
|
|
||||||
Document commandConfigs = getConfig();
|
|
||||||
|
|
||||||
// Check that there is at least one argument (if not display command options)
|
|
||||||
if (args.length < 1) {
|
|
||||||
System.err.println("You must provide at least one command argument");
|
|
||||||
display(commandConfigs);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look up command in the configuration, and execute.
|
|
||||||
int status;
|
|
||||||
status = runOneCommand(commandConfigs, args);
|
|
||||||
|
|
||||||
// Destroy the service kernel if it is still alive
|
|
||||||
if (kernelImpl != null) {
|
|
||||||
kernelImpl.destroy();
|
|
||||||
kernelImpl = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
System.exit(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static int runOneCommand(Document commandConfigs, String[] args) {
|
|
||||||
return runOneCommand(commandConfigs, args, kernelImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recognize and execute a single command.
|
|
||||||
*
|
|
||||||
* @param commandConfigs Document
|
|
||||||
* @param args the command line arguments given
|
|
||||||
*/
|
|
||||||
public static int runOneCommand(Document commandConfigs, String[] args, DSpaceKernelImpl kernelImpl) {
|
|
||||||
String request = args[0];
|
|
||||||
Element root = commandConfigs.getRootElement();
|
|
||||||
List<Element> commands = root.getChildren("command");
|
|
||||||
Element command = null;
|
|
||||||
for (Element candidate : commands) {
|
|
||||||
if (request.equalsIgnoreCase(candidate.getChild("name").getValue())) {
|
|
||||||
command = candidate;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == command) {
|
|
||||||
// The command wasn't found
|
|
||||||
System.err.println("Command not found: " + args[0]);
|
|
||||||
display(commandConfigs);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run each step
|
|
||||||
List<Element> steps = command.getChildren("step");
|
|
||||||
for (Element step : steps) {
|
|
||||||
// Instantiate the class
|
|
||||||
Class target = null;
|
|
||||||
|
|
||||||
// Is it the special case 'dsrun' where the user provides the class name?
|
|
||||||
String className;
|
|
||||||
if ("dsrun".equals(request)) {
|
|
||||||
if (args.length < 2) {
|
|
||||||
System.err.println("Error in launcher.xml: Missing class name");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
className = args[1];
|
|
||||||
} else {
|
|
||||||
className = step.getChild("class").getValue();
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
target = Class.forName(className,
|
|
||||||
true,
|
|
||||||
Thread.currentThread().getContextClassLoader());
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
System.err.println("Error in launcher.xml: Invalid class name: " + className);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip the leading argument from the args, and add the arguments
|
|
||||||
// Set <passargs>false</passargs> if the arguments should not be passed on
|
|
||||||
String[] useargs = args.clone();
|
|
||||||
Class[] argTypes = {useargs.getClass()};
|
|
||||||
boolean passargs = true;
|
|
||||||
if ((step.getAttribute("passuserargs") != null) &&
|
|
||||||
("false".equalsIgnoreCase(step.getAttribute("passuserargs").getValue()))) {
|
|
||||||
passargs = false;
|
|
||||||
}
|
|
||||||
if ((args.length == 1) || (("dsrun".equals(request)) && (args.length == 2)) || (!passargs)) {
|
|
||||||
useargs = new String[0];
|
|
||||||
} else {
|
|
||||||
// The number of arguments to ignore
|
|
||||||
// If dsrun is the command, ignore the next, as it is the class name not an arg
|
|
||||||
int x = 1;
|
|
||||||
if ("dsrun".equals(request)) {
|
|
||||||
x = 2;
|
|
||||||
}
|
|
||||||
String[] argsnew = new String[useargs.length - x];
|
|
||||||
for (int i = x; i < useargs.length; i++) {
|
|
||||||
argsnew[i - x] = useargs[i];
|
|
||||||
}
|
|
||||||
useargs = argsnew;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add any extra properties
|
|
||||||
List<Element> bits = step.getChildren("argument");
|
|
||||||
if (step.getChild("argument") != null) {
|
|
||||||
String[] argsnew = new String[useargs.length + bits.size()];
|
|
||||||
int i = 0;
|
|
||||||
for (Element arg : bits) {
|
|
||||||
argsnew[i++] = arg.getValue();
|
|
||||||
}
|
|
||||||
for (; i < bits.size() + useargs.length; i++) {
|
|
||||||
argsnew[i] = useargs[i - bits.size()];
|
|
||||||
}
|
|
||||||
useargs = argsnew;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish the request service startup
|
|
||||||
RequestService requestService = kernelImpl.getServiceManager().getServiceByName(
|
|
||||||
RequestService.class.getName(), RequestService.class);
|
|
||||||
if (requestService == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Could not get the DSpace RequestService to start the request transaction");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Establish a request related to the current session
|
|
||||||
// that will trigger the various request listeners
|
|
||||||
requestService.startRequest();
|
|
||||||
|
|
||||||
// Run the main() method
|
|
||||||
try {
|
|
||||||
Object[] arguments = {useargs};
|
|
||||||
|
|
||||||
// Useful for debugging, so left in the code...
|
|
||||||
/**System.out.print("About to execute: " + className);
|
|
||||||
for (String param : useargs)
|
|
||||||
{
|
|
||||||
System.out.print(" " + param);
|
|
||||||
}
|
|
||||||
System.out.println("");**/
|
|
||||||
|
|
||||||
Method main = target.getMethod("main", argTypes);
|
|
||||||
main.invoke(null, arguments);
|
|
||||||
|
|
||||||
// ensure we close out the request (happy request)
|
|
||||||
requestService.endRequest(null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Failure occurred in the request so we destroy it
|
|
||||||
requestService.endRequest(e);
|
|
||||||
|
|
||||||
// Exceptions from the script are reported as a 'cause'
|
|
||||||
Throwable cause = e.getCause();
|
|
||||||
System.err.println("Exception: " + cause.getMessage());
|
|
||||||
cause.printStackTrace();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything completed OK
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the launcher configuration file
|
|
||||||
*
|
|
||||||
* @return The XML configuration file Document
|
|
||||||
*/
|
|
||||||
protected static Document getConfig() {
|
|
||||||
return getConfig(kernelImpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Document getConfig(DSpaceKernelImpl kernelImpl) {
|
|
||||||
// Load the launcher configuration file
|
|
||||||
String config = kernelImpl.getConfigurationService().getProperty("dspace.dir") +
|
|
||||||
System.getProperty("file.separator") + "config" +
|
|
||||||
System.getProperty("file.separator") + "launcher.xml";
|
|
||||||
SAXBuilder saxBuilder = new SAXBuilder();
|
|
||||||
Document doc = null;
|
|
||||||
try {
|
|
||||||
doc = saxBuilder.build(config);
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.err.println("Unable to load the launcher configuration file: [dspace]/config/launcher.xml");
|
|
||||||
System.err.println(e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
return doc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display the commands that the current launcher config file knows about
|
|
||||||
*
|
|
||||||
* @param commandConfigs configs as Document
|
|
||||||
*/
|
|
||||||
private static void display(Document commandConfigs) {
|
|
||||||
// List all command elements
|
|
||||||
List<Element> commands = commandConfigs.getRootElement().getChildren("command");
|
|
||||||
|
|
||||||
// Sort the commands by name.
|
|
||||||
// We cannot just use commands.sort() because it tries to remove and
|
|
||||||
// reinsert Elements within other Elements, and that doesn't work.
|
|
||||||
TreeMap<String, Element> sortedCommands = new TreeMap<>();
|
|
||||||
for (Element command : commands) {
|
|
||||||
sortedCommands.put(command.getChild("name").getValue(), command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display the sorted list
|
|
||||||
System.out.println("Usage: dspace [command-name] {parameters}");
|
|
||||||
for (Element command : sortedCommands.values()) {
|
|
||||||
System.out.println(" - " + command.getChild("name").getValue() +
|
|
||||||
": " + command.getChild("description").getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.FontMetrics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class to attach a footer to an image using ImageMagick.
|
|
||||||
* Thanks Ninh Nguyen from the National Library of Australia for providing the source code.
|
|
||||||
* This version of the code is basically Ninh's but reorganised a little. Used with permission.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class Brand {
|
|
||||||
private int brandWidth;
|
|
||||||
private int brandHeight;
|
|
||||||
private Font font;
|
|
||||||
private int xOffset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor to set up footer image attributes.
|
|
||||||
*
|
|
||||||
* @param brandWidth length of the footer in pixels
|
|
||||||
* @param brandHeight height of the footer in pixels
|
|
||||||
* @param font font to use for text on the footer
|
|
||||||
* @param xOffset number of pixels text should be indented from left-hand side of footer
|
|
||||||
*/
|
|
||||||
public Brand(int brandWidth,
|
|
||||||
int brandHeight,
|
|
||||||
Font font,
|
|
||||||
int xOffset) {
|
|
||||||
this.brandWidth = brandWidth;
|
|
||||||
this.brandHeight = brandHeight;
|
|
||||||
this.font = font;
|
|
||||||
this.xOffset = xOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the brand image
|
|
||||||
*
|
|
||||||
* @param brandLeftText text that should appear in the bottom left of the image
|
|
||||||
* @param shortLeftText abbreviated form of brandLeftText that will be substituted if
|
|
||||||
* the image is resized such that brandLeftText will not fit. <code>null</code> if not
|
|
||||||
* required
|
|
||||||
* @param brandRightText text that should appear in the bottom right of the image
|
|
||||||
* @return BufferedImage a BufferedImage object describing the brand image file
|
|
||||||
*/
|
|
||||||
public BufferedImage create(String brandLeftText,
|
|
||||||
String shortLeftText,
|
|
||||||
String brandRightText) {
|
|
||||||
BrandText[] allBrandText = null;
|
|
||||||
|
|
||||||
BufferedImage brandImage =
|
|
||||||
new BufferedImage(brandWidth, brandHeight, BufferedImage.TYPE_INT_RGB);
|
|
||||||
|
|
||||||
if (brandWidth >= 350) {
|
|
||||||
allBrandText = new BrandText[] {
|
|
||||||
new BrandText(BrandText.BL, brandLeftText),
|
|
||||||
new BrandText(BrandText.BR, brandRightText)
|
|
||||||
};
|
|
||||||
} else if (brandWidth >= 190) {
|
|
||||||
allBrandText = new BrandText[] {
|
|
||||||
new BrandText(BrandText.BL, shortLeftText),
|
|
||||||
new BrandText(BrandText.BR, brandRightText)
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
allBrandText = new BrandText[] {
|
|
||||||
new BrandText(BrandText.BR, brandRightText)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allBrandText != null && allBrandText.length > 0) {
|
|
||||||
for (int i = 0; i < allBrandText.length; ++i) {
|
|
||||||
drawImage(brandImage, allBrandText[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return brandImage;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* do the text placements and preparatory work for the brand image generation
|
|
||||||
*
|
|
||||||
* @param brandImage a BufferedImage object where the image is created
|
|
||||||
* @param identifier and Identifier object describing what text is to be placed in what
|
|
||||||
* position within the brand
|
|
||||||
*/
|
|
||||||
private void drawImage(BufferedImage brandImage,
|
|
||||||
BrandText brandText) {
|
|
||||||
int imgWidth = brandImage.getWidth();
|
|
||||||
int imgHeight = brandImage.getHeight();
|
|
||||||
|
|
||||||
Graphics2D g2 = brandImage.createGraphics();
|
|
||||||
g2.setFont(font);
|
|
||||||
FontMetrics fm = g2.getFontMetrics();
|
|
||||||
|
|
||||||
int bWidth = fm.stringWidth(brandText.getText()) + xOffset * 2 + 1;
|
|
||||||
int bHeight = fm.getHeight();
|
|
||||||
|
|
||||||
int bx = 0;
|
|
||||||
int by = 0;
|
|
||||||
|
|
||||||
if (brandText.getLocation().equals(BrandText.TL)) {
|
|
||||||
bx = 0;
|
|
||||||
by = 0;
|
|
||||||
} else if (brandText.getLocation().equals(BrandText.TR)) {
|
|
||||||
bx = imgWidth - bWidth;
|
|
||||||
by = 0;
|
|
||||||
} else if (brandText.getLocation().equals(BrandText.BL)) {
|
|
||||||
bx = 0;
|
|
||||||
by = imgHeight - bHeight;
|
|
||||||
} else if (brandText.getLocation().equals(BrandText.BR)) {
|
|
||||||
bx = imgWidth - bWidth;
|
|
||||||
by = imgHeight - bHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle box = new Rectangle(bx, by, bWidth, bHeight);
|
|
||||||
int tx = bx + xOffset;
|
|
||||||
int ty = by + fm.getAscent();
|
|
||||||
|
|
||||||
g2.setColor(Color.black);
|
|
||||||
g2.fill(box);
|
|
||||||
g2.setColor(Color.white);
|
|
||||||
g2.drawString(brandText.getText(), tx, ty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifier class, holding a single item of text and its location
|
|
||||||
* within a rectangular areas. Allowable locations are any of the four corners.
|
|
||||||
* This is a copy of Picture Australia's PiObj class re-organised with methods.
|
|
||||||
* Thanks to Ninh Nguyen at the National Library for providing the original source.
|
|
||||||
*/
|
|
||||||
class BrandText {
|
|
||||||
/**
|
|
||||||
* Bottom Left
|
|
||||||
*/
|
|
||||||
public static final String BL = "bl";
|
|
||||||
/**
|
|
||||||
* Bottom Right
|
|
||||||
*/
|
|
||||||
public static final String BR = "br";
|
|
||||||
/**
|
|
||||||
* Top Left
|
|
||||||
*/
|
|
||||||
public static final String TL = "tl";
|
|
||||||
/**
|
|
||||||
* Top Right
|
|
||||||
*/
|
|
||||||
public static final String TR = "tr";
|
|
||||||
|
|
||||||
private String location;
|
|
||||||
private String text;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for an Identifier object containing a text string and
|
|
||||||
* its location within a rectangular area.
|
|
||||||
*
|
|
||||||
* @param location one of the class location constants e.g. <code>Identifier.BL</code>
|
|
||||||
* @param the text associated with the location
|
|
||||||
*/
|
|
||||||
public BrandText(String location, String text) {
|
|
||||||
this.location = location;
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the location the text of the Identifier object is associated with
|
|
||||||
*
|
|
||||||
* @return String one the class location constants e.g. <code>Identifier.BL</code>
|
|
||||||
*/
|
|
||||||
public String getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get the text associated with the Identifier object
|
|
||||||
*
|
|
||||||
* @return String the text associated with the Identifier object
|
|
||||||
*/
|
|
||||||
public String getText() {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set the location associated with the Identifier object
|
|
||||||
*
|
|
||||||
* @param location one of the class location constants
|
|
||||||
*/
|
|
||||||
public void setLocation(String location) {
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set the text associated with the Identifier object
|
|
||||||
*
|
|
||||||
* @param text any text string (typically a branding or identifier)
|
|
||||||
*/
|
|
||||||
public void setText(String text) {
|
|
||||||
this.text = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter image bitstreams, scaling the image to be within the bounds of
|
|
||||||
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
|
|
||||||
* no bigger than. Creates only JPEGs.
|
|
||||||
*
|
|
||||||
* @author Jason Sherman jsherman@usao.edu
|
|
||||||
*/
|
|
||||||
public class BrandedPreviewJPEGFilter extends MediaFilter {
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".preview.jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "BRANDED_PREVIEW";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "JPEG";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Generated Branded Preview";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
// read in bitstream's image
|
|
||||||
BufferedImage buf = ImageIO.read(source);
|
|
||||||
|
|
||||||
// get config params
|
|
||||||
float xmax = (float) ConfigurationManager
|
|
||||||
.getIntProperty("webui.preview.maxwidth");
|
|
||||||
float ymax = (float) ConfigurationManager
|
|
||||||
.getIntProperty("webui.preview.maxheight");
|
|
||||||
boolean blurring = (boolean) ConfigurationManager
|
|
||||||
.getBooleanProperty("webui.preview.blurring");
|
|
||||||
boolean hqscaling = (boolean) ConfigurationManager
|
|
||||||
.getBooleanProperty("webui.preview.hqscaling");
|
|
||||||
int brandHeight = ConfigurationManager.getIntProperty("webui.preview.brand.height");
|
|
||||||
String brandFont = ConfigurationManager.getProperty("webui.preview.brand.font");
|
|
||||||
int brandFontPoint = ConfigurationManager.getIntProperty("webui.preview.brand.fontpoint");
|
|
||||||
|
|
||||||
JPEGFilter jpegFilter = new JPEGFilter();
|
|
||||||
return jpegFilter
|
|
||||||
.getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, brandHeight, brandFontPoint,
|
|
||||||
brandFont);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.poi.POITextExtractor;
|
|
||||||
import org.apache.poi.extractor.ExtractorFactory;
|
|
||||||
import org.apache.poi.hssf.extractor.ExcelExtractor;
|
|
||||||
import org.apache.poi.xssf.extractor.XSSFExcelExtractor;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ExcelFilter
|
|
||||||
*
|
|
||||||
* Entries you must add to dspace.cfg:
|
|
||||||
*
|
|
||||||
* filter.plugins = blah, \
|
|
||||||
* Excel Text Extractor
|
|
||||||
*
|
|
||||||
* plugin.named.org.dspace.app.mediafilter.FormatFilter = \
|
|
||||||
* blah = blah, \
|
|
||||||
* org.dspace.app.mediafilter.ExcelFilter = Excel Text Extractor
|
|
||||||
*
|
|
||||||
* #Configure each filter's input Formats
|
|
||||||
* filter.org.dspace.app.mediafilter.ExcelFilter.inputFormats = Microsoft Excel, Microsoft Excel XML
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class ExcelFilter extends MediaFilter {
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(ExcelFilter.class);
|
|
||||||
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstream format
|
|
||||||
*/
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param item item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item item, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
String extractedText = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
POITextExtractor theExtractor = ExtractorFactory.createExtractor(source);
|
|
||||||
if (theExtractor instanceof ExcelExtractor) {
|
|
||||||
// for xls file
|
|
||||||
extractedText = (theExtractor).getText();
|
|
||||||
} else if (theExtractor instanceof XSSFExcelExtractor) {
|
|
||||||
// for xlsx file
|
|
||||||
extractedText = (theExtractor).getText();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error filtering bitstream: " + e.getMessage(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extractedText != null) {
|
|
||||||
// generate an input stream with the extracted text
|
|
||||||
return IOUtils.toInputStream(extractedText, StandardCharsets.UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public interface for any class which transforms or converts content/bitstreams
|
|
||||||
* from one format to another. This interface should be implemented by any class
|
|
||||||
* which defines a "filter" to be run by the MediaFilterManager.
|
|
||||||
*/
|
|
||||||
public interface FormatFilter {
|
|
||||||
/**
|
|
||||||
* Get a filename for a newly created filtered bitstream
|
|
||||||
*
|
|
||||||
* @param sourceName name of source bitstream
|
|
||||||
* @return filename generated by the filter - for example, document.pdf
|
|
||||||
* becomes document.pdf.txt
|
|
||||||
*/
|
|
||||||
public String getFilteredName(String sourceName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return name of the bundle this filter will stick its generated
|
|
||||||
* Bitstreams
|
|
||||||
*/
|
|
||||||
public String getBundleName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return name of the bitstream format (say "HTML" or "Microsoft Word")
|
|
||||||
* returned by this filter look in the bitstream format registry or
|
|
||||||
* mediafilter.cfg for valid format strings.
|
|
||||||
*/
|
|
||||||
public String getFormatString();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string to describe the newly-generated Bitstream - how it was
|
|
||||||
* produced is a good idea
|
|
||||||
*/
|
|
||||||
public String getDescription();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the source stream and produce the filtered content.
|
|
||||||
*
|
|
||||||
* @param item Item
|
|
||||||
* @param source input stream
|
|
||||||
* @param verbose verbosity flag
|
|
||||||
* @return result of filter's transformation as a byte stream.
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public InputStream getDestinationStream(Item item, InputStream source, boolean verbose)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any pre-processing of the source bitstream *before* the actual
|
|
||||||
* filtering takes place in MediaFilterManager.processBitstream().
|
|
||||||
* <p>
|
|
||||||
* Return true if pre-processing is successful (or no pre-processing
|
|
||||||
* is necessary). Return false if bitstream should be skipped
|
|
||||||
* for any reason.
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param item item containing bitstream to process
|
|
||||||
* @param source source bitstream to be processed
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return true if bitstream processing should continue,
|
|
||||||
* false if this bitstream should be skipped
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public boolean preProcessBitstream(Context c, Item item, Bitstream source, boolean verbose)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any post-processing of the generated bitstream *after* this
|
|
||||||
* filter has already been run.
|
|
||||||
* <p>
|
|
||||||
* Return true if pre-processing is successful (or no pre-processing
|
|
||||||
* is necessary). Return false if bitstream should be skipped
|
|
||||||
* for some reason.
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param item item containing bitstream to process
|
|
||||||
* @param generatedBitstream the bitstream which was generated by
|
|
||||||
* this filter.
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public void postProcessBitstream(Context c, Item item, Bitstream generatedBitstream)
|
|
||||||
throws Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import javax.swing.text.Document;
|
|
||||||
import javax.swing.text.html.HTMLEditorKit;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* to do: helpful error messages - can't find mediafilter.cfg - can't
|
|
||||||
* instantiate filter - bitstream format doesn't exist
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class HTMLFilter extends MediaFilter {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
// try and read the document - set to ignore character set directive,
|
|
||||||
// assuming that the input stream is already set properly (I hope)
|
|
||||||
HTMLEditorKit kit = new HTMLEditorKit();
|
|
||||||
Document doc = kit.createDefaultDocument();
|
|
||||||
|
|
||||||
doc.putProperty("IgnoreCharsetDirective", Boolean.TRUE);
|
|
||||||
|
|
||||||
kit.read(source, doc, 0);
|
|
||||||
|
|
||||||
String extractedText = doc.getText(0, doc.getLength());
|
|
||||||
|
|
||||||
// generate an input stream with the extracted text
|
|
||||||
byte[] textBytes = extractedText.getBytes();
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(textBytes);
|
|
||||||
|
|
||||||
return bais; // will this work? or will the byte array be out of scope?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter image bitstreams, scaling the image to be within the bounds of
|
|
||||||
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
|
|
||||||
* no bigger than. Creates only JPEGs.
|
|
||||||
*/
|
|
||||||
public class ImageMagickImageThumbnailFilter extends ImageMagickThumbnailFilter {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
File f = inputStreamToTempFile(source, "imthumb", ".tmp");
|
|
||||||
File f2 = null;
|
|
||||||
try {
|
|
||||||
f2 = getThumbnailFile(f, verbose);
|
|
||||||
byte[] bytes = Files.readAllBytes(f2.toPath());
|
|
||||||
return new ByteArrayInputStream(bytes);
|
|
||||||
} finally {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
f.delete();
|
|
||||||
if (f2 != null) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
f2.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
public class ImageMagickPdfThumbnailFilter extends ImageMagickThumbnailFilter {
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
File f = inputStreamToTempFile(source, "impdfthumb", ".pdf");
|
|
||||||
File f2 = null;
|
|
||||||
File f3 = null;
|
|
||||||
try {
|
|
||||||
f2 = getImageFile(f, 0, verbose);
|
|
||||||
f3 = getThumbnailFile(f2, verbose);
|
|
||||||
byte[] bytes = Files.readAllBytes(f3.toPath());
|
|
||||||
return new ByteArrayInputStream(bytes);
|
|
||||||
} finally {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
f.delete();
|
|
||||||
if (f2 != null) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
f2.delete();
|
|
||||||
}
|
|
||||||
if (f3 != null) {
|
|
||||||
//noinspection ResultOfMethodCallIgnored
|
|
||||||
f3.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.regex.PatternSyntaxException;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.factory.ContentServiceFactory;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.im4java.core.ConvertCmd;
|
|
||||||
import org.im4java.core.IM4JavaException;
|
|
||||||
import org.im4java.core.IMOperation;
|
|
||||||
import org.im4java.core.Info;
|
|
||||||
import org.im4java.process.ProcessStarter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter image bitstreams, scaling the image to be within the bounds of
|
|
||||||
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
|
|
||||||
* no bigger than. Creates only JPEGs.
|
|
||||||
*/
|
|
||||||
public abstract class ImageMagickThumbnailFilter extends MediaFilter {
|
|
||||||
protected static int width = 180;
|
|
||||||
protected static int height = 120;
|
|
||||||
private static boolean flatten = true;
|
|
||||||
static String bitstreamDescription = "IM Thumbnail";
|
|
||||||
static final String defaultPattern = "Generated Thumbnail";
|
|
||||||
static Pattern replaceRegex = Pattern.compile(defaultPattern);
|
|
||||||
protected final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
|
|
||||||
|
|
||||||
static String cmyk_profile;
|
|
||||||
static String srgb_profile;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String pre = ImageMagickThumbnailFilter.class.getName();
|
|
||||||
String s = ConfigurationManager.getProperty(pre + ".ProcessStarter");
|
|
||||||
ProcessStarter.setGlobalSearchPath(s);
|
|
||||||
width = ConfigurationManager.getIntProperty("thumbnail.maxwidth", width);
|
|
||||||
height = ConfigurationManager.getIntProperty("thumbnail.maxheight", height);
|
|
||||||
flatten = ConfigurationManager.getBooleanProperty(pre + ".flatten", flatten);
|
|
||||||
String description = ConfigurationManager.getProperty(pre + ".bitstreamDescription");
|
|
||||||
cmyk_profile = ConfigurationManager.getProperty(pre + ".cmyk_profile");
|
|
||||||
srgb_profile = ConfigurationManager.getProperty(pre + ".srgb_profile");
|
|
||||||
if (description != null) {
|
|
||||||
bitstreamDescription = description;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String patt = ConfigurationManager.getProperty(pre + ".replaceRegex");
|
|
||||||
replaceRegex = Pattern.compile(patt == null ? defaultPattern : patt);
|
|
||||||
} catch (PatternSyntaxException e) {
|
|
||||||
System.err.println("Invalid thumbnail replacement pattern: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageMagickThumbnailFilter() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "THUMBNAIL";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "JPEG";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamDescription
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return bitstreamDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File inputStreamToTempFile(InputStream source, String prefix, String suffix) throws IOException {
|
|
||||||
File f = File.createTempFile(prefix, suffix);
|
|
||||||
f.deleteOnExit();
|
|
||||||
FileOutputStream fos = new FileOutputStream(f);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int len = source.read(buffer);
|
|
||||||
while (len != -1) {
|
|
||||||
fos.write(buffer, 0, len);
|
|
||||||
len = source.read(buffer);
|
|
||||||
}
|
|
||||||
fos.close();
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getThumbnailFile(File f, boolean verbose)
|
|
||||||
throws IOException, InterruptedException, IM4JavaException {
|
|
||||||
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
|
|
||||||
f2.deleteOnExit();
|
|
||||||
ConvertCmd cmd = new ConvertCmd();
|
|
||||||
IMOperation op = new IMOperation();
|
|
||||||
op.autoOrient();
|
|
||||||
op.addImage(f.getAbsolutePath());
|
|
||||||
op.thumbnail(width, height);
|
|
||||||
op.addImage(f2.getAbsolutePath());
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("IM Thumbnail Param: " + op);
|
|
||||||
}
|
|
||||||
cmd.run(op);
|
|
||||||
return f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getImageFile(File f, int page, boolean verbose)
|
|
||||||
throws IOException, InterruptedException, IM4JavaException {
|
|
||||||
File f2 = new File(f.getParentFile(), f.getName() + ".jpg");
|
|
||||||
f2.deleteOnExit();
|
|
||||||
ConvertCmd cmd = new ConvertCmd();
|
|
||||||
IMOperation op = new IMOperation();
|
|
||||||
String s = "[" + page + "]";
|
|
||||||
op.addImage(f.getAbsolutePath() + s);
|
|
||||||
if (flatten) {
|
|
||||||
op.flatten();
|
|
||||||
}
|
|
||||||
// PDFs using the CMYK color system can be handled specially if
|
|
||||||
// profiles are defined
|
|
||||||
if (cmyk_profile != null && srgb_profile != null) {
|
|
||||||
Info imageInfo = new Info(f.getAbsolutePath(), true);
|
|
||||||
String imageClass = imageInfo.getImageClass();
|
|
||||||
if (imageClass.contains("CMYK")) {
|
|
||||||
op.profile(cmyk_profile);
|
|
||||||
op.profile(srgb_profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
op.addImage(f2.getAbsolutePath());
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("IM Image Param: " + op);
|
|
||||||
}
|
|
||||||
cmd.run(op);
|
|
||||||
return f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean preProcessBitstream(Context c, Item item, Bitstream source, boolean verbose) throws Exception {
|
|
||||||
String nsrc = source.getName();
|
|
||||||
for (Bundle b : itemService.getBundles(item, "THUMBNAIL")) {
|
|
||||||
for (Bitstream bit : b.getBitstreams()) {
|
|
||||||
String n = bit.getName();
|
|
||||||
if (n != null) {
|
|
||||||
if (nsrc != null) {
|
|
||||||
if (!n.startsWith(nsrc)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String description = bit.getDescription();
|
|
||||||
// If anything other than a generated thumbnail
|
|
||||||
// is found, halt processing
|
|
||||||
if (description != null) {
|
|
||||||
if (replaceRegex.matcher(description).matches()) {
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(description + " " + nsrc
|
|
||||||
+ " matches pattern and is replacable.");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (description.equals(bitstreamDescription)) {
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(bitstreamDescription + " " + nsrc
|
|
||||||
+ " is replacable.");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println("Custom Thumbnail exists for " + nsrc + " for item "
|
|
||||||
+ item.getHandle() + ". Thumbnail will not be generated. ");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // assume that the thumbnail is a custom one
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,315 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.RenderingHints;
|
|
||||||
import java.awt.Transparency;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.BufferedImageOp;
|
|
||||||
import java.awt.image.ConvolveOp;
|
|
||||||
import java.awt.image.Kernel;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter image bitstreams, scaling the image to be within the bounds of
|
|
||||||
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
|
|
||||||
* no bigger than. Creates only JPEGs.
|
|
||||||
*
|
|
||||||
* @author Jason Sherman jsherman@usao.edu
|
|
||||||
*/
|
|
||||||
public class JPEGFilter extends MediaFilter implements SelfRegisterInputFormats {
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "THUMBNAIL";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "JPEG";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Generated Thumbnail";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
// read in bitstream's image
|
|
||||||
BufferedImage buf = ImageIO.read(source);
|
|
||||||
|
|
||||||
return getThumb(currentItem, buf, verbose);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getThumb(Item currentItem, BufferedImage buf, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
// get config params
|
|
||||||
float xmax = (float) ConfigurationManager
|
|
||||||
.getIntProperty("thumbnail.maxwidth");
|
|
||||||
float ymax = (float) ConfigurationManager
|
|
||||||
.getIntProperty("thumbnail.maxheight");
|
|
||||||
boolean blurring = (boolean) ConfigurationManager
|
|
||||||
.getBooleanProperty("thumbnail.blurring");
|
|
||||||
boolean hqscaling = (boolean) ConfigurationManager
|
|
||||||
.getBooleanProperty("thumbnail.hqscaling");
|
|
||||||
|
|
||||||
return getThumbDim(currentItem, buf, verbose, xmax, ymax, blurring, hqscaling, 0, 0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getThumbDim(Item currentItem, BufferedImage buf, boolean verbose, float xmax, float ymax,
|
|
||||||
boolean blurring, boolean hqscaling, int brandHeight, int brandFontPoint,
|
|
||||||
String brandFont)
|
|
||||||
throws Exception {
|
|
||||||
// now get the image dimensions
|
|
||||||
float xsize = (float) buf.getWidth(null);
|
|
||||||
float ysize = (float) buf.getHeight(null);
|
|
||||||
|
|
||||||
// if verbose flag is set, print out dimensions
|
|
||||||
// to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("original size: " + xsize + "," + ysize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale by x first if needed
|
|
||||||
if (xsize > xmax) {
|
|
||||||
// calculate scaling factor so that xsize * scale = new size (max)
|
|
||||||
float scale_factor = xmax / xsize;
|
|
||||||
|
|
||||||
// if verbose flag is set, print out extracted text
|
|
||||||
// to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("x scale factor: " + scale_factor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now reduce x size
|
|
||||||
// and y size
|
|
||||||
xsize = xsize * scale_factor;
|
|
||||||
ysize = ysize * scale_factor;
|
|
||||||
|
|
||||||
// if verbose flag is set, print out extracted text
|
|
||||||
// to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("size after fitting to maximum width: " + xsize + "," + ysize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale by y if needed
|
|
||||||
if (ysize > ymax) {
|
|
||||||
float scale_factor = ymax / ysize;
|
|
||||||
|
|
||||||
// now reduce x size
|
|
||||||
// and y size
|
|
||||||
xsize = xsize * scale_factor;
|
|
||||||
ysize = ysize * scale_factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if verbose flag is set, print details to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println("size after fitting to maximum height: " + xsize + ", "
|
|
||||||
+ ysize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an image buffer for the thumbnail with the new xsize, ysize
|
|
||||||
BufferedImage thumbnail = new BufferedImage((int) xsize, (int) ysize,
|
|
||||||
BufferedImage.TYPE_INT_RGB);
|
|
||||||
|
|
||||||
// Use blurring if selected in config.
|
|
||||||
// a little blur before scaling does wonders for keeping moire in check.
|
|
||||||
if (blurring) {
|
|
||||||
// send the buffered image off to get blurred.
|
|
||||||
buf = getBlurredInstance((BufferedImage) buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use high quality scaling method if selected in config.
|
|
||||||
// this has a definite performance penalty.
|
|
||||||
if (hqscaling) {
|
|
||||||
// send the buffered image off to get an HQ downscale.
|
|
||||||
buf = getScaledInstance((BufferedImage) buf, (int) xsize, (int) ysize,
|
|
||||||
(Object) RenderingHints.VALUE_INTERPOLATION_BICUBIC, (boolean) true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now render the image into the thumbnail buffer
|
|
||||||
Graphics2D g2d = thumbnail.createGraphics();
|
|
||||||
g2d.drawImage(buf, 0, 0, (int) xsize, (int) ysize, null);
|
|
||||||
|
|
||||||
if (brandHeight != 0) {
|
|
||||||
Brand brand = new Brand((int) xsize, brandHeight, new Font(brandFont, Font.PLAIN, brandFontPoint), 5);
|
|
||||||
BufferedImage brandImage = brand.create(ConfigurationManager.getProperty("webui.preview.brand"),
|
|
||||||
ConfigurationManager.getProperty("webui.preview.brand.abbrev"),
|
|
||||||
currentItem == null ? "" : "hdl:" + currentItem.getHandle());
|
|
||||||
|
|
||||||
g2d.drawImage(brandImage, (int) 0, (int) ysize, (int) xsize, (int) 20, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now create an input stream for the thumbnail buffer and return it
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
ImageIO.write(thumbnail, "jpeg", baos);
|
|
||||||
|
|
||||||
// now get the array
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
|
||||||
|
|
||||||
return bais; // hope this gets written out before its garbage collected!
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputMIMETypes() {
|
|
||||||
return ImageIO.getReaderMIMETypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputDescriptions() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputExtensions() {
|
|
||||||
// Temporarily disabled as JDK 1.6 only
|
|
||||||
// return ImageIO.getReaderFileSuffixes();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BufferedImage getNormalizedInstance(BufferedImage buf) {
|
|
||||||
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
|
|
||||||
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB_PRE;
|
|
||||||
int w = buf.getWidth();
|
|
||||||
int h = buf.getHeight();
|
|
||||||
BufferedImage normal = new BufferedImage(w, h, type);
|
|
||||||
Graphics2D g2d = normal.createGraphics();
|
|
||||||
g2d.drawImage(buf, 0, 0, w, h, Color.WHITE, null);
|
|
||||||
g2d.dispose();
|
|
||||||
return normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method that returns a blurred instance of the
|
|
||||||
* provided {@code BufferedImage}.
|
|
||||||
*
|
|
||||||
* @param buf buffered image
|
|
||||||
* @return updated BufferedImage
|
|
||||||
*/
|
|
||||||
public BufferedImage getBlurredInstance(BufferedImage buf) {
|
|
||||||
buf = getNormalizedInstance(buf);
|
|
||||||
|
|
||||||
// kernel for blur op
|
|
||||||
float[] matrix = {
|
|
||||||
0.111f, 0.111f, 0.111f,
|
|
||||||
0.111f, 0.111f, 0.111f,
|
|
||||||
0.111f, 0.111f, 0.111f,
|
|
||||||
};
|
|
||||||
|
|
||||||
// perform the blur and return the blurred version.
|
|
||||||
BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, matrix));
|
|
||||||
BufferedImage blurbuf = blur.filter(buf, null);
|
|
||||||
return blurbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience method that returns a scaled instance of the
|
|
||||||
* provided {@code BufferedImage}.
|
|
||||||
*
|
|
||||||
* @param buf the original image to be scaled
|
|
||||||
* @param targetWidth the desired width of the scaled instance,
|
|
||||||
* in pixels
|
|
||||||
* @param targetHeight the desired height of the scaled instance,
|
|
||||||
* in pixels
|
|
||||||
* @param hint one of the rendering hints that corresponds to
|
|
||||||
* {@code RenderingHints.KEY_INTERPOLATION} (e.g.
|
|
||||||
* {@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
|
|
||||||
* {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
|
|
||||||
* {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
|
|
||||||
* @param higherQuality if true, this method will use a multi-step
|
|
||||||
* scaling technique that provides higher quality than the usual
|
|
||||||
* one-step technique (only useful in downscaling cases, where
|
|
||||||
* {@code targetWidth} or {@code targetHeight} is
|
|
||||||
* smaller than the original dimensions, and generally only when
|
|
||||||
* the {@code BILINEAR} hint is specified)
|
|
||||||
* @return a scaled version of the original {@code BufferedImage}
|
|
||||||
*/
|
|
||||||
public BufferedImage getScaledInstance(BufferedImage buf,
|
|
||||||
int targetWidth,
|
|
||||||
int targetHeight,
|
|
||||||
Object hint,
|
|
||||||
boolean higherQuality) {
|
|
||||||
int type = (buf.getTransparency() == Transparency.OPAQUE) ?
|
|
||||||
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
|
|
||||||
BufferedImage scalebuf = (BufferedImage) buf;
|
|
||||||
int w;
|
|
||||||
int h;
|
|
||||||
if (higherQuality) {
|
|
||||||
// Use multi-step technique: start with original size, then
|
|
||||||
// scale down in multiple passes with drawImage()
|
|
||||||
// until the target size is reached
|
|
||||||
w = buf.getWidth();
|
|
||||||
h = buf.getHeight();
|
|
||||||
} else {
|
|
||||||
// Use one-step technique: scale directly from original
|
|
||||||
// size to target size with a single drawImage() call
|
|
||||||
w = targetWidth;
|
|
||||||
h = targetHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (higherQuality && w > targetWidth) {
|
|
||||||
w /= 2;
|
|
||||||
if (w < targetWidth) {
|
|
||||||
w = targetWidth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (higherQuality && h > targetHeight) {
|
|
||||||
h /= 2;
|
|
||||||
if (h < targetHeight) {
|
|
||||||
h = targetHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferedImage tmp = new BufferedImage(w, h, type);
|
|
||||||
Graphics2D g2d = tmp.createGraphics();
|
|
||||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
|
|
||||||
g2d.drawImage(scalebuf, 0, 0, w, h, Color.WHITE, null);
|
|
||||||
g2d.dispose();
|
|
||||||
|
|
||||||
scalebuf = tmp;
|
|
||||||
} while (w != targetWidth || h != targetHeight);
|
|
||||||
|
|
||||||
return scalebuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class which defines the default settings for a *simple* Media or Format Filter.
|
|
||||||
* This class may be extended by any class which wishes to define a simple filter to be run
|
|
||||||
* by the MediaFilterManager. More complex filters should likely implement the FormatFilter
|
|
||||||
* interface directly, so that they can define their own pre/postProcessing methods.
|
|
||||||
*/
|
|
||||||
public abstract class MediaFilter implements FormatFilter {
|
|
||||||
/**
|
|
||||||
* Perform any pre-processing of the source bitstream *before* the actual
|
|
||||||
* filtering takes place in MediaFilterManager.processBitstream().
|
|
||||||
* <p>
|
|
||||||
* Return true if pre-processing is successful (or no pre-processing
|
|
||||||
* is necessary). Return false if bitstream should be skipped
|
|
||||||
* for any reason.
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param item item containing bitstream to process
|
|
||||||
* @param source source bitstream to be processed
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return true if bitstream processing should continue,
|
|
||||||
* false if this bitstream should be skipped
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean preProcessBitstream(Context c, Item item, Bitstream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
return true; //default to no pre-processing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any post-processing of the generated bitstream *after* this
|
|
||||||
* filter has already been run.
|
|
||||||
* <p>
|
|
||||||
* Return true if pre-processing is successful (or no pre-processing
|
|
||||||
* is necessary). Return false if bitstream should be skipped
|
|
||||||
* for some reason.
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param item item containing bitstream to process
|
|
||||||
* @param generatedBitstream the bitstream which was generated by
|
|
||||||
* this filter.
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void postProcessBitstream(Context c, Item item, Bitstream generatedBitstream)
|
|
||||||
throws Exception {
|
|
||||||
//default to no post-processing necessary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,325 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.MissingArgumentException;
|
|
||||||
import org.apache.commons.cli.Option;
|
|
||||||
import org.apache.commons.cli.OptionBuilder;
|
|
||||||
import org.apache.commons.cli.Options;
|
|
||||||
import org.apache.commons.cli.PosixParser;
|
|
||||||
import org.apache.commons.lang.ArrayUtils;
|
|
||||||
import org.dspace.app.mediafilter.factory.MediaFilterServiceFactory;
|
|
||||||
import org.dspace.app.mediafilter.service.MediaFilterService;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.SelfNamedPlugin;
|
|
||||||
import org.dspace.core.factory.CoreServiceFactory;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MediaFilterManager is the class that invokes the media/format filters over the
|
|
||||||
* repository's content. A few command line flags affect the operation of the
|
|
||||||
* MFM: -v verbose outputs all extracted text to STDOUT; -f force forces all
|
|
||||||
* bitstreams to be processed, even if they have been before; -n noindex does not
|
|
||||||
* recreate index after processing bitstreams; -i [identifier] limits processing
|
|
||||||
* scope to a community, collection or item; and -m [max] limits processing to a
|
|
||||||
* maximum number of items.
|
|
||||||
*/
|
|
||||||
public class MediaFilterCLITool {
|
|
||||||
|
|
||||||
//key (in dspace.cfg) which lists all enabled filters by name
|
|
||||||
private static final String MEDIA_FILTER_PLUGINS_KEY = "filter.plugins";
|
|
||||||
|
|
||||||
//prefix (in dspace.cfg) for all filter properties
|
|
||||||
private static final String FILTER_PREFIX = "filter";
|
|
||||||
|
|
||||||
//suffix (in dspace.cfg) for input formats supported by each filter
|
|
||||||
private static final String INPUT_FORMATS_SUFFIX = "inputFormats";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
*/
|
|
||||||
private MediaFilterCLITool() { }
|
|
||||||
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
// set headless for non-gui workstations
|
|
||||||
System.setProperty("java.awt.headless", "true");
|
|
||||||
|
|
||||||
// create an options object and populate it
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
Options options = new Options();
|
|
||||||
|
|
||||||
options.addOption("v", "verbose", false,
|
|
||||||
"print all extracted text and other details to STDOUT");
|
|
||||||
options.addOption("q", "quiet", false,
|
|
||||||
"do not print anything except in the event of errors.");
|
|
||||||
options.addOption("f", "force", false,
|
|
||||||
"force all bitstreams to be processed");
|
|
||||||
options.addOption("i", "identifier", true,
|
|
||||||
"ONLY process bitstreams belonging to identifier");
|
|
||||||
options.addOption("m", "maximum", true,
|
|
||||||
"process no more than maximum items");
|
|
||||||
options.addOption("h", "help", false, "help");
|
|
||||||
|
|
||||||
//create a "plugin" option (to specify specific MediaFilter plugins to run)
|
|
||||||
OptionBuilder.withLongOpt("plugins");
|
|
||||||
OptionBuilder.withValueSeparator(',');
|
|
||||||
OptionBuilder.withDescription(
|
|
||||||
"ONLY run the specified Media Filter plugin(s)\n" +
|
|
||||||
"listed from '" + MEDIA_FILTER_PLUGINS_KEY + "' in dspace.cfg.\n" +
|
|
||||||
"Separate multiple with a comma (,)\n" +
|
|
||||||
"(e.g. MediaFilterManager -p \n\"Word Text Extractor\",\"PDF Text Extractor\")");
|
|
||||||
Option pluginOption = OptionBuilder.create('p');
|
|
||||||
pluginOption.setArgs(Option.UNLIMITED_VALUES); //unlimited number of args
|
|
||||||
options.addOption(pluginOption);
|
|
||||||
|
|
||||||
//create a "skip" option (to specify communities/collections/items to skip)
|
|
||||||
OptionBuilder.withLongOpt("skip");
|
|
||||||
OptionBuilder.withValueSeparator(',');
|
|
||||||
OptionBuilder.withDescription(
|
|
||||||
"SKIP the bitstreams belonging to identifier\n" +
|
|
||||||
"Separate multiple identifiers with a comma (,)\n" +
|
|
||||||
"(e.g. MediaFilterManager -s \n 123456789/34,123456789/323)");
|
|
||||||
Option skipOption = OptionBuilder.create('s');
|
|
||||||
skipOption.setArgs(Option.UNLIMITED_VALUES); //unlimited number of args
|
|
||||||
options.addOption(skipOption);
|
|
||||||
|
|
||||||
boolean isVerbose = false;
|
|
||||||
boolean isQuiet = false;
|
|
||||||
boolean isForce = false; // default to not forced
|
|
||||||
String identifier = null; // object scope limiter
|
|
||||||
int max2Process = Integer.MAX_VALUE;
|
|
||||||
Map<String, List<String>> filterFormats = new HashMap<>();
|
|
||||||
|
|
||||||
CommandLine line = null;
|
|
||||||
try {
|
|
||||||
line = parser.parse(options, argv);
|
|
||||||
} catch (MissingArgumentException e) {
|
|
||||||
System.out.println("ERROR: " + e.getMessage());
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("MediaFilterManager\n", options);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("MediaFilterManager\n", options);
|
|
||||||
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('v')) {
|
|
||||||
isVerbose = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
isQuiet = line.hasOption('q');
|
|
||||||
|
|
||||||
if (line.hasOption('f')) {
|
|
||||||
isForce = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('i')) {
|
|
||||||
identifier = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line.hasOption('m')) {
|
|
||||||
max2Process = Integer.parseInt(line.getOptionValue('m'));
|
|
||||||
if (max2Process <= 1) {
|
|
||||||
System.out.println("Invalid maximum value '" +
|
|
||||||
line.getOptionValue('m') + "' - ignoring");
|
|
||||||
max2Process = Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String filterNames[] = null;
|
|
||||||
if (line.hasOption('p')) {
|
|
||||||
//specified which media filter plugins we are using
|
|
||||||
filterNames = line.getOptionValues('p');
|
|
||||||
|
|
||||||
if (filterNames == null || filterNames.length == 0) { //display error, since no plugins specified
|
|
||||||
System.err.println("\nERROR: -p (-plugin) option requires at least one plugin to be specified.\n" +
|
|
||||||
"(e.g. MediaFilterManager -p \"Word Text Extractor\",\"PDF Text Extractor\")\n");
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("MediaFilterManager\n", options);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//retrieve list of all enabled media filter plugins!
|
|
||||||
filterNames = DSpaceServicesFactory.getInstance().getConfigurationService()
|
|
||||||
.getArrayProperty(MEDIA_FILTER_PLUGINS_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
MediaFilterService mediaFilterService = MediaFilterServiceFactory.getInstance().getMediaFilterService();
|
|
||||||
mediaFilterService.setForce(isForce);
|
|
||||||
mediaFilterService.setQuiet(isQuiet);
|
|
||||||
mediaFilterService.setVerbose(isVerbose);
|
|
||||||
mediaFilterService.setMax2Process(max2Process);
|
|
||||||
|
|
||||||
//initialize an array of our enabled filters
|
|
||||||
List<FormatFilter> filterList = new ArrayList<FormatFilter>();
|
|
||||||
|
|
||||||
//set up each filter
|
|
||||||
for (int i = 0; i < filterNames.length; i++) {
|
|
||||||
//get filter of this name & add to list of filters
|
|
||||||
FormatFilter filter = (FormatFilter) CoreServiceFactory.getInstance().getPluginService()
|
|
||||||
.getNamedPlugin(FormatFilter.class, filterNames[i]);
|
|
||||||
if (filter == null) {
|
|
||||||
System.err.println(
|
|
||||||
"\nERROR: Unknown MediaFilter specified (either from command-line or in dspace.cfg): '" +
|
|
||||||
filterNames[i] + "'");
|
|
||||||
System.exit(1);
|
|
||||||
} else {
|
|
||||||
filterList.add(filter);
|
|
||||||
|
|
||||||
String filterClassName = filter.getClass().getName();
|
|
||||||
|
|
||||||
String pluginName = null;
|
|
||||||
|
|
||||||
//If this filter is a SelfNamedPlugin,
|
|
||||||
//then the input formats it accepts may differ for
|
|
||||||
//each "named" plugin that it defines.
|
|
||||||
//So, we have to look for every key that fits the
|
|
||||||
//following format: filter.<class-name>.<plugin-name>.inputFormats
|
|
||||||
if (SelfNamedPlugin.class.isAssignableFrom(filter.getClass())) {
|
|
||||||
//Get the plugin instance name for this class
|
|
||||||
pluginName = ((SelfNamedPlugin) filter).getPluginInstanceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Retrieve our list of supported formats from dspace.cfg
|
|
||||||
//For SelfNamedPlugins, format of key is:
|
|
||||||
// filter.<class-name>.<plugin-name>.inputFormats
|
|
||||||
//For other MediaFilters, format of key is:
|
|
||||||
// filter.<class-name>.inputFormats
|
|
||||||
String[] formats =
|
|
||||||
DSpaceServicesFactory.getInstance().getConfigurationService().getArrayProperty(
|
|
||||||
FILTER_PREFIX + "." + filterClassName +
|
|
||||||
(pluginName != null ? "." + pluginName : "") +
|
|
||||||
"." + INPUT_FORMATS_SUFFIX);
|
|
||||||
|
|
||||||
//add to internal map of filters to supported formats
|
|
||||||
if (ArrayUtils.isNotEmpty(formats)) {
|
|
||||||
//For SelfNamedPlugins, map key is:
|
|
||||||
// <class-name><separator><plugin-name>
|
|
||||||
//For other MediaFilters, map key is just:
|
|
||||||
// <class-name>
|
|
||||||
filterFormats.put(filterClassName +
|
|
||||||
(pluginName != null ? MediaFilterService.FILTER_PLUGIN_SEPARATOR +
|
|
||||||
pluginName : ""),
|
|
||||||
Arrays.asList(formats));
|
|
||||||
}
|
|
||||||
} //end if filter!=null
|
|
||||||
} //end for
|
|
||||||
|
|
||||||
//If verbose, print out loaded mediafilter info
|
|
||||||
if (isVerbose) {
|
|
||||||
System.out.println("The following MediaFilters are enabled: ");
|
|
||||||
Iterator<String> i = filterFormats.keySet().iterator();
|
|
||||||
while (i.hasNext()) {
|
|
||||||
String filterName = i.next();
|
|
||||||
System.out.println("Full Filter Name: " + filterName);
|
|
||||||
String pluginName = null;
|
|
||||||
if (filterName.contains(MediaFilterService.FILTER_PLUGIN_SEPARATOR)) {
|
|
||||||
String[] fields = filterName.split(MediaFilterService.FILTER_PLUGIN_SEPARATOR);
|
|
||||||
filterName = fields[0];
|
|
||||||
pluginName = fields[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println(filterName +
|
|
||||||
(pluginName != null ? " (Plugin: " + pluginName + ")" : ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaFilterService.setFilterFormats(filterFormats);
|
|
||||||
//store our filter list into an internal array
|
|
||||||
mediaFilterService.setFilterClasses(filterList);
|
|
||||||
|
|
||||||
|
|
||||||
//Retrieve list of identifiers to skip (if any)
|
|
||||||
String skipIds[] = null;
|
|
||||||
if (line.hasOption('s')) {
|
|
||||||
//specified which identifiers to skip when processing
|
|
||||||
skipIds = line.getOptionValues('s');
|
|
||||||
|
|
||||||
if (skipIds == null || skipIds.length == 0) { //display error, since no identifiers specified to skip
|
|
||||||
System.err.println("\nERROR: -s (-skip) option requires at least one identifier to SKIP.\n" +
|
|
||||||
"Make sure to separate multiple identifiers with a comma!\n" +
|
|
||||||
"(e.g. MediaFilterManager -s 123456789/34,123456789/323)\n");
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("MediaFilterManager\n", options);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//save to a global skip list
|
|
||||||
mediaFilterService.setSkipList(Arrays.asList(skipIds));
|
|
||||||
}
|
|
||||||
|
|
||||||
Context c = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
c = new Context();
|
|
||||||
|
|
||||||
// have to be super-user to do the filtering
|
|
||||||
c.turnOffAuthorisationSystem();
|
|
||||||
|
|
||||||
// now apply the filters
|
|
||||||
if (identifier == null) {
|
|
||||||
mediaFilterService.applyFiltersAllItems(c);
|
|
||||||
} else {
|
|
||||||
// restrict application scope to identifier
|
|
||||||
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, identifier);
|
|
||||||
if (dso == null) {
|
|
||||||
throw new IllegalArgumentException("Cannot resolve "
|
|
||||||
+ identifier + " to a DSpace object");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (dso.getType()) {
|
|
||||||
case Constants.COMMUNITY:
|
|
||||||
mediaFilterService.applyFiltersCommunity(c, (Community) dso);
|
|
||||||
break;
|
|
||||||
case Constants.COLLECTION:
|
|
||||||
mediaFilterService.applyFiltersCollection(c, (Collection) dso);
|
|
||||||
break;
|
|
||||||
case Constants.ITEM:
|
|
||||||
mediaFilterService.applyFiltersItem(c, (Item) dso);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.complete();
|
|
||||||
c = null;
|
|
||||||
} catch (Exception e) {
|
|
||||||
status = 1;
|
|
||||||
} finally {
|
|
||||||
if (c != null) {
|
|
||||||
c.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.exit(status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,469 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.dspace.app.mediafilter.service.MediaFilterService;
|
|
||||||
import org.dspace.authorize.service.AuthorizeService;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.BitstreamFormat;
|
|
||||||
import org.dspace.content.Bundle;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.DCDate;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.content.service.BitstreamFormatService;
|
|
||||||
import org.dspace.content.service.BitstreamService;
|
|
||||||
import org.dspace.content.service.BundleService;
|
|
||||||
import org.dspace.content.service.CollectionService;
|
|
||||||
import org.dspace.content.service.CommunityService;
|
|
||||||
import org.dspace.content.service.ItemService;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.SelfNamedPlugin;
|
|
||||||
import org.dspace.eperson.Group;
|
|
||||||
import org.dspace.eperson.service.GroupService;
|
|
||||||
import org.dspace.services.ConfigurationService;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MediaFilterManager is the class that invokes the media/format filters over the
|
|
||||||
* repository's content. A few command line flags affect the operation of the
|
|
||||||
* MFM: -v verbose outputs all extracted text to STDOUT; -f force forces all
|
|
||||||
* bitstreams to be processed, even if they have been before; -n noindex does not
|
|
||||||
* recreate index after processing bitstreams; -i [identifier] limits processing
|
|
||||||
* scope to a community, collection or item; and -m [max] limits processing to a
|
|
||||||
* maximum number of items.
|
|
||||||
*/
|
|
||||||
public class MediaFilterServiceImpl implements MediaFilterService, InitializingBean {
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected AuthorizeService authorizeService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected BitstreamFormatService bitstreamFormatService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected BitstreamService bitstreamService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected BundleService bundleService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected CollectionService collectionService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected CommunityService communityService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected GroupService groupService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected ItemService itemService;
|
|
||||||
@Autowired(required = true)
|
|
||||||
protected ConfigurationService configurationService;
|
|
||||||
|
|
||||||
protected int max2Process = Integer.MAX_VALUE; // maximum number items to process
|
|
||||||
|
|
||||||
protected int processed = 0; // number items processed
|
|
||||||
|
|
||||||
protected Item currentItem = null; // current item being processed
|
|
||||||
|
|
||||||
protected List<FormatFilter> filterClasses = null;
|
|
||||||
|
|
||||||
protected Map<String, List<String>> filterFormats = new HashMap<>();
|
|
||||||
|
|
||||||
protected List<String> skipList = null; //list of identifiers to skip during processing
|
|
||||||
|
|
||||||
protected final List<String> publicFiltersClasses = new ArrayList<>();
|
|
||||||
|
|
||||||
protected boolean isVerbose = false;
|
|
||||||
protected boolean isQuiet = false;
|
|
||||||
protected boolean isForce = false; // default to not forced
|
|
||||||
|
|
||||||
protected MediaFilterServiceImpl() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
String[] publicPermissionFilters = configurationService
|
|
||||||
.getArrayProperty("filter.org.dspace.app.mediafilter.publicPermission");
|
|
||||||
|
|
||||||
if (publicPermissionFilters != null) {
|
|
||||||
for (String filter : publicPermissionFilters) {
|
|
||||||
publicFiltersClasses.add(filter.trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyFiltersAllItems(Context context) throws Exception {
|
|
||||||
if (skipList != null) {
|
|
||||||
//if a skip-list exists, we need to filter community-by-community
|
|
||||||
//so we can respect what is in the skip-list
|
|
||||||
List<Community> topLevelCommunities = communityService.findAllTop(context);
|
|
||||||
|
|
||||||
for (Community topLevelCommunity : topLevelCommunities) {
|
|
||||||
applyFiltersCommunity(context, topLevelCommunity);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//otherwise, just find every item and process
|
|
||||||
Iterator<Item> itemIterator = itemService.findAll(context);
|
|
||||||
while (itemIterator.hasNext() && processed < max2Process) {
|
|
||||||
applyFiltersItem(context, itemIterator.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyFiltersCommunity(Context context, Community community)
|
|
||||||
throws Exception { //only apply filters if community not in skip-list
|
|
||||||
if (!inSkipList(community.getHandle())) {
|
|
||||||
List<Community> subcommunities = community.getSubcommunities();
|
|
||||||
for (Community subcommunity : subcommunities) {
|
|
||||||
applyFiltersCommunity(context, subcommunity);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Collection> collections = community.getCollections();
|
|
||||||
for (Collection collection : collections) {
|
|
||||||
applyFiltersCollection(context, collection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyFiltersCollection(Context context, Collection collection)
|
|
||||||
throws Exception {
|
|
||||||
//only apply filters if collection not in skip-list
|
|
||||||
if (!inSkipList(collection.getHandle())) {
|
|
||||||
Iterator<Item> itemIterator = itemService.findAllByCollection(context, collection);
|
|
||||||
while (itemIterator.hasNext() && processed < max2Process) {
|
|
||||||
applyFiltersItem(context, itemIterator.next());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyFiltersItem(Context c, Item item) throws Exception {
|
|
||||||
//only apply filters if item not in skip-list
|
|
||||||
if (!inSkipList(item.getHandle())) {
|
|
||||||
//cache this item in MediaFilterManager
|
|
||||||
//so it can be accessed by MediaFilters as necessary
|
|
||||||
currentItem = item;
|
|
||||||
|
|
||||||
if (filterItem(c, item)) {
|
|
||||||
// increment processed count
|
|
||||||
++processed;
|
|
||||||
}
|
|
||||||
// clear item objects from context cache and internal cache
|
|
||||||
c.uncacheEntity(currentItem);
|
|
||||||
currentItem = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean filterItem(Context context, Item myItem) throws Exception {
|
|
||||||
// get 'original' bundles
|
|
||||||
List<Bundle> myBundles = itemService.getBundles(myItem, "ORIGINAL");
|
|
||||||
boolean done = false;
|
|
||||||
for (Bundle myBundle : myBundles) {
|
|
||||||
// now look at all of the bitstreams
|
|
||||||
List<Bitstream> myBitstreams = myBundle.getBitstreams();
|
|
||||||
|
|
||||||
for (Bitstream myBitstream : myBitstreams) {
|
|
||||||
done |= filterBitstream(context, myItem, myBitstream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return done;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean filterBitstream(Context context, Item myItem,
|
|
||||||
Bitstream myBitstream) throws Exception {
|
|
||||||
boolean filtered = false;
|
|
||||||
|
|
||||||
// iterate through filter classes. A single format may be actioned
|
|
||||||
// by more than one filter
|
|
||||||
for (FormatFilter filterClass : filterClasses) {
|
|
||||||
//List fmts = (List)filterFormats.get(filterClasses[i].getClass().getName());
|
|
||||||
String pluginName = null;
|
|
||||||
|
|
||||||
//if this filter class is a SelfNamedPlugin,
|
|
||||||
//its list of supported formats is different for
|
|
||||||
//differently named "plugin"
|
|
||||||
if (SelfNamedPlugin.class.isAssignableFrom(filterClass.getClass())) {
|
|
||||||
//get plugin instance name for this media filter
|
|
||||||
pluginName = ((SelfNamedPlugin) filterClass).getPluginInstanceName();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get list of supported formats for the filter (and possibly named plugin)
|
|
||||||
//For SelfNamedPlugins, map key is:
|
|
||||||
// <class-name><separator><plugin-name>
|
|
||||||
//For other MediaFilters, map key is just:
|
|
||||||
// <class-name>
|
|
||||||
List<String> fmts = filterFormats.get(filterClass.getClass().getName() +
|
|
||||||
(pluginName != null ? FILTER_PLUGIN_SEPARATOR + pluginName : ""));
|
|
||||||
|
|
||||||
if (fmts.contains(myBitstream.getFormat(context).getShortDescription())) {
|
|
||||||
try {
|
|
||||||
// only update item if bitstream not skipped
|
|
||||||
if (processBitstream(context, myItem, myBitstream, filterClass)) {
|
|
||||||
itemService.update(context, myItem); // Make sure new bitstream has a sequence
|
|
||||||
// number
|
|
||||||
filtered = true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
String handle = myItem.getHandle();
|
|
||||||
List<Bundle> bundles = myBitstream.getBundles();
|
|
||||||
long size = myBitstream.getSize();
|
|
||||||
String checksum = myBitstream.getChecksum() + " (" + myBitstream.getChecksumAlgorithm() + ")";
|
|
||||||
int assetstore = myBitstream.getStoreNumber();
|
|
||||||
|
|
||||||
// Printout helpful information to find the errored bitstream.
|
|
||||||
System.out.println("ERROR filtering, skipping bitstream:\n");
|
|
||||||
System.out.println("\tItem Handle: " + handle);
|
|
||||||
for (Bundle bundle : bundles) {
|
|
||||||
System.out.println("\tBundle Name: " + bundle.getName());
|
|
||||||
}
|
|
||||||
System.out.println("\tFile Size: " + size);
|
|
||||||
System.out.println("\tChecksum: " + checksum);
|
|
||||||
System.out.println("\tAsset Store: " + assetstore);
|
|
||||||
System.out.println(e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else if (filterClass instanceof SelfRegisterInputFormats) {
|
|
||||||
// Filter implements self registration, so check to see if it should be applied
|
|
||||||
// given the formats it claims to support
|
|
||||||
SelfRegisterInputFormats srif = (SelfRegisterInputFormats) filterClass;
|
|
||||||
boolean applyFilter = false;
|
|
||||||
|
|
||||||
// Check MIME type
|
|
||||||
String[] mimeTypes = srif.getInputMIMETypes();
|
|
||||||
if (mimeTypes != null) {
|
|
||||||
for (String mimeType : mimeTypes) {
|
|
||||||
if (mimeType.equalsIgnoreCase(myBitstream.getFormat(context).getMIMEType())) {
|
|
||||||
applyFilter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check description
|
|
||||||
if (!applyFilter) {
|
|
||||||
String[] descriptions = srif.getInputDescriptions();
|
|
||||||
if (descriptions != null) {
|
|
||||||
for (String desc : descriptions) {
|
|
||||||
if (desc.equalsIgnoreCase(myBitstream.getFormat(context).getShortDescription())) {
|
|
||||||
applyFilter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check extensions
|
|
||||||
if (!applyFilter) {
|
|
||||||
String[] extensions = srif.getInputExtensions();
|
|
||||||
if (extensions != null) {
|
|
||||||
for (String ext : extensions) {
|
|
||||||
List<String> formatExtensions = myBitstream.getFormat(context).getExtensions();
|
|
||||||
if (formatExtensions != null && formatExtensions.contains(ext)) {
|
|
||||||
applyFilter = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter claims to handle this type of file, so attempt to apply it
|
|
||||||
if (applyFilter) {
|
|
||||||
try {
|
|
||||||
// only update item if bitstream not skipped
|
|
||||||
if (processBitstream(context, myItem, myBitstream, filterClass)) {
|
|
||||||
itemService.update(context, myItem); // Make sure new bitstream has a sequence
|
|
||||||
// number
|
|
||||||
filtered = true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("ERROR filtering, skipping bitstream #"
|
|
||||||
+ myBitstream.getID() + " " + e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filtered;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean processBitstream(Context context, Item item, Bitstream source, FormatFilter formatFilter)
|
|
||||||
throws Exception {
|
|
||||||
//do pre-processing of this bitstream, and if it fails, skip this bitstream!
|
|
||||||
if (!formatFilter.preProcessBitstream(context, item, source, isVerbose)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean overWrite = isForce;
|
|
||||||
|
|
||||||
// get bitstream filename, calculate destination filename
|
|
||||||
String newName = formatFilter.getFilteredName(source.getName());
|
|
||||||
|
|
||||||
Bitstream existingBitstream = null; // is there an existing rendition?
|
|
||||||
Bundle targetBundle = null; // bundle we're modifying
|
|
||||||
|
|
||||||
List<Bundle> bundles = itemService.getBundles(item, formatFilter.getBundleName());
|
|
||||||
|
|
||||||
// check if destination bitstream exists
|
|
||||||
if (bundles.size() > 0) {
|
|
||||||
// only finds the last match (FIXME?)
|
|
||||||
for (Bundle bundle : bundles) {
|
|
||||||
List<Bitstream> bitstreams = bundle.getBitstreams();
|
|
||||||
|
|
||||||
for (Bitstream bitstream : bitstreams) {
|
|
||||||
if (bitstream.getName().trim().equals(newName.trim())) {
|
|
||||||
targetBundle = bundle;
|
|
||||||
existingBitstream = bitstream;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if exists and overwrite = false, exit
|
|
||||||
if (!overWrite && (existingBitstream != null)) {
|
|
||||||
if (!isQuiet) {
|
|
||||||
System.out.println("SKIPPED: bitstream " + source.getID()
|
|
||||||
+ " (item: " + item.getHandle() + ") because '" + newName + "' already exists");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVerbose) {
|
|
||||||
System.out.println("PROCESSING: bitstream " + source.getID()
|
|
||||||
+ " (item: " + item.getHandle() + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream destStream;
|
|
||||||
try {
|
|
||||||
System.out.println("File: " + newName);
|
|
||||||
destStream = formatFilter.getDestinationStream(item, bitstreamService.retrieve(context, source), isVerbose);
|
|
||||||
if (destStream == null) {
|
|
||||||
if (!isQuiet) {
|
|
||||||
System.out.println("SKIPPED: bitstream " + source.getID()
|
|
||||||
+ " (item: " + item.getHandle() + ") because filtering was unsuccessful");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (OutOfMemoryError oome) {
|
|
||||||
System.out.println("!!! OutOfMemoryError !!!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create new bundle if needed
|
|
||||||
if (bundles.size() < 1) {
|
|
||||||
targetBundle = bundleService.create(context, item, formatFilter.getBundleName());
|
|
||||||
} else {
|
|
||||||
// take the first match
|
|
||||||
targetBundle = bundles.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Bitstream b = bitstreamService.create(context, targetBundle, destStream);
|
|
||||||
|
|
||||||
// Now set the format and name of the bitstream
|
|
||||||
b.setName(context, newName);
|
|
||||||
b.setSource(context, "Written by FormatFilter " + formatFilter.getClass().getName() +
|
|
||||||
" on " + DCDate.getCurrent() + " (GMT).");
|
|
||||||
b.setDescription(context, formatFilter.getDescription());
|
|
||||||
|
|
||||||
// Find the proper format
|
|
||||||
BitstreamFormat bf = bitstreamFormatService.findByShortDescription(context,
|
|
||||||
formatFilter.getFormatString());
|
|
||||||
bitstreamService.setFormat(context, b, bf);
|
|
||||||
bitstreamService.update(context, b);
|
|
||||||
|
|
||||||
//Set permissions on the derivative bitstream
|
|
||||||
//- First remove any existing policies
|
|
||||||
authorizeService.removeAllPolicies(context, b);
|
|
||||||
|
|
||||||
//- Determine if this is a public-derivative format
|
|
||||||
if (publicFiltersClasses.contains(formatFilter.getClass().getSimpleName())) {
|
|
||||||
//- Set derivative bitstream to be publicly accessible
|
|
||||||
Group anonymous = groupService.findByName(context, Group.ANONYMOUS);
|
|
||||||
authorizeService.addPolicy(context, b, Constants.READ, anonymous);
|
|
||||||
} else {
|
|
||||||
//- Inherit policies from the source bitstream
|
|
||||||
authorizeService.inheritPolicies(context, source, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixme - set date?
|
|
||||||
// we are overwriting, so remove old bitstream
|
|
||||||
if (existingBitstream != null) {
|
|
||||||
bundleService.removeBitstream(context, targetBundle, existingBitstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isQuiet) {
|
|
||||||
System.out.println("FILTERED: bitstream " + source.getID()
|
|
||||||
+ " (item: " + item.getHandle() + ") and created '" + newName + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
//do post-processing of the generated bitstream
|
|
||||||
formatFilter.postProcessBitstream(context, item, b);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Item getCurrentItem() {
|
|
||||||
return currentItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean inSkipList(String identifier) {
|
|
||||||
if (skipList != null && skipList.contains(identifier)) {
|
|
||||||
if (!isQuiet) {
|
|
||||||
System.out.println("SKIP-LIST: skipped bitstreams within identifier " + identifier);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVerbose(boolean isVerbose) {
|
|
||||||
this.isVerbose = isVerbose;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setQuiet(boolean isQuiet) {
|
|
||||||
this.isQuiet = isQuiet;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setForce(boolean isForce) {
|
|
||||||
this.isForce = isForce;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMax2Process(int max2Process) {
|
|
||||||
this.max2Process = max2Process;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFilterClasses(List<FormatFilter> filterClasses) {
|
|
||||||
this.filterClasses = filterClasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setSkipList(List<String> skipList) {
|
|
||||||
this.skipList = skipList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFilterFormats(Map<String, List<String>> filterFormats) {
|
|
||||||
this.filterFormats = filterFormats;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create JPEG thumbnails from PDF cover page using PDFBox.
|
|
||||||
* Based on JPEGFilter:
|
|
||||||
* Filter image bitstreams, scaling the image to be within the bounds of
|
|
||||||
* thumbnail.maxwidth, thumbnail.maxheight, the size we want our thumbnail to be
|
|
||||||
* no bigger than. Creates only JPEGs.
|
|
||||||
*
|
|
||||||
* @author Ivan Masár helix84@centrum.sk
|
|
||||||
* @author Jason Sherman jsherman@usao.edu
|
|
||||||
*/
|
|
||||||
public class PDFBoxThumbnail extends MediaFilter implements SelfRegisterInputFormats {
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".jpg";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "THUMBNAIL";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "JPEG";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Generated Thumbnail";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
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();
|
|
||||||
|
|
||||||
JPEGFilter jpegFilter = new JPEGFilter();
|
|
||||||
return jpegFilter.getThumb(currentItem, buf, verbose);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputMIMETypes() {
|
|
||||||
return ImageIO.getReaderMIMETypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputDescriptions() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getInputExtensions() {
|
|
||||||
// Temporarily disabled as JDK 1.6 only
|
|
||||||
// return ImageIO.getReaderFileSuffixes();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
|
||||||
import org.apache.pdfbox.text.PDFTextStripper;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.ConfigurationManager;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* to do: helpful error messages - can't find mediafilter.cfg - can't
|
|
||||||
* instantiate filter - bitstream format doesn't exist
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PDFFilter extends MediaFilter {
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(PDFFilter.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
try {
|
|
||||||
boolean useTemporaryFile = ConfigurationManager.getBooleanProperty("pdffilter.largepdfs", false);
|
|
||||||
|
|
||||||
// get input stream from bitstream
|
|
||||||
// pass to filter, get string back
|
|
||||||
PDFTextStripper pts = new PDFTextStripper();
|
|
||||||
pts.setSortByPosition(true);
|
|
||||||
PDDocument pdfDoc = null;
|
|
||||||
Writer writer = null;
|
|
||||||
File tempTextFile = null;
|
|
||||||
ByteArrayOutputStream byteStream = null;
|
|
||||||
|
|
||||||
if (useTemporaryFile) {
|
|
||||||
tempTextFile = File.createTempFile("dspacepdfextract" + source.hashCode(), ".txt");
|
|
||||||
tempTextFile.deleteOnExit();
|
|
||||||
writer = new OutputStreamWriter(new FileOutputStream(tempTextFile));
|
|
||||||
} else {
|
|
||||||
byteStream = new ByteArrayOutputStream();
|
|
||||||
writer = new OutputStreamWriter(byteStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
pdfDoc = PDDocument.load(source);
|
|
||||||
pts.writeText(pdfDoc, writer);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pdfDoc != null) {
|
|
||||||
pdfDoc.close();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error closing PDF file: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
writer.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error closing temporary extract file: " + e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useTemporaryFile) {
|
|
||||||
return new FileInputStream(tempTextFile);
|
|
||||||
} else {
|
|
||||||
byte[] bytes = byteStream.toByteArray();
|
|
||||||
return new ByteArrayInputStream(bytes);
|
|
||||||
}
|
|
||||||
} catch (OutOfMemoryError oome) {
|
|
||||||
log.error("Error parsing PDF document " + oome.getMessage(), oome);
|
|
||||||
if (!ConfigurationManager.getBooleanProperty("pdffilter.skiponmemoryexception", false)) {
|
|
||||||
throw oome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.apache.poi.POITextExtractor;
|
|
||||||
import org.apache.poi.extractor.ExtractorFactory;
|
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
|
||||||
import org.apache.xmlbeans.XmlException;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract flat text from Microsoft Word documents (.doc, .docx).
|
|
||||||
*/
|
|
||||||
public class PoiWordFilter
|
|
||||||
extends MediaFilter {
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(PoiWordFilter.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
String text;
|
|
||||||
try {
|
|
||||||
// get input stream from bitstream, pass to filter, get string back
|
|
||||||
POITextExtractor extractor = ExtractorFactory.createExtractor(source);
|
|
||||||
text = extractor.getText();
|
|
||||||
} catch (IOException | OpenXML4JException | XmlException e) {
|
|
||||||
System.err.format("Invalid File Format: %s%n", e.getMessage());
|
|
||||||
LOG.error("Unable to parse the bitstream: ", e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if verbose flag is set, print out extracted text to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the extracted text as a stream.
|
|
||||||
return new ByteArrayInputStream(text.getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.apache.poi.POITextExtractor;
|
|
||||||
import org.apache.poi.extractor.ExtractorFactory;
|
|
||||||
import org.apache.poi.hslf.extractor.PowerPointExtractor;
|
|
||||||
import org.apache.poi.xslf.extractor.XSLFPowerPointExtractor;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: Allow user to configure extraction of only text or only notes
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class PowerPointFilter extends MediaFilter {
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(PowerPointFilter.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstream format
|
|
||||||
*
|
|
||||||
* TODO: Check that this is correct
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
String extractedText = null;
|
|
||||||
new ExtractorFactory();
|
|
||||||
POITextExtractor pptExtractor = ExtractorFactory
|
|
||||||
.createExtractor(source);
|
|
||||||
|
|
||||||
// PowerPoint XML files and legacy format PowerPoint files
|
|
||||||
// require different classes and APIs for text extraction
|
|
||||||
|
|
||||||
// If this is a PowerPoint XML file, extract accordingly
|
|
||||||
if (pptExtractor instanceof XSLFPowerPointExtractor) {
|
|
||||||
|
|
||||||
// The true method arguments indicate that text from
|
|
||||||
// the slides and the notes is desired
|
|
||||||
extractedText = ((XSLFPowerPointExtractor) pptExtractor)
|
|
||||||
.getText(true, true);
|
|
||||||
} else if (pptExtractor instanceof PowerPointExtractor) { // Legacy PowerPoint files
|
|
||||||
|
|
||||||
extractedText = ((PowerPointExtractor) pptExtractor).getText()
|
|
||||||
+ " " + ((PowerPointExtractor) pptExtractor).getNotes();
|
|
||||||
|
|
||||||
}
|
|
||||||
if (extractedText != null) {
|
|
||||||
// if verbose flag is set, print out extracted text
|
|
||||||
// to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(extractedText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate an input stream with the extracted text
|
|
||||||
byte[] textBytes = extractedText.getBytes();
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(textBytes);
|
|
||||||
|
|
||||||
return bais;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error filtering bitstream: " + e.getMessage(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface to allow filters to register the input formats they handle
|
|
||||||
* (useful for exposing underlying capabilities of libraries used)
|
|
||||||
*/
|
|
||||||
public interface SelfRegisterInputFormats {
|
|
||||||
public String[] getInputMIMETypes();
|
|
||||||
|
|
||||||
public String[] getInputDescriptions();
|
|
||||||
|
|
||||||
public String[] getInputExtensions();
|
|
||||||
}
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.textmining.extraction.TextExtractor;
|
|
||||||
import org.textmining.extraction.word.WordTextExtractorFactory;
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* to do: helpful error messages - can't find mediafilter.cfg - can't
|
|
||||||
* instantiate filter - bitstream format doesn't exist.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class WordFilter extends MediaFilter {
|
|
||||||
|
|
||||||
private static Logger log = Logger.getLogger(WordFilter.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getFilteredName(String oldFilename) {
|
|
||||||
return oldFilename + ".txt";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bundle name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getBundleName() {
|
|
||||||
return "TEXT";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String bitstreamformat
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getFormatString() {
|
|
||||||
return "Text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return String description
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Extracted text";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param currentItem item
|
|
||||||
* @param source source input stream
|
|
||||||
* @param verbose verbose mode
|
|
||||||
* @return InputStream the resulting input stream
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public InputStream getDestinationStream(Item currentItem, InputStream source, boolean verbose)
|
|
||||||
throws Exception {
|
|
||||||
// get input stream from bitstream
|
|
||||||
// pass to filter, get string back
|
|
||||||
try {
|
|
||||||
WordTextExtractorFactory factory = new WordTextExtractorFactory();
|
|
||||||
TextExtractor e = factory.textExtractor(source);
|
|
||||||
String extractedText = e.getText();
|
|
||||||
|
|
||||||
// if verbose flag is set, print out extracted text
|
|
||||||
// to STDOUT
|
|
||||||
if (verbose) {
|
|
||||||
System.out.println(extractedText);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate an input stream with the extracted text
|
|
||||||
byte[] textBytes = extractedText.getBytes();
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(textBytes);
|
|
||||||
|
|
||||||
return bais; // will this work? or will the byte array be out of scope?
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
System.out.println("Invalid Word Format");
|
|
||||||
log.error("Error detected - Word File format not recognized: "
|
|
||||||
+ ioe.getMessage(), ioe);
|
|
||||||
throw ioe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.mediafilter.service.MediaFilterService;
|
|
||||||
import org.dspace.services.factory.DSpaceServicesFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract factory to get services for the mediafilter package, use MediaFilterServiceFactory.getInstance() to
|
|
||||||
* retrieve an implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public abstract class MediaFilterServiceFactory {
|
|
||||||
|
|
||||||
public abstract MediaFilterService getMediaFilterService();
|
|
||||||
|
|
||||||
public static MediaFilterServiceFactory getInstance() {
|
|
||||||
return DSpaceServicesFactory.getInstance().getServiceManager()
|
|
||||||
.getServiceByName("mediaFilterServiceFactory", MediaFilterServiceFactory.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter.factory;
|
|
||||||
|
|
||||||
import org.dspace.app.mediafilter.service.MediaFilterService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory implementation to get services for the mediafilter package, use MediaFilterServiceFactory.getInstance() to
|
|
||||||
* retrieve an implementation
|
|
||||||
*
|
|
||||||
* @author kevinvandevelde at atmire.com
|
|
||||||
*/
|
|
||||||
public class MediaFilterServiceFactoryImpl extends MediaFilterServiceFactory {
|
|
||||||
|
|
||||||
@Autowired(required = true)
|
|
||||||
private MediaFilterService mediaFilterService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MediaFilterService getMediaFilterService() {
|
|
||||||
return mediaFilterService;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.mediafilter.service;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.dspace.app.mediafilter.FormatFilter;
|
|
||||||
import org.dspace.content.Bitstream;
|
|
||||||
import org.dspace.content.Collection;
|
|
||||||
import org.dspace.content.Community;
|
|
||||||
import org.dspace.content.Item;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MediaFilterManager is the class that invokes the media/format filters over the
|
|
||||||
* repository's content. A few command line flags affect the operation of the
|
|
||||||
* MFM: -v verbose outputs all extracted text to STDOUT; -f force forces all
|
|
||||||
* bitstreams to be processed, even if they have been before; -n noindex does not
|
|
||||||
* recreate index after processing bitstreams; -i [identifier] limits processing
|
|
||||||
* scope to a community, collection or item; and -m [max] limits processing to a
|
|
||||||
* maximum number of items.
|
|
||||||
*/
|
|
||||||
public interface MediaFilterService {
|
|
||||||
|
|
||||||
//separator in filterFormats Map between a filter class name and a plugin name,
|
|
||||||
//for MediaFilters which extend SelfNamedPlugin (\034 is "file separator" char)
|
|
||||||
public static final String FILTER_PLUGIN_SEPARATOR = "\034";
|
|
||||||
|
|
||||||
|
|
||||||
public void applyFiltersAllItems(Context context) throws Exception;
|
|
||||||
|
|
||||||
public void applyFiltersCommunity(Context context, Community community)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
public void applyFiltersCollection(Context context, Collection collection)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
public void applyFiltersItem(Context c, Item item) throws Exception;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate through the item's bitstreams in the ORIGINAL bundle, applying
|
|
||||||
* filters if possible.
|
|
||||||
*
|
|
||||||
* @param context context
|
|
||||||
* @param myItem item
|
|
||||||
* @return true if any bitstreams processed,
|
|
||||||
* false if none
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public boolean filterItem(Context context, Item myItem) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to filter a bitstream.
|
|
||||||
*
|
|
||||||
* An exception will be thrown if the media filter class cannot be
|
|
||||||
* instantiated. Exceptions from filtering will be logged to STDOUT and
|
|
||||||
* swallowed.
|
|
||||||
*
|
|
||||||
* @param c context
|
|
||||||
* @param myItem item
|
|
||||||
* @param myBitstream bitstream
|
|
||||||
* @return true if bitstream processed,
|
|
||||||
* false if no applicable filter or already processed
|
|
||||||
* @throws Exception if error
|
|
||||||
*/
|
|
||||||
public boolean filterBitstream(Context c, Item myItem, Bitstream myBitstream) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A utility class that calls the virtual methods
|
|
||||||
* from the current MediaFilter class.
|
|
||||||
* It scans the bitstreams in an item, and decides if a bitstream has
|
|
||||||
* already been filtered, and if not or if overWrite is set, invokes the
|
|
||||||
* filter.
|
|
||||||
*
|
|
||||||
* @param context context
|
|
||||||
* @param item item containing bitstream to process
|
|
||||||
* @param source source bitstream to process
|
|
||||||
* @param formatFilter FormatFilter to perform filtering
|
|
||||||
* @return true if new rendition is created, false if rendition already
|
|
||||||
* exists and overWrite is not set
|
|
||||||
* @throws Exception if error occurs
|
|
||||||
*/
|
|
||||||
public boolean processBitstream(Context context, Item item, Bitstream source, FormatFilter formatFilter)
|
|
||||||
throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the item that is currently being processed/filtered
|
|
||||||
* by the MediaFilterManager.
|
|
||||||
* <p>
|
|
||||||
* This allows FormatFilters to retrieve the Item object
|
|
||||||
* in case they need access to item-level information for their format
|
|
||||||
* transformations/conversions.
|
|
||||||
*
|
|
||||||
* @return current Item being processed by MediaFilterManager
|
|
||||||
*/
|
|
||||||
public Item getCurrentItem();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether or not to skip processing the given identifier.
|
|
||||||
*
|
|
||||||
* @param identifier identifier (handle) of a community, collection or item
|
|
||||||
* @return true if this community, collection or item should be skipped
|
|
||||||
* during processing. Otherwise, return false.
|
|
||||||
*/
|
|
||||||
public boolean inSkipList(String identifier);
|
|
||||||
|
|
||||||
public void setVerbose(boolean isVerbose);
|
|
||||||
|
|
||||||
public void setQuiet(boolean isQuiet);
|
|
||||||
|
|
||||||
public void setForce(boolean isForce);
|
|
||||||
|
|
||||||
public void setMax2Process(int max2Process);
|
|
||||||
|
|
||||||
public void setFilterClasses(List<FormatFilter> filterClasses);
|
|
||||||
|
|
||||||
public void setSkipList(List<String> skipList);
|
|
||||||
|
|
||||||
public void setFilterFormats(Map<String, List<String>> filterFormats);
|
|
||||||
}
|
|
||||||
@@ -1,731 +0,0 @@
|
|||||||
/**
|
|
||||||
* The contents of this file are subject to the license and copyright
|
|
||||||
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
||||||
* tree and available online at
|
|
||||||
*
|
|
||||||
* http://www.dspace.org/license/
|
|
||||||
*/
|
|
||||||
package org.dspace.app.packager;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
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.PosixParser;
|
|
||||||
import org.dspace.authorize.AuthorizeException;
|
|
||||||
import org.dspace.content.DSpaceObject;
|
|
||||||
import org.dspace.content.crosswalk.CrosswalkException;
|
|
||||||
import org.dspace.content.packager.PackageDisseminator;
|
|
||||||
import org.dspace.content.packager.PackageException;
|
|
||||||
import org.dspace.content.packager.PackageIngester;
|
|
||||||
import org.dspace.content.packager.PackageParameters;
|
|
||||||
import org.dspace.core.Constants;
|
|
||||||
import org.dspace.core.Context;
|
|
||||||
import org.dspace.core.factory.CoreServiceFactory;
|
|
||||||
import org.dspace.core.service.PluginService;
|
|
||||||
import org.dspace.eperson.EPerson;
|
|
||||||
import org.dspace.eperson.factory.EPersonServiceFactory;
|
|
||||||
import org.dspace.handle.factory.HandleServiceFactory;
|
|
||||||
import org.dspace.workflow.WorkflowException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command-line interface to the Packager plugin.
|
|
||||||
* <p>
|
|
||||||
* This class ONLY exists to provide a CLI for the packager plugins. It does not
|
|
||||||
* "manage" the plugins and it is not called from within DSpace, but the name
|
|
||||||
* follows a DSpace convention.
|
|
||||||
* <p>
|
|
||||||
* It can invoke one of the Submission (SIP) packagers to create a new DSpace
|
|
||||||
* Item out of a package, or a Dissemination (DIP) packager to write an Item out
|
|
||||||
* as a package.
|
|
||||||
* <p>
|
|
||||||
* Usage is as follows:<br>
|
|
||||||
* (Add the -h option to get the command to show its own help)
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* 1. To submit a SIP (submissions tend to create a *new* object, with a new handle. If you want to restore an
|
|
||||||
* object, see -r option below)
|
|
||||||
* dspace packager
|
|
||||||
* -e {ePerson}
|
|
||||||
* -t {PackagerType}
|
|
||||||
* -p {parent-handle} [ -p {parent2} ...]
|
|
||||||
* [-o {name}={value} [ -o {name}={value} ..]]
|
|
||||||
* [-a] --- also recursively ingest all child packages of the initial package
|
|
||||||
* (child pkgs must be referenced from parent pkg)
|
|
||||||
* [-w] --- skip Workflow
|
|
||||||
* {package-filename}
|
|
||||||
*
|
|
||||||
* {PackagerType} must match one of the aliases of the chosen Packager
|
|
||||||
* plugin.
|
|
||||||
*
|
|
||||||
* The "-w" option circumvents Workflow, and is optional. The "-o"
|
|
||||||
* option, which may be repeated, passes options to the packager
|
|
||||||
* (e.g. "metadataOnly" to a DIP packager).
|
|
||||||
*
|
|
||||||
* 2. To restore an AIP (similar to submit mode, but attempts to restore with the handles/parents specified in AIP):
|
|
||||||
* dspace packager
|
|
||||||
* -r --- restores a object from a package info, including the specified handle (will throw an error if
|
|
||||||
* handle is already in use)
|
|
||||||
* -e {ePerson}
|
|
||||||
* -t {PackagerType}
|
|
||||||
* [-o {name}={value} [ -o {name}={value} ..]]
|
|
||||||
* [-a] --- also recursively restore all child packages of the initial package
|
|
||||||
* (child pkgs must be referenced from parent pkg)
|
|
||||||
* [-k] --- Skip over errors where objects already exist and Keep Existing objects by default.
|
|
||||||
* Use with -r to only restore objects which do not already exist. By default, -r will throw an error
|
|
||||||
* and rollback all changes when an object is found that already exists.
|
|
||||||
* [-f] --- Force a restore (even if object already exists).
|
|
||||||
* Use with -r to replace an existing object with one from a package (essentially a delete and
|
|
||||||
* restore).
|
|
||||||
* By default, -r will throw an error and rollback all changes when an object is found that already
|
|
||||||
* exists.
|
|
||||||
* [-i {identifier-handle-of-object}] -- Optional when -f is specified. When replacing an object, you can
|
|
||||||
* specify the
|
|
||||||
* object to replace if it cannot be easily determined from the package itself.
|
|
||||||
* {package-filename}
|
|
||||||
*
|
|
||||||
* Restoring is very similar to submitting, except that you are recreating pre-existing objects. So, in a restore,
|
|
||||||
* the object(s) are
|
|
||||||
* being recreated based on the details in the AIP. This means that the object is recreated with the same handle
|
|
||||||
* and same parent/children
|
|
||||||
* objects. Not all {PackagerTypes} may support a "restore".
|
|
||||||
*
|
|
||||||
* 3. To write out a DIP:
|
|
||||||
* dspace packager
|
|
||||||
* -d
|
|
||||||
* -e {ePerson}
|
|
||||||
* -t {PackagerType}
|
|
||||||
* -i {identifier-handle-of-object}
|
|
||||||
* [-a] --- also recursively disseminate all child objects of this object
|
|
||||||
* [-o {name}={value} [ -o {name}={value} ..]]
|
|
||||||
* {package-filename}
|
|
||||||
*
|
|
||||||
* The "-d" switch chooses a Dissemination packager, and is required.
|
|
||||||
* The "-o" option, which may be repeated, passes options to the packager
|
|
||||||
* (e.g. "metadataOnly" to a DIP packager).
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* Note that {package-filename} may be "-" for standard input or standard
|
|
||||||
* output, respectively.
|
|
||||||
*
|
|
||||||
* @author Larry Stone
|
|
||||||
* @author Tim Donohue
|
|
||||||
* @version $Revision$
|
|
||||||
*/
|
|
||||||
public class Packager {
|
|
||||||
/* Various private global settings/options */
|
|
||||||
protected String packageType = null;
|
|
||||||
protected boolean submit = true;
|
|
||||||
protected boolean userInteractionEnabled = true;
|
|
||||||
|
|
||||||
// die from illegal command line
|
|
||||||
protected static void usageError(String msg) {
|
|
||||||
System.out.println(msg);
|
|
||||||
System.out.println(" (run with -h flag for details)");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] argv) throws Exception {
|
|
||||||
Options options = new Options();
|
|
||||||
options.addOption("p", "parent", true,
|
|
||||||
"Handle(s) of parent Community or Collection into which to ingest object (repeatable)");
|
|
||||||
options.addOption("e", "eperson", true,
|
|
||||||
"email address of eperson doing importing");
|
|
||||||
options
|
|
||||||
.addOption(
|
|
||||||
"w",
|
|
||||||
"install",
|
|
||||||
false,
|
|
||||||
"disable workflow; install immediately without going through collection's workflow");
|
|
||||||
options.addOption("r", "restore", false,
|
|
||||||
"ingest in \"restore\" mode. Restores a missing object based on the contents in a package.");
|
|
||||||
options.addOption("k", "keep-existing", false,
|
|
||||||
"if an object is found to already exist during a restore (-r), then keep the existing " +
|
|
||||||
"object and continue processing. Can only be used with '-r'. This avoids " +
|
|
||||||
"object-exists errors which are thrown by -r by default.");
|
|
||||||
options.addOption("f", "force-replace", false,
|
|
||||||
"if an object is found to already exist during a restore (-r), then remove it and replace " +
|
|
||||||
"it with the contents of the package. Can only be used with '-r'. This REPLACES the " +
|
|
||||||
"object(s) in the repository with the contents from the package(s).");
|
|
||||||
options.addOption("t", "type", true, "package type or MIMEtype");
|
|
||||||
options
|
|
||||||
.addOption("o", "option", true,
|
|
||||||
"Packager option to pass to plugin, \"name=value\" (repeatable)");
|
|
||||||
options.addOption("d", "disseminate", false,
|
|
||||||
"Disseminate package (output); default is to submit.");
|
|
||||||
options.addOption("s", "submit", false,
|
|
||||||
"Submission package (Input); this is the default. ");
|
|
||||||
options.addOption("i", "identifier", true, "Handle of object to disseminate.");
|
|
||||||
options.addOption("a", "all", false,
|
|
||||||
"also recursively ingest/disseminate any child packages, e.g. all Items within a Collection" +
|
|
||||||
" (not all packagers may support this option!)");
|
|
||||||
options.addOption("h", "help", false,
|
|
||||||
"help (you may also specify '-h -t [type]' for additional help with a specific type of " +
|
|
||||||
"packager)");
|
|
||||||
options.addOption("u", "no-user-interaction", false,
|
|
||||||
"Skips over all user interaction (i.e. [y/n] question prompts) within this script. This " +
|
|
||||||
"flag can be used if you want to save (pipe) a report of all changes to a file, and " +
|
|
||||||
"therefore need to bypass all user interaction.");
|
|
||||||
|
|
||||||
CommandLineParser parser = new PosixParser();
|
|
||||||
CommandLine line = parser.parse(options, argv);
|
|
||||||
|
|
||||||
String sourceFile = null;
|
|
||||||
String eperson = null;
|
|
||||||
String[] parents = null;
|
|
||||||
String identifier = null;
|
|
||||||
PackageParameters pkgParams = new PackageParameters();
|
|
||||||
PluginService pluginService = CoreServiceFactory.getInstance().getPluginService();
|
|
||||||
|
|
||||||
//initialize a new packager -- we'll add all our current params as settings
|
|
||||||
Packager myPackager = new Packager();
|
|
||||||
|
|
||||||
if (line.hasOption('h')) {
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("Packager [options] package-file|-\n",
|
|
||||||
options);
|
|
||||||
//If user specified a type, also print out the SIP and DIP options
|
|
||||||
// that are specific to that type of packager
|
|
||||||
if (line.hasOption('t')) {
|
|
||||||
System.out.println("\n--------------------------------------------------------------");
|
|
||||||
System.out.println("Additional options for the " + line.getOptionValue('t') + " packager:");
|
|
||||||
System.out.println("--------------------------------------------------------------");
|
|
||||||
System.out.println("(These options may be specified using --option as described above)");
|
|
||||||
|
|
||||||
PackageIngester sip = (PackageIngester) pluginService
|
|
||||||
.getNamedPlugin(PackageIngester.class, line.getOptionValue('t'));
|
|
||||||
|
|
||||||
if (sip != null) {
|
|
||||||
System.out.println("\n\n" + line.getOptionValue('t') + " Submission (SIP) plugin options:\n");
|
|
||||||
System.out.println(sip.getParameterHelp());
|
|
||||||
} else {
|
|
||||||
System.out.println("\nNo valid Submission plugin found for " + line.getOptionValue('t') + " type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageDisseminator dip = (PackageDisseminator) pluginService
|
|
||||||
.getNamedPlugin(PackageDisseminator.class, line.getOptionValue('t'));
|
|
||||||
|
|
||||||
if (dip != null) {
|
|
||||||
System.out.println("\n\n" + line.getOptionValue('t') + " Dissemination (DIP) plugin options:\n");
|
|
||||||
System.out.println(dip.getParameterHelp());
|
|
||||||
} else {
|
|
||||||
System.out
|
|
||||||
.println("\nNo valid Dissemination plugin found for " + line.getOptionValue('t') + " type.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//otherwise, display list of valid packager types
|
|
||||||
System.out.println("\nAvailable Submission Package (SIP) types:");
|
|
||||||
String pn[] = pluginService
|
|
||||||
.getAllPluginNames(PackageIngester.class);
|
|
||||||
for (int i = 0; i < pn.length; ++i) {
|
|
||||||
System.out.println(" " + pn[i]);
|
|
||||||
}
|
|
||||||
System.out
|
|
||||||
.println("\nAvailable Dissemination Package (DIP) types:");
|
|
||||||
pn = pluginService.getAllPluginNames(PackageDisseminator.class);
|
|
||||||
for (int i = 0; i < pn.length; ++i) {
|
|
||||||
System.out.println(" " + pn[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//look for flag to disable all user interaction
|
|
||||||
if (line.hasOption('u')) {
|
|
||||||
myPackager.userInteractionEnabled = false;
|
|
||||||
}
|
|
||||||
if (line.hasOption('w')) {
|
|
||||||
pkgParams.setWorkflowEnabled(false);
|
|
||||||
}
|
|
||||||
if (line.hasOption('r')) {
|
|
||||||
pkgParams.setRestoreModeEnabled(true);
|
|
||||||
}
|
|
||||||
//keep-existing is only valid in restoreMode (-r) -- otherwise ignore -k option.
|
|
||||||
if (line.hasOption('k') && pkgParams.restoreModeEnabled()) {
|
|
||||||
pkgParams.setKeepExistingModeEnabled(true);
|
|
||||||
}
|
|
||||||
//force-replace is only valid in restoreMode (-r) -- otherwise ignore -f option.
|
|
||||||
if (line.hasOption('f') && pkgParams.restoreModeEnabled()) {
|
|
||||||
pkgParams.setReplaceModeEnabled(true);
|
|
||||||
}
|
|
||||||
if (line.hasOption('e')) {
|
|
||||||
eperson = line.getOptionValue('e');
|
|
||||||
}
|
|
||||||
if (line.hasOption('p')) {
|
|
||||||
parents = line.getOptionValues('p');
|
|
||||||
}
|
|
||||||
if (line.hasOption('t')) {
|
|
||||||
myPackager.packageType = line.getOptionValue('t');
|
|
||||||
}
|
|
||||||
if (line.hasOption('i')) {
|
|
||||||
identifier = line.getOptionValue('i');
|
|
||||||
}
|
|
||||||
if (line.hasOption('a')) {
|
|
||||||
//enable 'recursiveMode' param to packager implementations, in case it helps with packaging or ingestion
|
|
||||||
// process
|
|
||||||
pkgParams.setRecursiveModeEnabled(true);
|
|
||||||
}
|
|
||||||
String files[] = line.getArgs();
|
|
||||||
if (files.length > 0) {
|
|
||||||
sourceFile = files[0];
|
|
||||||
}
|
|
||||||
if (line.hasOption('d')) {
|
|
||||||
myPackager.submit = false;
|
|
||||||
}
|
|
||||||
if (line.hasOption('o')) {
|
|
||||||
String popt[] = line.getOptionValues('o');
|
|
||||||
for (int i = 0; i < popt.length; ++i) {
|
|
||||||
String pair[] = popt[i].split("\\=", 2);
|
|
||||||
if (pair.length == 2) {
|
|
||||||
pkgParams.addProperty(pair[0].trim(), pair[1].trim());
|
|
||||||
} else if (pair.length == 1) {
|
|
||||||
pkgParams.addProperty(pair[0].trim(), "");
|
|
||||||
} else {
|
|
||||||
System.err
|
|
||||||
.println("Warning: Illegal package option format: \""
|
|
||||||
+ popt[i] + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity checks on arg list: required args
|
|
||||||
// REQUIRED: sourceFile, ePerson (-e), packageType (-t)
|
|
||||||
if (sourceFile == null || eperson == null || myPackager.packageType == null) {
|
|
||||||
System.err.println("Error - missing a REQUIRED argument or option.\n");
|
|
||||||
HelpFormatter myhelp = new HelpFormatter();
|
|
||||||
myhelp.printHelp("PackageManager [options] package-file|-\n", options);
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the EPerson, assign to context
|
|
||||||
Context context = new Context();
|
|
||||||
EPerson myEPerson = null;
|
|
||||||
myEPerson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, eperson);
|
|
||||||
if (myEPerson == null) {
|
|
||||||
usageError("Error, eperson cannot be found: " + eperson);
|
|
||||||
}
|
|
||||||
context.setCurrentUser(myEPerson);
|
|
||||||
|
|
||||||
|
|
||||||
//If we are in REPLACE mode
|
|
||||||
if (pkgParams.replaceModeEnabled()) {
|
|
||||||
context.setMode(Context.Mode.BATCH_EDIT);
|
|
||||||
PackageIngester sip = (PackageIngester) pluginService
|
|
||||||
.getNamedPlugin(PackageIngester.class, myPackager.packageType);
|
|
||||||
if (sip == null) {
|
|
||||||
usageError("Error, Unknown package type: " + myPackager.packageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
DSpaceObject objToReplace = null;
|
|
||||||
|
|
||||||
//if a specific identifier was specified, make sure it is valid
|
|
||||||
if (identifier != null && identifier.length() > 0) {
|
|
||||||
objToReplace = HandleServiceFactory.getInstance().getHandleService()
|
|
||||||
.resolveToObject(context, identifier);
|
|
||||||
if (objToReplace == null) {
|
|
||||||
throw new IllegalArgumentException("Bad identifier/handle -- "
|
|
||||||
+ "Cannot resolve handle \"" + identifier + "\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String choiceString = null;
|
|
||||||
if (myPackager.userInteractionEnabled) {
|
|
||||||
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
System.out.println("\n\nWARNING -- You are running the packager in REPLACE mode.");
|
|
||||||
System.out.println(
|
|
||||||
"\nREPLACE mode may be potentially dangerous as it will automatically remove and replace contents" +
|
|
||||||
" within DSpace.");
|
|
||||||
System.out.println(
|
|
||||||
"We highly recommend backing up all your DSpace contents (files & database) before continuing.");
|
|
||||||
System.out.print("\nWould you like to continue? [y/n]: ");
|
|
||||||
choiceString = input.readLine();
|
|
||||||
} else {
|
|
||||||
//user interaction disabled -- default answer to 'yes', otherwise script won't continue
|
|
||||||
choiceString = "y";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (choiceString.equalsIgnoreCase("y")) {
|
|
||||||
System.out.println("Beginning replacement process...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
//replace the object from the source file
|
|
||||||
myPackager.replace(context, sip, pkgParams, sourceFile, objToReplace);
|
|
||||||
|
|
||||||
//commit all changes & exit successfully
|
|
||||||
context.complete();
|
|
||||||
System.exit(0);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// abort all operations
|
|
||||||
e.printStackTrace();
|
|
||||||
context.abort();
|
|
||||||
System.out.println(e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (myPackager.submit || pkgParams.restoreModeEnabled()) {
|
|
||||||
//else if normal SUBMIT mode (or basic RESTORE mode -- which is a special type of submission)
|
|
||||||
context.setMode(Context.Mode.BATCH_EDIT);
|
|
||||||
|
|
||||||
PackageIngester sip = (PackageIngester) pluginService
|
|
||||||
.getNamedPlugin(PackageIngester.class, myPackager.packageType);
|
|
||||||
if (sip == null) {
|
|
||||||
usageError("Error, Unknown package type: " + myPackager.packageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate each parent arg (if any)
|
|
||||||
DSpaceObject parentObjs[] = null;
|
|
||||||
if (parents != null) {
|
|
||||||
System.out.println("Destination parents:");
|
|
||||||
|
|
||||||
parentObjs = new DSpaceObject[parents.length];
|
|
||||||
for (int i = 0; i < parents.length; i++) {
|
|
||||||
// sanity check: did handle resolve?
|
|
||||||
parentObjs[i] = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context,
|
|
||||||
parents[i]);
|
|
||||||
if (parentObjs[i] == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Bad parent list -- "
|
|
||||||
+ "Cannot resolve parent handle \""
|
|
||||||
+ parents[i] + "\"");
|
|
||||||
}
|
|
||||||
System.out.println((i == 0 ? "Owner: " : "Parent: ")
|
|
||||||
+ parentObjs[i].getHandle());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
//ingest the object from the source file
|
|
||||||
myPackager.ingest(context, sip, pkgParams, sourceFile, parentObjs);
|
|
||||||
|
|
||||||
//commit all changes & exit successfully
|
|
||||||
context.complete();
|
|
||||||
System.exit(0);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// abort all operations
|
|
||||||
e.printStackTrace();
|
|
||||||
context.abort();
|
|
||||||
System.out.println(e);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// else, if DISSEMINATE mode
|
|
||||||
context.setMode(Context.Mode.READ_ONLY);
|
|
||||||
|
|
||||||
//retrieve specified package disseminator
|
|
||||||
PackageDisseminator dip = (PackageDisseminator) pluginService
|
|
||||||
.getNamedPlugin(PackageDisseminator.class, myPackager.packageType);
|
|
||||||
if (dip == null) {
|
|
||||||
usageError("Error, Unknown package type: " + myPackager.packageType);
|
|
||||||
}
|
|
||||||
|
|
||||||
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService()
|
|
||||||
.resolveToObject(context, identifier);
|
|
||||||
if (dso == null) {
|
|
||||||
throw new IllegalArgumentException("Bad identifier/handle -- "
|
|
||||||
+ "Cannot resolve handle \"" + identifier + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
//disseminate the requested object
|
|
||||||
myPackager.disseminate(context, dip, dso, pkgParams, sourceFile);
|
|
||||||
}
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ingest one or more DSpace objects from package(s) based on the
|
|
||||||
* options passed to the 'packager' script. This method is called
|
|
||||||
* for both 'submit' (-s) and 'restore' (-r) modes.
|
|
||||||
* <p>
|
|
||||||
* Please note that replace (-r -f) mode calls the replace() method instead.
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param sip PackageIngester which will actually ingest the package
|
|
||||||
* @param pkgParams Parameters to pass to individual packager instances
|
|
||||||
* @param sourceFile location of the source package to ingest
|
|
||||||
* @param parentObjs Parent DSpace object(s) to attach new object to
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws CrosswalkException if crosswalk error
|
|
||||||
* @throws PackageException if packaging error
|
|
||||||
*/
|
|
||||||
protected void ingest(Context context, PackageIngester sip, PackageParameters pkgParams, String sourceFile,
|
|
||||||
DSpaceObject parentObjs[])
|
|
||||||
throws IOException, SQLException, FileNotFoundException, AuthorizeException, CrosswalkException,
|
|
||||||
PackageException {
|
|
||||||
// make sure we have an input file
|
|
||||||
File pkgFile = new File(sourceFile);
|
|
||||||
|
|
||||||
if (!pkgFile.exists()) {
|
|
||||||
System.out.println("\nERROR: Package located at " + sourceFile + " does not exist!");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("\nIngesting package located at " + sourceFile);
|
|
||||||
|
|
||||||
//find first parent (if specified) -- this will be the "owner" of the object
|
|
||||||
DSpaceObject parent = null;
|
|
||||||
if (parentObjs != null && parentObjs.length > 0) {
|
|
||||||
parent = parentObjs[0];
|
|
||||||
}
|
|
||||||
//NOTE: at this point, Parent may be null -- in which case it is up to the PackageIngester
|
|
||||||
// to either determine the Parent (from package contents) or throw an error.
|
|
||||||
|
|
||||||
try {
|
|
||||||
//If we are doing a recursive ingest, call ingestAll()
|
|
||||||
if (pkgParams.recursiveModeEnabled()) {
|
|
||||||
System.out.println("\nAlso ingesting all referenced packages (recursive mode)..");
|
|
||||||
System.out.println(
|
|
||||||
"This may take a while, please check your logs for ongoing status while we process each package.");
|
|
||||||
|
|
||||||
//ingest first package & recursively ingest anything else that package references (child packages, etc)
|
|
||||||
List<String> hdlResults = sip.ingestAll(context, parent, pkgFile, pkgParams, null);
|
|
||||||
|
|
||||||
if (hdlResults != null) {
|
|
||||||
//Report total objects created
|
|
||||||
System.out.println("\nCREATED a total of " + hdlResults.size() + " DSpace Objects.");
|
|
||||||
|
|
||||||
String choiceString = null;
|
|
||||||
//Ask if user wants full list printed to command line, as this may be rather long.
|
|
||||||
if (this.userInteractionEnabled) {
|
|
||||||
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
System.out.print("\nWould you like to view a list of all objects that were created? [y/n]: ");
|
|
||||||
choiceString = input.readLine();
|
|
||||||
} else {
|
|
||||||
// user interaction disabled -- default answer to 'yes', as
|
|
||||||
// we want to provide user with as detailed a report as possible.
|
|
||||||
choiceString = "y";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide detailed report if user answered 'yes'
|
|
||||||
if (choiceString.equalsIgnoreCase("y")) {
|
|
||||||
System.out.println("\n\n");
|
|
||||||
for (String result : hdlResults) {
|
|
||||||
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService()
|
|
||||||
.resolveToObject(context, result);
|
|
||||||
|
|
||||||
if (dso != null) {
|
|
||||||
|
|
||||||
if (pkgParams.restoreModeEnabled()) {
|
|
||||||
System.out.println("RESTORED DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + ", dbID=" + dso
|
|
||||||
.getID() + " ] ");
|
|
||||||
} else {
|
|
||||||
System.out.println("CREATED new DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + ", dbID=" + dso
|
|
||||||
.getID() + " ] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//otherwise, just one package to ingest
|
|
||||||
try {
|
|
||||||
DSpaceObject dso = sip.ingest(context, parent, pkgFile, pkgParams, null);
|
|
||||||
|
|
||||||
if (dso != null) {
|
|
||||||
if (pkgParams.restoreModeEnabled()) {
|
|
||||||
System.out.println("RESTORED DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] ");
|
|
||||||
} else {
|
|
||||||
System.out.println("CREATED new DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + ", dbID=" + dso.getID() + " ] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IllegalStateException ie) {
|
|
||||||
// NOTE: if we encounter an IllegalStateException, this means the
|
|
||||||
// handle is already in use and this object already exists.
|
|
||||||
|
|
||||||
//if we are skipping over (i.e. keeping) existing objects
|
|
||||||
if (pkgParams.keepExistingModeEnabled()) {
|
|
||||||
System.out.println(
|
|
||||||
"\nSKIPPED processing package '" + pkgFile + "', as an Object already exists with this " +
|
|
||||||
"handle.");
|
|
||||||
} else {
|
|
||||||
// Pass this exception on -- which essentially causes a full rollback of all changes (this
|
|
||||||
// is the default)
|
|
||||||
throw ie;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (WorkflowException e) {
|
|
||||||
throw new PackageException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disseminate one or more DSpace objects into package(s) based on the
|
|
||||||
* options passed to the 'packager' script
|
|
||||||
*
|
|
||||||
* @param context DSpace context
|
|
||||||
* @param dip PackageDisseminator which will actually create the package
|
|
||||||
* @param dso DSpace Object to disseminate as a package
|
|
||||||
* @param pkgParams Parameters to pass to individual packager instances
|
|
||||||
* @param outputFile File where final package should be saved
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws CrosswalkException if crosswalk error
|
|
||||||
* @throws PackageException if packaging error
|
|
||||||
*/
|
|
||||||
protected void disseminate(Context context, PackageDisseminator dip,
|
|
||||||
DSpaceObject dso, PackageParameters pkgParams,
|
|
||||||
String outputFile)
|
|
||||||
throws IOException, SQLException, FileNotFoundException, AuthorizeException, CrosswalkException,
|
|
||||||
PackageException {
|
|
||||||
// initialize output file
|
|
||||||
File pkgFile = new File(outputFile);
|
|
||||||
|
|
||||||
System.out.println("\nDisseminating DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + " ] to " + outputFile);
|
|
||||||
|
|
||||||
//If we are doing a recursive dissemination of this object & all its child objects, call disseminateAll()
|
|
||||||
if (pkgParams.recursiveModeEnabled()) {
|
|
||||||
System.out.println("\nAlso disseminating all child objects (recursive mode)..");
|
|
||||||
System.out.println(
|
|
||||||
"This may take a while, please check your logs for ongoing status while we process each package.");
|
|
||||||
|
|
||||||
//disseminate initial object & recursively disseminate all child objects as well
|
|
||||||
List<File> fileResults = dip.disseminateAll(context, dso, pkgParams, pkgFile);
|
|
||||||
|
|
||||||
if (fileResults != null) {
|
|
||||||
//Report total files created
|
|
||||||
System.out.println("\nCREATED a total of " + fileResults.size() + " dissemination package files.");
|
|
||||||
|
|
||||||
String choiceString = null;
|
|
||||||
//Ask if user wants full list printed to command line, as this may be rather long.
|
|
||||||
if (this.userInteractionEnabled) {
|
|
||||||
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
System.out.print("\nWould you like to view a list of all files that were created? [y/n]: ");
|
|
||||||
choiceString = input.readLine();
|
|
||||||
} else {
|
|
||||||
// user interaction disabled -- default answer to 'yes', as
|
|
||||||
// we want to provide user with as detailed a report as possible.
|
|
||||||
choiceString = "y";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide detailed report if user answered 'yes'
|
|
||||||
if (choiceString.equalsIgnoreCase("y")) {
|
|
||||||
System.out.println("\n\n");
|
|
||||||
for (File result : fileResults) {
|
|
||||||
System.out.println("CREATED package file: " + result.getCanonicalPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//otherwise, just disseminate a single object to a single package file
|
|
||||||
dip.disseminate(context, dso, pkgParams, pkgFile);
|
|
||||||
|
|
||||||
if (pkgFile != null && pkgFile.exists()) {
|
|
||||||
System.out.println("\nCREATED package file: " + pkgFile.getCanonicalPath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace an one or more existing DSpace objects with the contents of
|
|
||||||
* specified package(s) based on the options passed to the 'packager' script.
|
|
||||||
* This method is only called for full replaces ('-r -f' options specified)
|
|
||||||
*
|
|
||||||
* @param context DSpace Context
|
|
||||||
* @param sip PackageIngester which will actually replace the object with the package
|
|
||||||
* @param pkgParams Parameters to pass to individual packager instances
|
|
||||||
* @param sourceFile location of the source package to ingest as the replacement
|
|
||||||
* @param objToReplace DSpace object to replace (may be null if it will be specified in the package itself)
|
|
||||||
* @throws IOException if IO error
|
|
||||||
* @throws SQLException if database error
|
|
||||||
* @throws FileNotFoundException if file doesn't exist
|
|
||||||
* @throws AuthorizeException if authorization error
|
|
||||||
* @throws CrosswalkException if crosswalk error
|
|
||||||
* @throws PackageException if packaging error
|
|
||||||
*/
|
|
||||||
protected void replace(Context context, PackageIngester sip, PackageParameters pkgParams, String sourceFile,
|
|
||||||
DSpaceObject objToReplace)
|
|
||||||
throws IOException, SQLException, FileNotFoundException, AuthorizeException, CrosswalkException,
|
|
||||||
PackageException {
|
|
||||||
|
|
||||||
// make sure we have an input file
|
|
||||||
File pkgFile = new File(sourceFile);
|
|
||||||
|
|
||||||
if (!pkgFile.exists()) {
|
|
||||||
System.out.println("\nPackage located at " + sourceFile + " does not exist!");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.println("\nReplacing DSpace object(s) with package located at " + sourceFile);
|
|
||||||
if (objToReplace != null) {
|
|
||||||
System.out.println("Will replace existing DSpace " + Constants.typeText[objToReplace.getType()] +
|
|
||||||
" [ hdl=" + objToReplace.getHandle() + " ]");
|
|
||||||
}
|
|
||||||
// NOTE: At this point, objToReplace may be null. If it is null, it is up to the PackageIngester
|
|
||||||
// to determine which Object needs to be replaced (based on the handle specified in the pkg, etc.)
|
|
||||||
|
|
||||||
try {
|
|
||||||
//If we are doing a recursive replace, call replaceAll()
|
|
||||||
if (pkgParams.recursiveModeEnabled()) {
|
|
||||||
//ingest first object using package & recursively replace anything else that package references
|
|
||||||
// (child objects, etc)
|
|
||||||
List<String> hdlResults = sip.replaceAll(context, objToReplace, pkgFile, pkgParams);
|
|
||||||
|
|
||||||
if (hdlResults != null) {
|
|
||||||
//Report total objects replaced
|
|
||||||
System.out.println("\nREPLACED a total of " + hdlResults.size() + " DSpace Objects.");
|
|
||||||
|
|
||||||
String choiceString = null;
|
|
||||||
//Ask if user wants full list printed to command line, as this may be rather long.
|
|
||||||
if (this.userInteractionEnabled) {
|
|
||||||
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
|
|
||||||
System.out.print("\nWould you like to view a list of all objects that were replaced? [y/n]: ");
|
|
||||||
choiceString = input.readLine();
|
|
||||||
} else {
|
|
||||||
// user interaction disabled -- default answer to 'yes', as
|
|
||||||
// we want to provide user with as detailed a report as possible.
|
|
||||||
choiceString = "y";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide detailed report if user answered 'yes'
|
|
||||||
if (choiceString.equalsIgnoreCase("y")) {
|
|
||||||
System.out.println("\n\n");
|
|
||||||
for (String result : hdlResults) {
|
|
||||||
DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService()
|
|
||||||
.resolveToObject(context, result);
|
|
||||||
|
|
||||||
if (dso != null) {
|
|
||||||
System.out.println("REPLACED DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + " ] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//otherwise, just one object to replace
|
|
||||||
DSpaceObject dso = sip.replace(context, objToReplace, pkgFile, pkgParams);
|
|
||||||
|
|
||||||
if (dso != null) {
|
|
||||||
System.out.println("REPLACED DSpace " + Constants.typeText[dso.getType()] +
|
|
||||||
" [ hdl=" + dso.getHandle() + " ] ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (WorkflowException e) {
|
|
||||||
throw new PackageException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user